commit e545e62015fa54ae35cee3f7400aca62b8792ac5
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Wed Mar 21 11:51:48 2018 +0100

    Major overhaul to AMiRo-OS version 2.0.0

diff --git a/.gitignore b/.gitignore
index 320c10b..c3268c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,3 @@
-doc
 build
 .dep
 *.tmp
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8bb5d56
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,10 @@
+[submodule "kernel/ChibiOS"]
+	path = kernel/ChibiOS
+	url = https://github.com/ChibiOS/ChibiOS.git
+	ignore = dirty
+[submodule "bootloader/AMiRo-BLT"]
+	path = bootloader/AMiRo-BLT
+	url = http://openresearch.cit-ec.de/git/amiro-os.amiro-blt.git
+[submodule "periphery-lld/AMiRo-LLD"]
+	path = periphery-lld/AMiRo-LLD
+	url = http://openresearch.cit-ec.de/git/amiro-os.amiro-lld.git
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0b91f81
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,97 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+
+
+define HELP_TEXT
+################################################################################
+#                                                                              #
+# Copyright (c) 2016..2018  Thomas Schöpping                                   #
+#                                                                              #
+# This is free software; see the source for copying conditions. There is NO    #
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  #
+# The development of this software was supported by the Excellence Cluster     #
+# EXC 227 Cognitive Interaction Technology. The Excellence Cluster EXC 227 is  #
+# a grant of the Deutsche Forschungsgemeinschaft (DFG) in the context of the   #
+# German Excellence Initiative.                                                #
+#                                                                              #
+################################################################################
+
+  AMiRo-OS Makefile help
+  ======================
+
+ARGUMENTS:
+
+  help:
+      Prints this text.
+
+  all:
+      Builds the binaries for all modules.
+
+  flash:
+      Flashes all binaries to the hardware.
+      If the binaries do not exist, they are created beforehand.
+
+  clean:
+      Deletes all temporary and binary files of all modules.
+
+  <module>:
+      Builds the binary only for the specified module.
+      Possible values for <module> are:
+        - DiWheelDrive
+        - PowerManagement
+        - LightRing
+
+
+EXAMPLES:
+
+  >$$ make DiWheelDrive
+      This command will generate the binary file for the DiWheelDrive module.
+
+  >$$ make DiWheelDrive LightRing
+      This command will generate the binary files for the two modules
+      DiWheelDrive and LightRing.
+
+  >$$ make flash -j
+      This command will first build all missing binary files and flash all
+      modules as soon as the binaries are ready.
+      By the additional argument '-j' the build process will be parallelized.
+
+  >$$ make clean && make all && make flash
+      This command will first clean all thee projects. In a second step the
+      binaries for al three modules are build from scratch. Finally all modules
+      are updated with the latest software.
+      The following command can be used as a shorter and faster version:
+          >$$ make clean && make flash -j
+
+################################################################################
+endef
+export HELP_TEXT
+
+OS_BASE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+help:
+	@echo "$$HELP_TEXT"
+	@exit
+
+include $(OS_BASE_DIR)/os/modules/Makefile
diff --git a/README.txt b/README.txt
index 0e54436..43e4af4 100644
--- a/README.txt
+++ b/README.txt
@@ -1,9 +1,10 @@
-AMiRo-OS is the operating system for the base version of the Autonomous Mini
+AMiRo-OS is an operating system for the base version of the Autonomous Mini
 Robot (AMiRo) [1]. It utilizes ChibiOS (a real-time operating system for
 embedded devices developed by Giovanni di Sirio; see <http://chibios.org>) as
-system kernel and extends it with platform specific functionalities.
+system kernel and extends it with platform specific configurations and further
+functionalities and abstractions.
 
-Copyright (C) 2016..2017  Thomas Schöpping et al.
+Copyright (C) 2016..2018  Thomas Schöpping et al.
 (a complete list of all authors is given below)
 
 This program is free software: you can redistribute it and/or modify
@@ -24,14 +25,8 @@ Cognitive Interaction Technology 'CITEC' (EXC 277) at Bielefeld
 University, which is funded by the German Research Foundation (DFG).
 
 Authors:
- - Thomas Schöpping        <tschoepp[at]cit-ec.uni-bielefeld.de>
- - Timo Korthals           <tkorthals[at]cit-ec.uni-bielefeld.de>
- - Stefan Herbrechtsmeier  <sherbrec[at]cit-ec.uni-bielefeld.de>
- - Teerapat Chinapirom     <tchinapirom[at]cit-ec.uni-bielefeld.de>
- - Robert Abel
- - Marvin Barther
- - Claas Braun
- - Tristan Kenneweg
+ - Thomas Schöpping          <tschoepp[at]cit-ec.uni-bielefeld.de>
+ - Marc Rothmann
 
 References:
  [1] S. Herbrechtsmeier, T. Korthals, T. Schopping and U. Rückert, "AMiRo: A
@@ -59,15 +54,17 @@ the source code, and flash it to the AMiRo modules.
 ================================================================================
 
 CONTENTS:
- 1  Required software
-   1.1  Git
-   1.2  GCC ARM Embedded Toolchain
-   1.3  ChibiOS
-   1.4  AMiRo-BLT
- 2  Recommended software
-   2.1  gtkterm and hterm
-   2.2  QtCreator
- 3  Building and flashing
+
+  1  Required software
+    1.1  Git
+    1.2  Bootloader & Tools
+    1.3  System Kernel
+    1.4  Low-Level Drivers
+  2  Recommended software
+    2.1  gtkterm and hterm
+    2.2  QtCreator IDE
+    2.3  Doxygen & Graphviz
+  3  Building and flashing
 
 ================================================================================
 
@@ -76,10 +73,10 @@ CONTENTS:
 1 - REQUIRED SOFTWARE
 ---------------------
 
-In order to compile the source code, you need to install the GCC for ARM
-embedded devices. Since AMiRo-OS requires ChibiOS as system kernel, you need a
-copy of that project as well. Furthermore, AMiRo-OS requires a compatible
-bootloader, such as provided by the AMiRo-BLT project.
+In order to compile the source code, you need to install the GNU ARM Embedded
+Toolchain. Since this project uses GNU Make for configuring and calling the
+compiler, this tool is requried too. AMiRo-OS uses ChibiOS as system kernel,
+so you need a copy of that project as well.
 
 
 1.1 - Git
@@ -89,74 +86,58 @@ Since all main- and subprojects are available as Git repositories, installing a
 recent version of the tool is mandatory.
 
 
-1.2 GCC ARM Embedded Toolchain
-------------------------------
-
-Various versions of the GCC for ARM embedded devices can be found at
-<https://launchpad.net/gcc-arm-embedded>. It is highly recommended to use the
-version 4.8 with update 2014-q1 since some others will cause issues. For
-installation of the compiler toolchain, please follow the instructions that can
-be found on the web page.
+1.2 Bootloader & Tools
+----------------------
 
-If you are running a 64-bit operating system, you will have to install several
-32-bit libraries in order to make the compiler work. The required packages are
-libc6, libstdc++6, and libncurses5. You can run the following shell commands to
-install the according 32-bit versions of the packages:
-  >$ sudo dpkg --add-architecture i386 && sudo apt-get update
-  >$ sudo apt-get install libc6:i386 libstdc++6:i386 libncurses5:i386
+AMiRo-OS can take advantage of an installed bootloader if such exists and
+provides an interface. By default, AMiRo-BLT is included as a Git submodule and
+can easily be initialized via the ./setup.sh script. If requried, you can
+replace the used bootloader by adding an according subfolder in the ./bootloader
+directory. Note that you will have to adapt the makefiles and scripts, and
+probably the operating system as well.
+AMiRo-BLT furthermore has its own required and recommended software tools as
+described in its README.txt file. Follow th instructions to initialize the
+development environment manually or use the ./setup.sh script.
 
 
-1.3 ChibiOS
------------
+1.3 System Kernel
+-----------------
 
 Since AMiRo-OS uses ChibiOS as underlying system kernel, you need to acquire a
-copy of it as well. First, go to the directory which contains the AMiRo-OS
-folder (but do not go into the AMiRo-OS directory itself!). Now clone the GIT
-repository of ChibiOS and checkout version 2.6.x:
-  >$ git clone https://github.com/ChibiOS/ChibiOS.git ChibiOS
-  >$ cd ChibiOS
-  >$ git checkout 2e6dfc7364e7551483922ea6afbaea8f3501ab0e
-It is highly recommended to use exactly this commit. Although newer commits in
-the 2.6.x branch might work fine, AMiRo-OS is not compatible with ChibiOS
-version 3 or newer.
-
-AMiRo-OS comes with some patches to ChibiOS, which must be applied as well
-before compiling the project. Therefore you need to copy all files from the
-./patches directory of AMiRo-OS to the root directory of ChibiOS. You can then
-apply the patches via the following command:
-  >$ for i in `ls | grep patch`; do git am --ignore-space-change --ignore-whitespace < ${i}; done
-If the files could not be patched successfully, you are probably using an
-incompatible version of ChibiOS (try to checkout the correct commit as denoted
-above).
-
-
-1.4 AMiRo-BLT
--------------
-
-AMiRo-BLT is an additional software project, which is developed in parallel with
-AMiRo-OS. If you did not receive a copy of AMiRo-BLT with AMiRo-OS, you can find
-all code and documentation at <https://opensource.cit-ec.de/projects/amiro-os>.
-Instructions for installation and how to use the software provided by AMiRo-BLT
-can be found on the web page or in the project's readme file. It is highly
-recommended to install AMiRo-BLT in the same directory as AMiRo-OS and ChibiOS
-and name its root directory 'amiro-blt'.
+copy of it as well. For the sake of compatibility, it is included in AMiRo-OS as
+a Git submodule. It is highly recommended to use the ./setup.sh script for
+initialization. Moreover, you have to apply the patches to ChibiOS in order to
+make AMiRo-OS work properly. It is recommended to use the .setup.sh script for this
+purpose.
+If you would like to use a different kernel, you can add a subfolder in the
+./kernel/ directory and adapt the scripts and operating system source code.
+
+
+1.4 Low-Level Drivers
+---------------------
+
+Any required low-level drivers for the AMiRo hardware is available in an
+additional project: AMiRo-LLD. It is included as a Git subodule and can be
+initialized via the ./setup.sh script.
 
 
 
 2 - RECOMMENDED SOFTWARE
 ------------------------
 
-In order to fully use all features of AMiRo-OS it is recommended to install the
-'hterm' or 'gtkterm' application for accessing the robot. To ease further
-development, this project offers support for the QtCreator IDE.
+AMiRo-OS can take advanatge of an installed bootloader, which is recommended for
+the best experience. In order to use all features of AMiRo-OS it is also
+recommended to install either the 'hterm' or 'gtkterm' application for accessing
+the robot. To ease further development, this project offers support for the
+QtCreator IDE.
 
 
 2.1 - gtkterm and hterm
 -----------------------
 
-Depending on your operating system, it is recommended to install 'gtkterm' for
+Depending on your operating system it is recommended to install 'gtkterm' for
 Linux (available in the Ubuntu repositories), or 'hterm' for Windows. For
-gtkterm you need to modify the configuration file ~/.gtktermrc (it is generated
+gtkterm you need to modify the configuration file ~/.gtktermrc (generated
 automatically when you start the application for the first time) as follows:
 
   port	= /dev/ttyUSB0
@@ -172,15 +153,26 @@ automatically when you start the application for the first time) as follows:
   echo	= False
   crlfauto	= True
 
-For hterm you must need to configure the tool analogously.
+For hterm you need to configure the tool analogously. With either tool the robot
+can be reset by toggling the RTS signal on and off again, and you can access the
+system shell of AMiRo-OS.
 
 
-2.2 - QtCreator
----------------
+2.2 - QtCreator IDE
+-------------------
 
-In order to setup QtCreator projects for the three AMiRo base modules, a script
-is provided in the directory ./ide/qtcreator/. It is accompanied by an
-additional README.txt file, which contains further information.
+In order to setup QtCreator projects for the three AMiRo base modules, you can
+use the provided ./setup.sh script. Further instructions for a more advanced
+configuration of the IDE are provided in the ./tools/qtcreator/README.txt file.
+
+
+2.3  Doxygen & Graphviz
+-----------------------
+
+In order to generate the documentation from the source code, Doxygen and
+Graphviz are requried. It is recommended to install these tool using the
+default versions for your system. Ubuntu users should simply run
+  >$ sudo apt-get install doxygen graphviz
 
 
 
@@ -188,30 +180,22 @@ additional README.txt file, which contains further information.
 -------------------------
 
 Each time you modify any part of AMiRo-OS, you need to recompile the whole
-project for the according AMiRo module. Therefore you have to use the makefiles
-provided in ./devices/<DeviceToRecompile>/ by simply executing 'make' in the
-according directory. If you want to compile all modules at once, you can also
-use the makefile in the ./devices/ folder.
-
-After compilation, you always have to flash the generated program to the robot.
-Therefore you need to install the SerialBoot tool provided by the AMiRo-BLT
-project. By default AMiRo-OS assumes AMiRo-BLT to be installed in the same
-folder and its root directory to be named 'amiro-blt'. If this is the case, it
-will automatically detect the SerialBoot tool. Otherwise the tool must be
-accessible globally under the environment variable 'SERIALBOOT'. You can make
-it so by appending the following line to your ~/.bashrc file:
-
-  export SERIALBOOT=</absolute/path/to/the/SerialBoot/binary>
-
-You can test the tool by calling it via the variable:
-  >$ ${SERIALBOOT}
-This should print some information about the tool.
-
-Similar to the compilation procedure as described above, you can flash either
-each module separately, or all modules at once by executing 'make flash' from
-the according directory. Note that you must connect the programming cable either
-to the DiWheelDrive or the PowerManagement module for flashing the operating
-system. All other modules are powered off after reset so that only these two
-offer a bootloader that is required for flashing.
+project for the according AMiRo module. Therefore you can use the ./Makefile by
+simply executing 'make' and follow the instructions. Alternatively, you can
+either use the makefiles provided per module in ./os/modules/<ModuleToCompile>
+or - if you want to compile all modules at once - the makefile in the
+./os/modules folder. After the build process has finished successfully, you
+always have to flash the generated program to the robot. Therefore you need an
+appropriate tool, such as stm32flash (if you don't use a bootloader) or
+SerialBoot (highly recommended; provided by AMiRo-BLT). Similarly to the
+compilation procedure as described above, you can flash either each module
+separately, or all modules at once by executing 'make flash' from the according
+directory.
+
+When using SerialBoot, please note that you must connect the programming cable
+either to the DiWheelDrive or the PowerManagement module for flashing the
+operating system. All other modules are powered off after reset so that only
+these two offer a running bootloader, which is required for flashing.
 
 ================================================================================
+
diff --git a/boards/DiWheelDrive/board.c b/boards/DiWheelDrive/board.c
deleted file mode 100644
index 4b3ebfe..0000000
--- a/boards/DiWheelDrive/board.c
+++ /dev/null
@@ -1,153 +0,0 @@
-#include "ch.h"
-#include "hal.h"
-
-/**
- * @brief   PAL setup.
- * @details Digital I/O ports static configuration as defined in @p board.h.
- *          This variable is used by the HAL when initializing the PAL driver.
- */
-#if HAL_USE_PAL || defined(__DOXYGEN__)
-const PALConfig pal_default_config =
-{
-  {VAL_GPIOAODR, VAL_GPIOACRL, VAL_GPIOACRH},
-  {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH},
-  {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH},
-  {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH},
-  {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH},
-  {VAL_GPIOFODR, VAL_GPIOFCRL, VAL_GPIOFCRH},
-  {VAL_GPIOGODR, VAL_GPIOGCRL, VAL_GPIOGCRH},
-};
-
-#endif
-
-/*
- * Early initialization code.
- * This initialization must be performed just after stack setup and before
- * any other initialization.
- */
-void __early_init(void) {
-
-  stm32_clock_init();
-}
-
-/*
- * Board-specific initialization code.
- */
-void boardInit(void) {
-  /*
-   * Several I/O pins are re-mapped:
-   *   JTAG disabled and SWJ enabled
-   *   TIM2 to the PA15/PB3/PA2/PA3 pins.
-   *   TIM3 to PC6/PC7 pins.
-   *   USART3 to the PC10/PC11 pins.
-   *   I2C1 to the PB8/PB9 pins.
-   */
-  AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE |
-               AFIO_MAPR_TIM2_REMAP_PARTIALREMAP1 |
-               AFIO_MAPR_TIM3_REMAP_FULLREMAP |
-               AFIO_MAPR_USART3_REMAP_PARTIALREMAP |
-               AFIO_MAPR_I2C1_REMAP;
-}
-
-inline void boardWriteIoPower(const uint8_t value)
-{
-    if (value) {
-        // drive pins
-        palSetPadMode(GPIOA, GPIOA_CAN_TX, PAL_MODE_STM32_ALTERNATE_PUSHPULL);
-    } else {
-        // float pins
-        palSetPadMode(GPIOA, GPIOA_CAN_TX, PAL_MODE_INPUT);
-    }
-}
-
-inline void boardWriteLed(int value)
-{
-    palWritePad(GPIOA, GPIOA_LED, !value);
-}
-
-inline void boardRequestShutdown(void)
-{
-  palClearPad(GPIOC, GPIOC_SYS_PD_N);
-}
-
-inline void boardStandby(void)
-{
-
-  palSetPad(GPIOC, GPIOC_SYS_PD_N);
-  chSysLock();
-  // Standby
-  // set deepsleep bit
-  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
-  // enable wakeup pin
-  //PWR->CSR |= PWR_CSR_EWUP;
-  // set PDDS, clear WUF, clear SBF
-  PWR->CR |= (PWR_CR_CWUF | PWR_CR_PDDS | PWR_CR_CSBF);
-  // clear RTC wakeup source flags
-  RTC->CRL &= ~(RTC_CRL_ALRF);
-  // Wait for Interrupt
-  __WFI();
-
-}
-
-inline void boardWakeup(void) {
-
-  palClearPad(GPIOC, GPIOC_SYS_PD_N);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOC, GPIOC_SYS_PD_N);
-}
-
-inline void boardClearI2CBus(const uint8_t scl_pad, const uint8_t sda_pad) {
-
-  uint8_t i;
-
-  // configure I²C SCL and SDA open drain
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-
-  // perform a 2-wire software reset for the eeprom (see AT24C01BN-SH-B datasheet, chapter 3)
-  // note: clock is ~50kHz (20us per cycle)
-  palSetPad(GPIOB, sda_pad);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palSetPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  for (i = 0; i < 9; ++i) {
-    palSetPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(10);
-    palClearPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(10);
-  }
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palSetPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-
-  // perform bus clear as per I²C Specification v6 3.1.16
-  // note: clock is 100kHz (10us per cycle)
-  for (i = 0; i < 10; i++) {
-    palClearPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(5);
-    palSetPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(5);
-  }
-
-  // reconfigure I²C SCL
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
-
-  return;
-}
diff --git a/boards/DiWheelDrive/board.h b/boards/DiWheelDrive/board.h
deleted file mode 100644
index fe5c683..0000000
--- a/boards/DiWheelDrive/board.h
+++ /dev/null
@@ -1,207 +0,0 @@
-#ifndef _BOARD_H_
-#define _BOARD_H_
-
-/*
- * Setup for AMiRo DiWheelDrive board.
- */
-
-/*
- * Board identifier.
- */
-#define BOARD_DI_WHEEL_DRIVE
-#define BOARD_NAME              "AMiRo DiWheelDrive"
-#define BOARD_VERSION           "1.1"
-
-/*
- * Board frequencies.
- */
-#define STM32_LSECLK            0
-#define STM32_HSECLK            8000000
-
-/*
- * MCU type as defined in the ST header file stm32f1xx.h.
- */
-#define STM32F10X_HD
-
-/*
- * IO pins assignments.
- */
-#define GPIOA_WKUP              0
-#define GPIOA_LED               1
-#define GPIOA_DRIVE_PWM1A       2
-#define GPIOA_DRIVE_PWM1B       3
-#define GPIOA_MOTION_SCLK       5
-#define GPIOA_MOTION_MISO       6
-#define GPIOA_MOTION_MOSI       7
-#define GPIOA_PROG_RX           9
-#define GPIOA_PROG_TX           10
-#define GPIOA_CAN_RX            11
-#define GPIOA_CAN_TX            12
-#define GPIOA_SWDIO             13
-#define GPIOA_SWCLK             14
-#define GPIOA_DRIVE_PWM2B       15
-
-
-#define GPIOB_DRIVE_SENSE2      1
-#define GPIOB_POWER_EN          2
-#define GPIOB_DRIVE_PWM2A       3
-#define GPIOB_COMPASS_DRDY      5
-#define GPIOB_DRIVE_ENC1A       6
-#define GPIOB_DRIVE_ENC1B       7
-#define GPIOB_COMPASS_SCL       8
-#define GPIOB_COMPASS_SDA       9
-#define GPIOB_IR_SCL            10
-#define GPIOB_IR_SDA            11
-#define GPIOB_IR_INT            12
-#define GPIOB_GYRO_DRDY         13
-#define GPIOB_SYS_UART_UP       14
-#define GPIOB_ACCEL_INT_N       15
-
-#define GPIOC_DRIVE_SENSE1      0
-#define GPIOC_SYS_INT_N         1
-#define GPIOC_PATH_DCSTAT       3
-#define GPIOC_PATH_DCEN         5
-#define GPIOC_DRIVE_ENC2B       6
-#define GPIOC_DRIVE_ENC2A       7
-#define GPIOC_SYS_PD_N          8
-#define GPIOC_SYS_REG_EN        9
-#define GPIOC_SYS_UART_RX       10
-#define GPIOC_SYS_UART_TX       11
-#define GPIOC_ACCEL_SS_N        13
-#define GPIOC_GYRO_SS_N         14
-
-#define GPIOD_OSC_IN            0
-#define GPIOD_OSC_OUT           1
-#define GPIOD_SYS_WARMRST_N     2
-
-/*
- * I/O ports initial setup, this configuration is established soon after reset
- * in the initialization code.
- */
-#define PIN_MODE_INPUT(n)               (0x4U << (((n) % 8) * 4))
-#define PIN_MODE_INPUT_PULLX(n)         (0x8U << (((n) % 8) * 4))
-#define PIN_MODE_INPUT_ANALOG(n)        (0x0U << (((n) % 8) * 4))
-/* Push Pull output 50MHz */
-#define PIN_MODE_OUTPUT_PUSHPULL(n)     (0x3U << (((n) % 8) * 4))
-/* Open Drain output 50MHz */
-#define PIN_MODE_OUTPUT_OPENDRAIN(n)    (0x7U << (((n) % 8) * 4))
-/* Alternate Push Pull output 50MHz */
-#define PIN_MODE_ALTERNATE_PUSHPULL(n)  (0xbU << (((n) % 8) * 4))
-/* Alternate Open Drain output 50MHz */
-#define PIN_MODE_ALTERNATE_OPENDRAIN(n) (0xfU << (((n) % 8) * 4))
-
-/*
- * Port A setup.
- */
-#define VAL_GPIOACRL            (PIN_MODE_INPUT(GPIOA_WKUP) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOA_LED) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_DRIVE_PWM1A) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_DRIVE_PWM1B) | \
-                                 PIN_MODE_INPUT_PULLX(4) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_MOTION_SCLK) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_MOTION_MISO) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_MOTION_MOSI))
-#define VAL_GPIOACRH            (PIN_MODE_INPUT_PULLX(8) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_PROG_RX) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_PROG_TX) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_CAN_RX) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_CAN_TX) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_SWDIO) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_SWCLK) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_DRIVE_PWM2B))
-#define VAL_GPIOAODR            0xF7FF /* prevent power over CAN bug */
-
-/*
- * Port B setup.
- */
-#define VAL_GPIOBCRL            (PIN_MODE_INPUT_PULLX(0) | \
-                                 PIN_MODE_INPUT_ANALOG(GPIOB_DRIVE_SENSE2) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOB_POWER_EN) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOB_DRIVE_PWM2A) | \
-                                 PIN_MODE_INPUT_PULLX(4) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOB_COMPASS_DRDY) | \
-                                 PIN_MODE_INPUT(GPIOB_DRIVE_ENC1A) | \
-                                 PIN_MODE_INPUT(GPIOB_DRIVE_ENC1B))
-#define VAL_GPIOBCRH            (PIN_MODE_ALTERNATE_OPENDRAIN(GPIOB_COMPASS_SCL) | \
-                                 PIN_MODE_ALTERNATE_OPENDRAIN(GPIOB_COMPASS_SDA) | \
-                                 PIN_MODE_ALTERNATE_OPENDRAIN(GPIOB_IR_SCL) | \
-                                 PIN_MODE_ALTERNATE_OPENDRAIN(GPIOB_IR_SDA) | \
-                                 PIN_MODE_INPUT(GPIOB_IR_INT) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOB_GYRO_DRDY) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOB_SYS_UART_UP) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOB_ACCEL_INT_N))
-#define VAL_GPIOBODR            0xFFFB /* initially the motors are not powered */
-
-/*
- * Port C setup.
- */
-#define VAL_GPIOCCRL            (PIN_MODE_INPUT_ANALOG(GPIOC_DRIVE_SENSE1) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOC_SYS_INT_N) | \
-                                 PIN_MODE_INPUT_PULLX(2) | \
-                                 PIN_MODE_INPUT(GPIOC_PATH_DCSTAT) | \
-                                 PIN_MODE_INPUT_PULLX(4) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOC_PATH_DCEN) | \
-                                 PIN_MODE_INPUT(GPIOC_DRIVE_ENC2B) | \
-                                 PIN_MODE_INPUT(GPIOC_DRIVE_ENC2A))
-#define VAL_GPIOCCRH            (PIN_MODE_OUTPUT_OPENDRAIN(GPIOC_SYS_PD_N) | \
-                                 PIN_MODE_INPUT(GPIOC_SYS_REG_EN) | \
-                                 PIN_MODE_INPUT(GPIOC_SYS_UART_RX) | \
-                                 PIN_MODE_INPUT(GPIOC_SYS_UART_TX) | \
-                                 PIN_MODE_INPUT_PULLX(12) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOC_ACCEL_SS_N) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOC_GYRO_SS_N) | \
-                                 PIN_MODE_INPUT_PULLX(15))
-#define VAL_GPIOCODR            0xFFDD /* initially charging via the pins is disabled and SYSNIN_N indicates that the OS is busy */
-
-/*
- * Port D setup.
- */
-#define VAL_GPIODCRL            (PIN_MODE_INPUT(GPIOD_OSC_IN) | \
-                                 PIN_MODE_INPUT(GPIOD_OSC_OUT) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOD_SYS_WARMRST_N) | \
-                                 PIN_MODE_INPUT_PULLX(3) | \
-                                 PIN_MODE_INPUT_PULLX(4) | \
-                                 PIN_MODE_INPUT_PULLX(5) | \
-                                 PIN_MODE_INPUT_PULLX(6) | \
-                                 PIN_MODE_INPUT_PULLX(7))
-#define VAL_GPIODCRH            0x88888888
-#define VAL_GPIODODR            0xFFFF
-
-/*
- * Port E setup.
- */
-#define VAL_GPIOECRL            0x88888888 /*  PE7...PE0 */
-#define VAL_GPIOECRH            0x88888888 /* PE15...PE8 */
-#define VAL_GPIOEODR            0xFFFF
-
-/*
- * Port F setup.
- */
-#define VAL_GPIOFCRL            0x88888888 /*  PF7...PF0 */
-#define VAL_GPIOFCRH            0x88888888 /* PF15...PF8 */
-#define VAL_GPIOFODR            0xFFFF
-
-/*
- * Port G setup.
- */
-#define VAL_GPIOGCRL            0x88888888 /*  PG7...PG0 */
-#define VAL_GPIOGCRH            0x88888888 /* PG15...PG8 */
-#define VAL_GPIOGODR            0xFFFF
-
-#if !defined(_FROM_ASM_)
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void boardInit(void);
-  void boardWriteIoPower(const uint8_t value);
-  void boardWriteLed(int value);
-  void boardRequestShutdown(void);
-  void boardStandby(void);
-  void boardWakeup(void);
-  void boardClearI2CBus(const uint8_t scl_pad, const uint8_t sda_pad);
-#ifdef __cplusplus
-}
-#endif
-#endif /* _FROM_ASM_ */
-
-#endif /* _BOARD_H_ */
diff --git a/boards/DiWheelDrive/board.mk b/boards/DiWheelDrive/board.mk
deleted file mode 100644
index ad22449..0000000
--- a/boards/DiWheelDrive/board.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-# List of all the board related files.
-BOARDSRC = ${AMIRO}/boards/DiWheelDrive/board.c
-
-# Required include directories
-BOARDINC = ${AMIRO}/boards/DiWheelDrive
-
-# Required linker directory
-BOARDLD = ${AMIRO}/ports
-
diff --git a/boards/LightRing/board.c b/boards/LightRing/board.c
deleted file mode 100644
index eec705c..0000000
--- a/boards/LightRing/board.c
+++ /dev/null
@@ -1,121 +0,0 @@
-#include "ch.h"
-#include "hal.h"
-
-/**
- * @brief   PAL setup.
- * @details Digital I/O ports static configuration as defined in @p board.h.
- *          This variable is used by the HAL when initializing the PAL driver.
- */
-#if HAL_USE_PAL || defined(__DOXYGEN__)
-const PALConfig pal_default_config =
-{
-  {VAL_GPIOAODR, VAL_GPIOACRL, VAL_GPIOACRH},
-  {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH},
-  {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH},
-  {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH},
-  {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH},
-  {VAL_GPIOFODR, VAL_GPIOFCRL, VAL_GPIOFCRH},
-  {VAL_GPIOGODR, VAL_GPIOGCRL, VAL_GPIOGCRH},
-};
-
-#endif
-
-/*
- * Early initialization code.
- * This initialization must be performed just after stack setup and before
- * any other initialization.
- */
-void __early_init(void) {
-
-  stm32_clock_init();
-}
-
-/*
- * Board-specific initialization code.
- */
-void boardInit(void) {
-  /*
-   * Several I/O pins are re-mapped:
-   *   JTAG disabled and SWD enabled
-   */
-  AFIO->MAPR = AFIO_MAPR_SWJ_CFG_JTAGDISABLE |
-               AFIO_MAPR_USART3_REMAP_PARTIALREMAP;
-}
-
-inline void boardRequestShutdown(void)
-{
-  palClearPad(GPIOC, GPIOC_SYS_PD_N);
-}
-
-inline void boardStandby(void)
-{
-
-  palSetPad(GPIOC, GPIOC_SYS_PD_N);
-  chSysLock();
-  // Standby
-  // set deepsleep bit
-  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
-  // set PDDS, clear WUF, clear SBF
-  PWR->CR |= (PWR_CR_CWUF | PWR_CR_PDDS | PWR_CR_CSBF);
-  // clear RTC wakeup source flags
-  RTC->CRL &= ~(RTC_CRL_ALRF);
-  // Wait for Interrupt
-  __WFI();
-
-}
-
-inline void boardClearI2CBus(const uint8_t scl_pad, const uint8_t sda_pad) {
-
-  uint8_t i;
-
-  // configure I²C SCL and SDA open drain
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-
-  // perform a 2-wire software reset for the eeprom (see AT24C01BN-SH-B datasheet, chapter 3)
-  // note: clock is ~50kHz (20us per cycle)
-  palSetPad(GPIOB, sda_pad);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palSetPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  for (i = 0; i < 9; ++i) {
-    palSetPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(10);
-    palClearPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(10);
-  }
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palSetPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-
-  // perform bus clear as per I²C Specification v6 3.1.16
-  // note: clock is 100kHz (10us per cycle)
-  for (i = 0; i < 10; i++) {
-    palClearPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(5);
-    palSetPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(5);
-  }
-
-  // reconfigure I²C SCL
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
-
-  return;
-}
diff --git a/boards/LightRing/board.h b/boards/LightRing/board.h
deleted file mode 100644
index 3ae668f..0000000
--- a/boards/LightRing/board.h
+++ /dev/null
@@ -1,187 +0,0 @@
-#ifndef _BOARD_H_
-#define _BOARD_H_
-
-/*
- * Setup for AMiRo LightRing board.
- */
-
-/*
- * Board identifier.
- */
-#define BOARD_LIGHT_RING
-#define BOARD_NAME              "AMiRo LightRing"
-#define BOARD_VERSION           "1.0"
-
-/*
- * Board frequencies.
- */
-#define STM32_LSECLK            0
-#define STM32_HSECLK            8000000
-
-/*
- * MCU type as defined in the ST header file stm32f1xx.h.
- */
-#define STM32F10X_HD
-
-/*
- * IO pins assignments.
- */
-#define GPIOA_LASER_RX          2
-#define GPIOA_LASER_TX          3
-#define GPIOA_LIGHT_BLANK       4
-#define GPIOA_LIGHT_SCLK        5
-#define GPIOA_LIGHT_MOSI        7
-#define GPIOA_PROG_RX           9
-#define GPIOA_PROG_TX           10
-#define GPIOA_CAN_RX            11
-#define GPIOA_CAN_TX            12
-
-#define GPIOB_LASER_EN          2
-#define GPIOB_LASER_OC_N        5
-#define GPIOB_SYS_UART_DN       6
-#define GPIOB_WL_GDO2           8
-#define GPIOB_WL_GDO0           9
-#define GPIOB_MEM_SCL           10
-#define GPIOB_MEM_SDA           11
-#define GPIOB_WL_SS_N           12
-#define GPIOB_WL_SCLK           13
-#define GPIOB_WL_MISO           14
-#define GPIOB_WL_MOSI           15
-
-#define GPIOC_LIGHT_XLAT        4
-#define GPIOC_SYS_UART_RX       10
-#define GPIOC_SYS_UART_TX       11
-#define GPIOC_SYS_PD_N          14
-
-#define GPIOD_OSC_IN            0
-#define GPIOD_OSC_OUT           1
-#define GPIOD_SYS_INT_N         2
-
-/*
- * I/O ports initial setup, this configuration is established soon after reset
- * in the initialization code.
- */
-#define PIN_MODE_INPUT(n)               (0x4U << (((n) % 8) * 4))
-#define PIN_MODE_INPUT_PULLX(n)         (0x8U << (((n) % 8) * 4))
-#define PIN_MODE_INPUT_ANALOG(n)        (0x0U << (((n) % 8) * 4))
-/* Push Pull output 50MHz */
-#define PIN_MODE_OUTPUT_PUSHPULL(n)     (0x3U << (((n) % 8) * 4))
-/* Open Drain output 50MHz */
-#define PIN_MODE_OUTPUT_OPENDRAIN(n)    (0x7U << (((n) % 8) * 4))
-/* Alternate Push Pull output 50MHz */
-#define PIN_MODE_ALTERNATE_PUSHPULL(n)  (0xbU << (((n) % 8) * 4))
-/* Alternate Open Drain output 50MHz */
-#define PIN_MODE_ALTERNATE_OPENDRAIN(n) (0xfU << (((n) % 8) * 4))
-
-/*
- * Port A setup.
- */
-#define VAL_GPIOACRL            (PIN_MODE_INPUT_PULLX(0) | \
-                                 PIN_MODE_INPUT_PULLX(1) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_LASER_RX) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_LASER_TX) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOA_LIGHT_BLANK) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_LIGHT_SCLK) | \
-                                 PIN_MODE_INPUT_PULLX(6) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_LIGHT_MOSI))
-#define VAL_GPIOACRH            (PIN_MODE_INPUT_PULLX(8) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_PROG_RX) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOA_PROG_TX) | \
-                                 PIN_MODE_INPUT(GPIOA_CAN_RX) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOA_CAN_TX) | \
-                                 PIN_MODE_INPUT_PULLX(13) | \
-                                 PIN_MODE_INPUT_PULLX(14) | \
-                                 PIN_MODE_INPUT_PULLX(15))
-#define VAL_GPIOAODR            0xFFFF
-
-/*
- * Port B setup.
- */
-#define VAL_GPIOBCRL            (PIN_MODE_INPUT_PULLX(0) | \
-                                 PIN_MODE_INPUT_PULLX(1) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOB_LASER_EN) | \
-                                 PIN_MODE_INPUT_PULLX(3) | \
-                                 PIN_MODE_INPUT_PULLX(4) | \
-                                 PIN_MODE_INPUT(GPIOB_LASER_OC_N) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOB_SYS_UART_DN) | \
-                                 PIN_MODE_INPUT_PULLX(7))
-#define VAL_GPIOBCRH            (PIN_MODE_INPUT_PULLX(GPIOB_WL_GDO2) | \
-                                 PIN_MODE_INPUT_PULLX(GPIOB_WL_GDO0) | \
-                                 PIN_MODE_ALTERNATE_OPENDRAIN(GPIOB_MEM_SCL) | \
-                                 PIN_MODE_ALTERNATE_OPENDRAIN(GPIOB_MEM_SDA) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOB_WL_SS_N) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOB_WL_SCLK) | \
-                                 PIN_MODE_INPUT(GPIOB_WL_MISO) | \
-                                 PIN_MODE_ALTERNATE_PUSHPULL(GPIOB_WL_MOSI))
-#define VAL_GPIOBODR            0xFFFB /* initially LASER_EN is deactivated */
-
-/*
- * Port C setup.
- */
-#define VAL_GPIOCCRL            (PIN_MODE_INPUT_PULLX(0) | \
-                                 PIN_MODE_INPUT_PULLX(1) | \
-                                 PIN_MODE_INPUT_PULLX(2) | \
-                                 PIN_MODE_INPUT_PULLX(3) | \
-                                 PIN_MODE_OUTPUT_PUSHPULL(GPIOC_LIGHT_XLAT) | \
-                                 PIN_MODE_INPUT_PULLX(5) | \
-                                 PIN_MODE_INPUT_PULLX(6) | \
-                                 PIN_MODE_INPUT_PULLX(7))
-#define VAL_GPIOCCRH            (PIN_MODE_INPUT_PULLX(8) | \
-                                 PIN_MODE_INPUT_PULLX(9) | \
-                                 PIN_MODE_INPUT(GPIOC_SYS_UART_RX) | \
-                                 PIN_MODE_INPUT(GPIOC_SYS_UART_TX) | \
-                                 PIN_MODE_INPUT_PULLX(12) | \
-                                 PIN_MODE_INPUT_PULLX(13) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOC_SYS_PD_N) | \
-                                 PIN_MODE_INPUT_PULLX(15))
-#define VAL_GPIOCODR            0xFFFF
-
-/*
- * Port D setup.
- */
-#define VAL_GPIODCRL            (PIN_MODE_INPUT(GPIOD_OSC_IN) | \
-                                 PIN_MODE_INPUT(GPIOD_OSC_OUT) | \
-                                 PIN_MODE_OUTPUT_OPENDRAIN(GPIOD_SYS_INT_N) | \
-                                 PIN_MODE_INPUT_PULLX(3) | \
-                                 PIN_MODE_INPUT_PULLX(4) | \
-                                 PIN_MODE_INPUT_PULLX(5) | \
-                                 PIN_MODE_INPUT_PULLX(6) | \
-                                 PIN_MODE_INPUT_PULLX(7))
-#define VAL_GPIODCRH            0x88888888
-#define VAL_GPIODODR            0xFFFB /* initially SYS_INT_N indicates that the OS is busy */
-
-/*
- * Port E setup.
- */
-#define VAL_GPIOECRL            0x88888888 /*  PE7...PE0 */
-#define VAL_GPIOECRH            0x88888888 /* PE15...PE8 */
-#define VAL_GPIOEODR            0xFFFF
-
-/*
- * Port F setup.
- */
-#define VAL_GPIOFCRL            0x88888888 /*  PF7...PF0 */
-#define VAL_GPIOFCRH            0x88888888 /* PF15...PF8 */
-#define VAL_GPIOFODR            0xFFFF
-
-/*
- * Port G setup.
- */
-#define VAL_GPIOGCRL            0x88888888 /*  PG7...PG0 */
-#define VAL_GPIOGCRH            0x88888888 /* PG15...PG8 */
-#define VAL_GPIOGODR            0xFFFF
-
-#if !defined(_FROM_ASM_)
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void boardInit(void);
-  void boardRequestShutdown(void);
-  void boardStandby(void);
-  void boardClearI2CBus(const uint8_t scl_pad, const uint8_t sda_pad);
-#ifdef __cplusplus
-}
-#endif
-#endif /* _FROM_ASM_ */
-
-#endif /* _BOARD_H_ */
diff --git a/boards/LightRing/board.mk b/boards/LightRing/board.mk
deleted file mode 100644
index f8f1d7a..0000000
--- a/boards/LightRing/board.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-# List of all the board related files.
-BOARDSRC = ${AMIRO}/boards/LightRing/board.c
-
-# Required include directories
-BOARDINC = ${AMIRO}/boards/LightRing
-
-# Required linker directory
-BOARDLD = ${AMIRO}/ports
-
diff --git a/boards/PowerManagement/board.c b/boards/PowerManagement/board.c
deleted file mode 100644
index d6f596b..0000000
--- a/boards/PowerManagement/board.c
+++ /dev/null
@@ -1,219 +0,0 @@
-#include "ch.h"
-#include "hal.h"
-#include "board.h"
-
-/**
- * @brief   PAL setup.
- * @details Digital I/O ports static configuration as defined in @p board.h.
- *          This variable is used by the HAL when initializing the PAL driver.
- */
-#if HAL_USE_PAL || defined(__DOXYGEN__)
-const PALConfig pal_default_config =
-{
-  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR, VAL_GPIOA_ODR, VAL_GPIOA_AFRL, VAL_GPIOA_AFRH},
-  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR, VAL_GPIOB_ODR, VAL_GPIOB_AFRL, VAL_GPIOB_AFRH},
-  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR, VAL_GPIOC_ODR, VAL_GPIOC_AFRL, VAL_GPIOC_AFRH},
-  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR, VAL_GPIOD_ODR, VAL_GPIOD_AFRL, VAL_GPIOD_AFRH},
-  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR, VAL_GPIOE_ODR, VAL_GPIOE_AFRL, VAL_GPIOE_AFRH},
-  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR, VAL_GPIOF_ODR, VAL_GPIOF_AFRL, VAL_GPIOF_AFRH},
-  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR, VAL_GPIOG_ODR, VAL_GPIOG_AFRL, VAL_GPIOG_AFRH},
-  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR, VAL_GPIOH_ODR, VAL_GPIOH_AFRL, VAL_GPIOH_AFRH},
-  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR, VAL_GPIOI_ODR, VAL_GPIOI_AFRL, VAL_GPIOI_AFRH}
-};
-#endif
-
-/*
- * Early initialization code.
- * This initialization must be performed just after stack setup and before
- * any other initialization.
- */
-void __early_init(void) {
-
-  stm32_clock_init();
-}
-
-/*
- * Board-specific initialization code.
- */
-void boardInit(void) {
-
-}
-
-inline void boardWriteIoPower(int value)
-{
-    palWritePad(GPIOA, GPIOA_SYS_REG_EN, value);
-    if (value) {
-        // drive pins
-        palSetPadMode(GPIOA, GPIOA_CAN_TX, PAL_MODE_ALTERNATE(9));
-        palSetPadMode(GPIOA, GPIOA_SYS_UART_TX, PAL_MODE_ALTERNATE(7));
-        palSetPadMode(GPIOB, GPIOB_BT_CTS, PAL_MODE_ALTERNATE(7));
-    } else {
-        // float pins
-        palSetPadMode(GPIOA, GPIOA_CAN_TX, PAL_MODE_INPUT);
-        palSetPadMode(GPIOA, GPIOA_SYS_UART_TX, PAL_MODE_INPUT);
-        palSetPadMode(GPIOB, GPIOB_BT_CTS, PAL_MODE_INPUT);
-    }
-    chThdSleepMilliseconds(50);
-}
-
-inline void boardWriteLed(int value)
-{
-    palWritePad(GPIOB, GPIOB_LED, !value);
-}
-
-inline void boardWriteSystemPower(int value)
-{
-    palWritePad(GPIOB, GPIOB_POWER_EN, value);
-    chThdSleepMilliseconds(50);
-}
-
-inline void boardWriteWarmRestart(const uint8_t value)
-{
-    palWritePad(GPIOC, GPIOC_SYS_WARMRST_N, ~value);
-    chThdSleepMilliseconds(50);
-}
-
-inline void boardChargerSetState(uint8_t chrg_mask, uint8_t state)
-{
-  if (chrg_mask & (1u << 0))
-    palWritePad(GPIOC, GPIOC_CHARGE_EN1_N, ~state);
-  if (chrg_mask & (1u << 1))
-    palWritePad(GPIOD, GPIOD_CHARGE_EN2_N, ~state);
-}
-
-inline void boardBluetoothSetState(uint8_t state)
-{
-    palWritePad(GPIOC, GPIOC_BT_RST, ~state);
-}
-
-inline void boardRequestShutdown(void)
-{
-  palClearPad(GPIOC, GPIOC_SYS_PD_N);
-}
-
-#define RTC_ISR_TAMP2F ((uint32_t)0x00004000)
-
-inline void boardStandby(void)
-{
-
-  chSysLock();
-  // set deepsleep bit
-  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
-  // enable wakeup pin
-  PWR->CSR |= PWR_CSR_EWUP;
-  // set PDDS, clear WUF, clear SBF
-  PWR->CR |= (PWR_CR_CWUF | PWR_CR_PDDS | PWR_CR_CSBF);
-  // clear RTC wakeup source flags
-  RTC->ISR &= ~(RTC_ISR_ALRBF | RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TAMP1F | RTC_ISR_TAMP2F |
-                RTC_ISR_TSOVF | RTC_ISR_TSF);
-  // Wait for Interrupt
-  __WFI();
-
-}
-
-inline void boardStop(const uint8_t lpds, const uint8_t fpds)
-{
-
-  chSysLock();
-  // set deepsleep bit
-  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
-  // enable wakeup pin
-  //PWR->CSR |= PWR_CSR_EWUP;
-  // clear PDDS, clear LPDS, clear FPDS
-  PWR->CR &= ~(PWR_CR_PDDS | PWR_CR_LPDS | PWR_CR_FPDS);
-  // clear WUF, clear SBF
-  PWR->CR |= (PWR_CR_CWUF | PWR_CR_CSBF);
-  if (lpds)
-    PWR->CR |= (PWR_CR_LPDS);
-  if (fpds)
-    PWR->CR |= (PWR_CR_FPDS);
-  // clear RTC wakeup source flags
-  RTC->ISR &= ~(RTC_ISR_ALRBF | RTC_ISR_ALRAF | RTC_ISR_WUTF | RTC_ISR_TAMP1F | RTC_ISR_TAMP2F |
-                RTC_ISR_TSOVF | RTC_ISR_TSF);
-  // clear pending interrupts
-  EXTI->PR = ~0;
-  // Wait for Interrupt
-  __WFI();
-
-}
-
-#undef RTC_ISR_TAMP2F
-
-inline void boardWakeup(void) {
-
-  palClearPad(GPIOC, GPIOC_SYS_PD_N);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOC, GPIOC_SYS_PD_N);
-}
-
-inline void boardClearI2CBus(const uint8_t scl_pad, const uint8_t sda_pad) {
-
-  uint8_t i;
-
-  // configure I²C SCL and SDA open drain
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-
-  // perform a 2-wire software reset for the eeprom (see AT24C01BN-SH-B datasheet, chapter 3)
-  // note: clock is ~50kHz (20us per cycle)
-  palSetPad(GPIOB, sda_pad);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palSetPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  for (i = 0; i < 9; ++i) {
-    palSetPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(10);
-    palClearPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(10);
-  }
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-  palSetPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(5);
-  palSetPad(GPIOB, sda_pad);
-  chThdSleepMicroseconds(5);
-  palClearPad(GPIOB, scl_pad);
-  chThdSleepMicroseconds(10);
-
-  // perform bus clear as per I²C Specification v6 3.1.16
-  // note: clock is 100kHz (10us per cycle)
-  for (i = 0; i < 10; i++) {
-    palClearPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(5);
-    palSetPad(GPIOB, scl_pad);
-    chThdSleepMicroseconds(5);
-  }
-
-  // reconfigure I²C SCL
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_ALTERNATE(4) | PAL_STM32_OTYPE_OPENDRAIN);
-
-  return;
-}
-
-inline void boardResetBQ27500I2C(const uint8_t scl_pad, const uint8_t sda_pad) {
-
-  // configure I²C SCL and SDA open drain
-  palSetPadMode(GPIOB, scl_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-  palSetPadMode(GPIOB, sda_pad, PAL_MODE_OUTPUT_OPENDRAIN);
-
-  // BQ27500: reset by holding bus low for t_BUSERR (17.3 - 21.2 seconds)
-  palClearPad(GPIOB, scl_pad);
-  palClearPad(GPIOB, sda_pad);
-  chThdSleepSeconds(20);
-
-  boardClearI2CBus(scl_pad, sda_pad);
-
-  return;
-}
diff --git a/boards/PowerManagement/board.h b/boards/PowerManagement/board.h
deleted file mode 100644
index 4a1a234..0000000
--- a/boards/PowerManagement/board.h
+++ /dev/null
@@ -1,385 +0,0 @@
-#ifndef _BOARD_H_
-#define _BOARD_H_
-
-/*
- * Setup for AMiRo PowerManagement board.
- */
-
-/*
- * Board identifier.
- */
-#define BOARD_POWER_MANAGEMENT
-#define BOARD_NAME              "AMiRo PowerManagement"
-#define BOARD_VERSION           "1.1"
-
-/*
- * Board frequencies.
- */
-#define STM32_LSECLK            0
-#define STM32_HSECLK            8000000
-
-/*
- * Board voltages.
- * Required for performance limits calculation.
- */
-#define STM32_VDD               330
-
-/*
- * MCU type as defined in the ST header file stm32f4xx.h.
- */
-#define STM32F40_41xxx
-
-/*
- * IO pins assignments.
- */
-#define GPIOA_WKUP              0
-#define GPIOA_SYS_UART_TX       2
-#define GPIOA_SYS_UART_RX       3
-#define GPIOA_SYS_SPI_SS0_N     4
-#define GPIOA_SYS_SPI_SCLK      5
-#define GPIOA_SYS_SPI_MISO      6
-#define GPIOA_SYS_SPI_MOSI      7
-#define GPIOA_SYS_REG_EN        8
-#define GPIOA_PROG_RX           9
-#define GPIOA_PROG_TX           10
-#define GPIOA_CAN_RX            11
-#define GPIOA_CAN_TX            12
-#define GPIOA_SYS_SPI_SS1_N     15
-
-#define GPIOB_IR_INT1_N         0
-#define GPIOB_VSYS_SENSE        1
-#define GPIOB_POWER_EN          2
-#define GPIOB_SYS_UART_DN       3
-#define GPIOB_CHARGE_STAT2A     4
-#define GPIOB_BUZZER            5
-#define GPIOB_GAUGE_BATLOW2     6
-#define GPIOB_GAUGE_BATGD2_N    7
-#define GPIOB_GAUGE_SCL2        8
-#define GPIOB_GAUGE_SDA2        9
-#define GPIOB_GAUGE_SCL1        10
-#define GPIOB_GAUGE_SDA1        11
-#define GPIOB_LED               12
-#define GPIOB_BT_RTS            13
-#define GPIOB_BT_CTS            14
-#define GPIOB_SYS_UART_UP       15
-
-#define GPIOC_CHARGE_STAT1A     0
-#define GPIOC_GAUGE_BATLOW1     1
-#define GPIOC_GAUGE_BATGD1_N    2
-#define GPIOC_CHARGE_EN1_N      3
-#define GPIOC_IR_INT2_N         4
-#define GPIOC_TOUCH_INT_N       5
-#define GPIOC_SYS_DONE          6
-#define GPIOC_SYS_PROG_N        7
-#define GPIOC_PATH_DC           8
-#define GPIOC_SYS_SPI_DIR       9
-#define GPIOC_BT_RX             10
-#define GPIOC_BT_TX             11
-#define GPIOC_SYS_INT_N         12
-#define GPIOC_SYS_PD_N          13
-#define GPIOC_SYS_WARMRST_N     14
-#define GPIOC_BT_RST            15
-
-#define GPIOD_CHARGE_EN2_N      2
-
-#define GPIOH_OSC_IN            0
-#define GPIOH_OSC_OUT           1
-
-/*
- * I/O ports initial setup, this configuration is established soon after reset
- * in the initialization code.
- */
-#define PIN_MODE_INPUT(n)       (0U << ((n) * 2))
-#define PIN_MODE_OUTPUT(n)      (1U << ((n) * 2))
-#define PIN_MODE_ALTERNATE(n)   (2U << ((n) * 2))
-#define PIN_MODE_ANALOG(n)      (3U << ((n) * 2))
-#define PIN_OTYPE_PUSHPULL(n)   (0U << (n))
-#define PIN_OTYPE_OPENDRAIN(n)  (1U << (n))
-#define PIN_OSPEED_2M(n)        (0U << ((n) * 2))
-#define PIN_OSPEED_25M(n)       (1U << ((n) * 2))
-#define PIN_OSPEED_50M(n)       (2U << ((n) * 2))
-#define PIN_OSPEED_100M(n)      (3U << ((n) * 2))
-#define PIN_PUDR_FLOATING(n)    (0U << ((n) * 2))
-#define PIN_PUDR_PULLUP(n)      (1U << ((n) * 2))
-#define PIN_PUDR_PULLDOWN(n)    (2U << ((n) * 2))
-#define PIN_AFIO_AF(n, v)       ((v##U) << ((n % 8) * 4))
-
-/*
- * Port A setup.
- */
-#define VAL_GPIOA_MODER         (PIN_MODE_INPUT(GPIOA_WKUP) | \
-                                 PIN_MODE_INPUT(1) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_SYS_UART_TX) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_SYS_UART_RX) | \
-                                 PIN_MODE_INPUT(GPIOA_SYS_SPI_SS0_N) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_SYS_SPI_SCLK) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_SYS_SPI_MOSI) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_SYS_SPI_MISO) | \
-                                 PIN_MODE_INPUT(GPIOA_SYS_SPI_SS1_N) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_PROG_RX) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_PROG_TX) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_CAN_RX) | \
-                                 PIN_MODE_ALTERNATE(GPIOA_CAN_TX) | \
-                                 PIN_MODE_INPUT(13) | \
-                                 PIN_MODE_INPUT(14) | \
-                                 PIN_MODE_OUTPUT(GPIOA_SYS_REG_EN))
-#define VAL_GPIOA_OTYPER        (PIN_OTYPE_PUSHPULL(GPIOA_SYS_UART_TX) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOA_SYS_SPI_SS0_N) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOA_PROG_RX) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOA_CAN_TX) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOA_SYS_REG_EN))
-#define VAL_GPIOA_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOA_PUPDR         (PIN_PUDR_FLOATING(GPIOA_WKUP) | \
-                                 PIN_PUDR_PULLUP(1) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_UART_TX) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_UART_RX) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_SPI_SS0_N) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_SPI_SCLK) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_SPI_MOSI) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_SPI_MISO) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_SPI_SS1_N) | \
-                                 PIN_PUDR_FLOATING(GPIOA_PROG_RX) | \
-                                 PIN_PUDR_PULLUP(GPIOA_PROG_TX) | \
-                                 PIN_PUDR_FLOATING(GPIOA_CAN_RX) | \
-                                 PIN_PUDR_FLOATING(GPIOA_CAN_TX) | \
-                                 PIN_PUDR_PULLUP(13) | \
-                                 PIN_PUDR_PULLUP(14) | \
-                                 PIN_PUDR_FLOATING(GPIOA_SYS_REG_EN))
-
-#define VAL_GPIOA_ODR           0xFFFF
-#define VAL_GPIOA_AFRL          (PIN_AFIO_AF(GPIOA_SYS_UART_TX, 7) | \
-                                 PIN_AFIO_AF(GPIOA_SYS_UART_RX, 7) | \
-                                 PIN_AFIO_AF(GPIOA_SYS_SPI_SCLK, 5) | \
-                                 PIN_AFIO_AF(GPIOA_SYS_SPI_MISO, 5) | \
-                                 PIN_AFIO_AF(GPIOA_SYS_SPI_MOSI, 5))
-#define VAL_GPIOA_AFRH          (PIN_AFIO_AF(GPIOA_PROG_RX, 7) | \
-                                 PIN_AFIO_AF(GPIOA_PROG_TX, 7) | \
-                                 PIN_AFIO_AF(GPIOA_CAN_RX, 9) | \
-                                 PIN_AFIO_AF(GPIOA_CAN_TX, 9))
-
-/*
- * Port B setup.
- */
-#define VAL_GPIOB_MODER         (PIN_MODE_INPUT(GPIOB_IR_INT1_N) | \
-                                 PIN_MODE_ANALOG(GPIOB_VSYS_SENSE) | \
-                                 PIN_MODE_OUTPUT(GPIOB_POWER_EN) | \
-                                 PIN_MODE_OUTPUT(GPIOB_SYS_UART_DN) | \
-                                 PIN_MODE_INPUT(GPIOB_CHARGE_STAT2A) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_BUZZER) | \
-                                 PIN_MODE_INPUT(GPIOB_GAUGE_BATLOW2) | \
-                                 PIN_MODE_INPUT(GPIOB_GAUGE_BATGD2_N) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_GAUGE_SCL2) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_GAUGE_SDA2) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_GAUGE_SCL1) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_GAUGE_SDA1) | \
-                                 PIN_MODE_OUTPUT(GPIOB_LED) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_BT_RTS) | \
-                                 PIN_MODE_ALTERNATE(GPIOB_BT_CTS) | \
-                                 PIN_MODE_OUTPUT(GPIOB_SYS_UART_UP))
-#define VAL_GPIOB_OTYPER        (PIN_OTYPE_PUSHPULL(GPIOB_POWER_EN) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_SYS_UART_DN) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOB_BUZZER) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SCL2) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SDA2) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SCL1) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SDA1) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_LED) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOB_BT_CTS) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOB_SYS_UART_UP))
-#define VAL_GPIOB_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOB_PUPDR         0x00000000
-#define VAL_GPIOB_ODR           0xFFFF
-#define VAL_GPIOB_AFRL          (PIN_AFIO_AF(GPIOB_BUZZER, 2))
-#define VAL_GPIOB_AFRH          (PIN_AFIO_AF(GPIOB_GAUGE_SCL2, 4) | \
-                                 PIN_AFIO_AF(GPIOB_GAUGE_SDA2, 4) | \
-                                 PIN_AFIO_AF(GPIOB_GAUGE_SCL1, 4) | \
-                                 PIN_AFIO_AF(GPIOB_GAUGE_SDA1, 4) | \
-                                 PIN_AFIO_AF(GPIOB_BT_RTS, 7) | \
-                                 PIN_AFIO_AF(GPIOB_BT_CTS, 7))
-
-/*
- * Port C setup.
- */
-#define VAL_GPIOC_MODER         (PIN_MODE_INPUT(GPIOC_CHARGE_STAT1A) | \
-                                 PIN_MODE_INPUT(GPIOC_GAUGE_BATLOW1) | \
-                                 PIN_MODE_INPUT(GPIOC_GAUGE_BATGD1_N) | \
-                                 PIN_MODE_OUTPUT(GPIOC_CHARGE_EN1_N) | \
-                                 PIN_MODE_INPUT(GPIOC_IR_INT2_N) | \
-                                 PIN_MODE_INPUT(GPIOC_TOUCH_INT_N) | \
-                                 PIN_MODE_INPUT(GPIOC_SYS_DONE) | \
-                                 PIN_MODE_OUTPUT(GPIOC_SYS_PROG_N) | \
-                                 PIN_MODE_INPUT(GPIOC_PATH_DC) | \
-                                 PIN_MODE_OUTPUT(GPIOC_SYS_SPI_DIR) | \
-                                 PIN_MODE_ALTERNATE(GPIOC_BT_RX) | \
-                                 PIN_MODE_ALTERNATE(GPIOC_BT_TX) | \
-                                 PIN_MODE_OUTPUT(GPIOC_SYS_INT_N) | \
-                                 PIN_MODE_OUTPUT(GPIOC_SYS_PD_N) | \
-                                 PIN_MODE_OUTPUT(GPIOC_SYS_WARMRST_N) | \
-                                 PIN_MODE_OUTPUT(GPIOC_BT_RST))
-#define VAL_GPIOC_OTYPER        (PIN_OTYPE_OPENDRAIN(GPIOC_CHARGE_EN1_N) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOC_SYS_PROG_N) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOC_SYS_SPI_DIR) | \
-                                 PIN_OTYPE_PUSHPULL(GPIOC_BT_RX) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOC_SYS_INT_N) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOC_SYS_PD_N) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOC_SYS_WARMRST_N) | \
-                                 PIN_OTYPE_OPENDRAIN(GPIOC_BT_RST))
-#define VAL_GPIOC_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOC_PUPDR         0x00000000
-#define VAL_GPIOC_ODR           0xEEFF /* emulate open drain for PATH_DC. This is required to prevent accidental shortcuts. Furthermore, pull down SYS_INT_N to indicate the OS is starting */
-#define VAL_GPIOC_AFRL          0x00000000
-#define VAL_GPIOC_AFRH          (PIN_AFIO_AF(GPIOC_BT_RX, 7) | \
-                                 PIN_AFIO_AF(GPIOC_BT_TX, 7))
-
-/*
- * Port D setup.
- */
-#define VAL_GPIOD_MODER         (PIN_MODE_INPUT(0) | \
-                                 PIN_MODE_INPUT(1) | \
-                                 PIN_MODE_OUTPUT(GPIOD_CHARGE_EN2_N) | \
-                                 PIN_MODE_INPUT(3) | \
-                                 PIN_MODE_INPUT(4) | \
-                                 PIN_MODE_INPUT(5) | \
-                                 PIN_MODE_INPUT(6) | \
-                                 PIN_MODE_INPUT(7) | \
-                                 PIN_MODE_INPUT(8) | \
-                                 PIN_MODE_INPUT(9) | \
-                                 PIN_MODE_INPUT(10) | \
-                                 PIN_MODE_INPUT(11) | \
-                                 PIN_MODE_INPUT(12) | \
-                                 PIN_MODE_INPUT(13) | \
-                                 PIN_MODE_INPUT(14) | \
-                                 PIN_MODE_INPUT(15))
-#define VAL_GPIOD_OTYPER        (PIN_OTYPE_OPENDRAIN(GPIOD_CHARGE_EN2_N))
-#define VAL_GPIOD_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOD_PUPDR         (PIN_PUDR_PULLUP(0) | \
-                                 PIN_PUDR_PULLUP(1) | \
-                                 PIN_PUDR_FLOATING(GPIOD_CHARGE_EN2_N) | \
-                                 PIN_PUDR_PULLUP(3) | \
-                                 PIN_PUDR_PULLUP(4) | \
-                                 PIN_PUDR_PULLUP(5) | \
-                                 PIN_PUDR_PULLUP(6) | \
-                                 PIN_PUDR_PULLUP(7) | \
-                                 PIN_PUDR_PULLUP(8) | \
-                                 PIN_PUDR_PULLUP(9) | \
-                                 PIN_PUDR_PULLUP(10) | \
-                                 PIN_PUDR_PULLUP(11) | \
-                                 PIN_PUDR_PULLUP(12) | \
-                                 PIN_PUDR_PULLUP(13) | \
-                                 PIN_PUDR_PULLUP(14) | \
-                                 PIN_PUDR_PULLUP(15))
-#define VAL_GPIOD_ODR           0x0FFF
-#define VAL_GPIOD_AFRL          0x00000000
-#define VAL_GPIOD_AFRH          0x00000000
-
-/*
- * Port E setup.
- */
-#define VAL_GPIOE_MODER         0x00000000
-#define VAL_GPIOE_OTYPER        0x00000000
-#define VAL_GPIOE_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOE_PUPDR         0xFFFFFFFF
-#define VAL_GPIOE_ODR           0xFFFF
-#define VAL_GPIOE_AFRL          0x00000000
-#define VAL_GPIOE_AFRH          0x00000000
-
-/*
- * Port F setup.
- * All input with pull-up.
- */
-#define VAL_GPIOF_MODER         0x00000000
-#define VAL_GPIOF_OTYPER        0x00000000
-#define VAL_GPIOF_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOF_PUPDR         0xFFFFFFFF
-#define VAL_GPIOF_ODR           0xFFFF
-#define VAL_GPIOF_AFRL          0x00000000
-#define VAL_GPIOF_AFRH          0x00000000
-
-/*
- * Port G setup.
- * All input with pull-up.
- */
-#define VAL_GPIOG_MODER         0x00000000
-#define VAL_GPIOG_OTYPER        0x00000000
-#define VAL_GPIOG_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOG_PUPDR         0xFFFFFFFF
-#define VAL_GPIOG_ODR           0xFFFF
-#define VAL_GPIOG_AFRL          0x00000000
-#define VAL_GPIOG_AFRH          0x00000000
-
-/*
- * Port H setup.
- */
-#define VAL_GPIOH_MODER         (PIN_MODE_INPUT(GPIOH_OSC_IN) | \
-                                 PIN_MODE_INPUT(GPIOH_OSC_OUT) | \
-                                 PIN_MODE_INPUT(2) | \
-                                 PIN_MODE_INPUT(3) | \
-                                 PIN_MODE_INPUT(4) | \
-                                 PIN_MODE_INPUT(5) | \
-                                 PIN_MODE_INPUT(6) | \
-                                 PIN_MODE_INPUT(7) | \
-                                 PIN_MODE_INPUT(8) | \
-                                 PIN_MODE_INPUT(9) | \
-                                 PIN_MODE_INPUT(10) | \
-                                 PIN_MODE_INPUT(11) | \
-                                 PIN_MODE_INPUT(12) | \
-                                 PIN_MODE_INPUT(13) | \
-                                 PIN_MODE_INPUT(14) | \
-                                 PIN_MODE_INPUT(15))
-#define VAL_GPIOH_OTYPER        0x00000000
-#define VAL_GPIOH_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOH_PUPDR         (PIN_PUDR_FLOATING(GPIOH_OSC_IN) | \
-                                 PIN_PUDR_FLOATING(GPIOH_OSC_OUT) | \
-                                 PIN_PUDR_PULLUP(2) | \
-                                 PIN_PUDR_PULLUP(3) | \
-                                 PIN_PUDR_PULLUP(4) | \
-                                 PIN_PUDR_PULLUP(5) | \
-                                 PIN_PUDR_PULLUP(6) | \
-                                 PIN_PUDR_PULLUP(7) | \
-                                 PIN_PUDR_PULLUP(8) | \
-                                 PIN_PUDR_PULLUP(9) | \
-                                 PIN_PUDR_PULLUP(10) | \
-                                 PIN_PUDR_PULLUP(11) | \
-                                 PIN_PUDR_PULLUP(12) | \
-                                 PIN_PUDR_PULLUP(13) | \
-                                 PIN_PUDR_PULLUP(14) | \
-                                 PIN_PUDR_PULLUP(15))
-#define VAL_GPIOH_ODR           0xFFFF
-#define VAL_GPIOH_AFRL          0x00000000
-#define VAL_GPIOH_AFRH          0x00000000
-
-/*
- * Port I setup.
- * All input with pull-up.
- */
-#define VAL_GPIOI_MODER         0x00000000
-#define VAL_GPIOI_OTYPER        0x00000000
-#define VAL_GPIOI_OSPEEDR       0xFFFFFFFF
-#define VAL_GPIOI_PUPDR         0xFFFFFFFF
-#define VAL_GPIOI_ODR           0xFFFF
-#define VAL_GPIOI_AFRL          0x00000000
-#define VAL_GPIOI_AFRH          0x00000000
-
-#if !defined(_FROM_ASM_)
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void boardInit(void);
-  void boardWriteIoPower(int value);
-  void boardWriteLed(int value);
-  void boardWriteSystemPower(int value);
-  void boardWriteWarmRestart(const uint8_t value);
-  void boardChargerSetState(uint8_t chrg_mask, uint8_t state);
-  void boardBluetoothSetState(uint8_t state);
-  void boardRequestShutdown(void);
-  void boardStandby(void);
-  void boardStop(const uint8_t lpds, const uint8_t fpds);
-  void boardWakeup(void);
-  void boardClearI2CBus(const uint8_t scl_pad, const uint8_t sda_pad);
-  void boardResetBQ27500I2C(const uint8_t scl_pad, const uint8_t sda_pad);
-#ifdef __cplusplus
-}
-#endif
-#endif /* _FROM_ASM_ */
-
-#endif /* _BOARD_H_ */
diff --git a/boards/PowerManagement/board.mk b/boards/PowerManagement/board.mk
deleted file mode 100644
index 6988c4f..0000000
--- a/boards/PowerManagement/board.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# List of all the board related files.
-BOARDSRC = ${AMIRO}/boards/PowerManagement/board.c \
-           ${AMIRO}/boards/PowerManagement/wakeup.c
-
-# Required include directories
-BOARDINC = ${AMIRO}/boards/PowerManagement
-
-# Required linker directory
-BOARDLD = ${AMIRO}/ports
-
diff --git a/boards/PowerManagement/wakeup.c b/boards/PowerManagement/wakeup.c
deleted file mode 100644
index 35d537a..0000000
--- a/boards/PowerManagement/wakeup.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include <ch.h>
-#include <hal.h>
-
-#include <board.h>
-#include "wakeup.h"
-
-enum wakeup_mode   wakeup_mode;
-enum wakeup_source wakeup_source;
-
-void standby_wakeup_source(void) {
-
-  uint32_t csr = PWR->CSR;
-  uint32_t gpioc_val = palReadPort(GPIOC);
-
-  // default to POR
-  wakeup_mode = WAKE_MODE_POR;
-  wakeup_source = WAKE_SRC_UNKN;
-
-  // make sure reset while powered on looks like POR
-  PWR->CR |= (PWR_CR_CSBF);
-
-  if ((csr & (PWR_CSR_SBF | PWR_CSR_WUF)) == (PWR_CSR_SBF | PWR_CSR_WUF)) {
-
-    // wakeup or RTC event from standby mode
-    // default to WKUP
-    wakeup_mode = WAKE_MODE_STDBY;
-    wakeup_source = WAKE_SRC_WKUP;
-
-    if (gpioc_val & (1u << GPIOC_PATH_DC))
-      wakeup_source |= WAKE_SRC_PATHDC_CONNECT;
-
-    if (!(gpioc_val & (1u << GPIOC_TOUCH_INT_N)))
-      wakeup_source |= WAKE_SRC_TOUCH_INT;
-
-    /*
-     * default to SYS_PD_N source when
-     * no other reason for wakeup was found.
-     */
-    if (wakeup_source == WAKE_SRC_WKUP)
-      wakeup_source |= WAKE_SRC_SYS_PD_N;
-
-  }
-
-}
-
-void stop_wakeup_source(void) {
-
-  wakeup_mode = WAKE_MODE_STOP;
-  wakeup_source = WAKE_SRC_UNKN;
-
-}
diff --git a/boards/PowerManagement/wakeup.h b/boards/PowerManagement/wakeup.h
deleted file mode 100644
index d9778ae..0000000
--- a/boards/PowerManagement/wakeup.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef WAKEUP_H_
-#define WAKEUP_H_
-
-enum wakeup_mode {
-
-  /**
-   * Wakeup POR.
-   */
-  WAKE_MODE_POR,
-  /**
-   * Wakeup from stop mode.
-   */
-  WAKE_MODE_STOP,
-  /**
-   * Wakeup from standby mode.
-   */
-  WAKE_MODE_STDBY,
-
-};
-
-enum wakeup_source {
-
-  /**
-   * Wakeup source unknown.
-   */
-  WAKE_SRC_UNKN                 = 0x00000000u,
-  /**
-   * Wakeup source wakeup pin.
-   */
-  WAKE_SRC_WKUP                 = 0x00000001u,
-  /**
-   * Wakeup source DC jack connected.
-   */
-  WAKE_SRC_PATHDC_CONNECT       = 0x00000002u,
-  /**
-   * Wakeup source DC jack disconnected.
-   */
-  WAKE_SRC_PATHDC_DISCONNECT    = 0x00000004u,
-  /**
-   * Wakeup source touch button interrupt.
-   */
-  WAKE_SRC_TOUCH_INT            = 0x00000008u,
-  /**
-   * Wakeup source other board.
-   */
-  WAKE_SRC_SYS_PD_N             = 0x00000010u,
-  /**
-   * Wakeup source any RTC event.
-   */
-  WAKE_SRC_RTC                  = 0x00000060u,
-  /**
-   * Wakeup source RTC Tamper/Timestamp event.
-   */
-  WAKE_SRC_RTC_TAMPER_TIMESTAMP = 0x00000020u,
-  /**
-   * Wakeup source RTC Wakeup.
-   */
-  WAKE_SRC_RTC_WAKEUP           = 0x00000040u,
-
-};
-
-extern enum wakeup_mode   wakeup_mode;
-extern enum wakeup_source wakeup_source;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void standby_wakeup_source(void);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* WAKEUP_H_ */
diff --git a/bootloader/AMiRo-BLT b/bootloader/AMiRo-BLT
new file mode 160000
index 0000000..68bf121
--- /dev/null
+++ b/bootloader/AMiRo-BLT
@@ -0,0 +1 @@
+Subproject commit 68bf121199fb3d8fba8bde03299da0e89a8e2bc1
diff --git a/bootloader/bootloader.mk b/bootloader/bootloader.mk
new file mode 100644
index 0000000..0c89c58
--- /dev/null
+++ b/bootloader/bootloader.mk
@@ -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/>.        #
+#                                                                              #
+# 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).                              #
+################################################################################
+
+
+
+# the path to this makefile
+BOOTLOADER_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# the interface for the bootloader
+BOOTLOADERINC = $(BOOTLOADER_DIR)AMiRo-BLT/Target/Source/AMiRo
+
+include $(BOOTLOADER_DIR)AMiRo-BLT/Target/Modules/moduleids.mk
+
+# some flashing parameters
+ifeq ($(OS),Windows_NT)
+	FLASH_PORT ?= COM4
+else
+	FLASH_PORT ?= /dev/ttyUSB0
+endif
+FLASH_BAUDRATE ?= 115200
+
+# set the flashing tool, the command to call it, arguments, and file extensions
+ifneq ($(wildcard $(BOOTLOADER_DIR)AMiRo-BLT/Host/Source/SerialBoot/build/SerialBoot),)
+	# if AMiRo-BLT project is available, use SerialBoot
+	FLASHTOOL = SerialBoot
+	FLASHTOOL_CMD = $(BOOTLOADER_DIR)AMiRo-BLT/Host/Source/SerialBoot/build/SerialBoot
+	FLASHTOOL_EXT = srec
+	ifdef PROJECT
+		FLASHTOOL_ARGS = -d$(FLASH_PORT) -b$(FLASH_BAUDRATE) $(foreach module,$(FLASH_MODULES),-T$($(module)_ID_HEX) build/$(module).$(FLASHTOOL_EXT))
+	else
+		FLASHTOOL_ARGS = -d$(FLASH_PORT) -b$(FLASH_BAUDRATE) $(foreach module,$(FLASH_MODULES),-T$($(module)_ID_HEX) $(FLASH_DIR)$(module)/build/$(module).$(FLASHTOOL_EXT))
+	endif
+else
+	# the default tool to use is stm32flash
+	ifneq ($(words $(FLASH_MODULES)),1)
+		FLASH_MODULES := $(firstword $(FLASH_MODULES))
+	endif
+	FLASHTOOL = stm32flash
+	FLASHTOOL_CMD = stm32flash
+	FLASHTOOL_EXT = hex
+	ifdef PROJECT
+		FLASHTOOL_ARGS = $(FLASH_PORT) -i "rts,-dtr,-rts":"rts,dtr,-rts" -R -b $(FLASH_BAUDRATE) -w build/$(FLASH_MODULES).$(FLASHTOOL_EXT)
+	else
+		FLASHTOOL_ARGS = $(FLASH_PORT) -i "rts,-dtr,-rts":"rts,dtr,-rts" -R -b $(FLASH_BAUDRATE) -w $(FLASH_MODULES)/build/$(FLASH_MODULES).$(FLASHTOOL_EXT)
+	endif
+endif
+
diff --git a/bootloader/bootloadersetup.sh b/bootloader/bootloadersetup.sh
new file mode 100755
index 0000000..d47a5a3
--- /dev/null
+++ b/bootloader/bootloadersetup.sh
@@ -0,0 +1,602 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+################################################################################
+# GENERIC FUNCTIONS                                                            #
+################################################################################
+
+### print an error message #####################################################
+# Prints a error <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printError <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printError {
+  local string="ERROR:   $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a warning message ####################################################
+# Prints a warning <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printMessage <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printWarning {
+  local string="WARNING: $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)"
+}
+
+### print an information message ###############################################
+# Prints an information <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printInfo <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printInfo {
+  local string="INFO:    $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)"
+}
+
+### print a message to file ####################################################
+# Appends a <message> to a log file, specified by the variable 'LOG_FILE'.
+#
+# usage       printLog <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printLog {
+  local string="LOG:     $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+}
+
+### exit the script normally ###################################################
+# Prints a delimiter and exits the script normally (returns 0).
+#
+# usage:      quitScript
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
+  exit 0
+}
+
+### read a user input ##########################################################
+# Reads a single character user input from a set up <options> and stores it in
+# a given <return> variable.
+#
+# usage:      readUserInput <options> <return>
+# arguments:  <options>
+#                 String definiing the set of valid characters.
+#                 If the string is empty, the user can input any character.
+#             <return>
+#                 Variable to store the selected character to.
+# return:     n/a
+#
+function readUserInput {
+  local input=""
+  # read user input
+  while [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); do
+    read -p "your selection: " -n 1 -e input
+    if [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); then
+      printWarning "[$input] is no valid action\n"
+    fi
+  done
+  printLog "[$input] has been selected\n"
+  eval $2="$input"
+}
+
+### check whether argument is an option ########################################
+# Checks a <string> whether it is an option.
+# Options are defined to either start with '--' followed by any string, or
+# to start with a single '-' followed by a single character, or
+# to start with a single '-' followed by a single character, a '=' and any string.
+# Examples: '--option', '--option=arg', '-o', '-o=arg', '--'
+#
+# usage:      parseIsOption <string>
+# arguments:  <string>
+#                 A string to check whether it is an option.
+# return:     0
+#                 <string> is an option.
+#             -1
+#                 <string> is not an option.
+#
+function parseIsOption {
+  if [[ "$1" =~ ^-(.$|.=.*) ]] || [[ "$1" =~ ^--.* ]]; then
+    return 0
+  else
+    return -1
+  fi
+}
+
+### set the log file ###########################################################
+# Sets a specified <infile> as log file and checks whether it already exists.
+# If so, the log may either be appended to the file, its content can be cleared,
+# or no log is generated at all.
+# The resulting path is stored in <outvar>.
+#
+# usage:      setLogFile [--option=<option>] [--quiet] <infile> <outvar>
+# arguments:  --option=<option>
+#                 Select what to do if <file> already exists.
+#                 Possible values are 'a', 'c', 'r' and 'n'.
+#                 - a: append (starts with a separator)
+#                 - c: continue (does not insert a seperator)
+#                 - r: delete and restart
+#                 - n: no log
+#                 If no option is secified but <file> exists, an interactive selection is provided.
+#             --quiet
+#                 Suppress all messages.
+#             <infile>
+#                 Path of the wanted log file.
+#             <outvar>
+#                 Variable to store the path of the log file to.
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: invalid input
+#
+function setLogFile {
+  local filepath=""
+  local option=""
+  local quiet=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -o=*|--option=*)
+          option=${1#*=}; shift 1;;
+        -o*|--option*)
+          option="$2"; shift 2;;
+        -q|--quiet)
+          quiet=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+  filepath=$(realpath ${otherargs[0]})
+
+  # if file already exists
+  if [ -e $filepath ]; then
+    # if no option was specified, ask what to do
+    if [ -z "$option" ]; then
+      printWarning "log file $filepath already esists\n"
+      local userinput=""
+      printf "Select what to do:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput "AaRrNn" userinput
+      option=${userinput,,}
+    fi
+    # evaluate option
+    case "$option" in
+      a|c)
+        if [ $quiet = false ]; then
+          printInfo "appending log to $filepath\n"
+        fi
+        if [ $option != c ]; then
+          printf "\n" >> $filepath
+          printf "######################################################################\n" >> $filepath
+          printf "\n" >> $filepath
+        fi
+        ;;
+      r)
+        echo -n "" > $filepath
+        if [ $quiet = false ]; then
+          printInfo "content of $filepath wiped\n"
+        fi
+        ;;
+      n)
+        if [ $quiet = false ]; then
+          printInfo "no log file will be generated\n"
+        fi
+        filepath=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $option\n"; return -1;;
+    esac
+  else
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
+  fi
+
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
+}
+
+################################################################################
+# SPECIFIC FUNCTIONS                                                           #
+################################################################################
+
+### print welcome text #########################################################
+# Prints a welcome message to standard out.
+#
+# usage:      printWelcomeText
+# arguments:  n/a
+# return:     n/a
+#
+function printWelcomeText {
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "#             Welcome to the AMiRo-BLT submodule setup!              #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+  printf "#                                                                    #\n"
+  printf "# This is free software; see the source for copying conditions.      #\n"
+  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+  printf "# Excellence Initiative.                                             #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+}
+
+### print help #################################################################
+# Prints a help text to standard out.
+#
+# usage:      printHelp
+# arguments:  n/a
+# return:     n/a
+#
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-i|--init] [-s|--setup] [-w|--wipe] [-q|--quit] [--log=<file>]\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -i, --init\n"
+  printf "              Initialize the AMiRo-BLT submodule.\n"
+  printf "          -s, --setup\n"
+  printf "              Enter AMiRo-BLT setup.\n"
+  printf "          -w, --wipe\n"
+  printf "              Wipe the entire AMiRo-BLT submodule.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file> \n"
+  printf "              Specify a log file.\n"
+}
+
+### initialize AMiRo-BLT submodule #############################################
+# Initialize the AMiRo-BLT submodule.
+#
+# usage:      initAmiroBlt
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Arborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function initAmiroBlt {
+  printInfo "initializing AMiRo-BLT submodule...\n"
+  local userdir=$(pwd)
+  local bootloaderdir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local amirobltdir=${bootloaderdir}/AMiRo-BLT
+
+  # if the AMiRo-BLT folder is not empty
+  if [ ! -z "$(ls -A $amirobltdir)" ]; then
+    printWarning "$(realpath $amirobltdir) is not empty. Delete and reinitialize? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case $userinput in
+      Y|y)
+        wipeAmiroBlt
+        ;;
+      N|n)
+        printWarning "AMiRo-BLT initialization aborted by user\n"
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  fi
+
+  # initialize submodule to default branch
+  cd $bootloaderdir
+  git submodule update --init $amirobltdir 2>&1 | tee -a $LOG_FILE
+  while [ ${PIPESTATUS[0]} -ne 0 ]; do
+    printWarning "initialitaion failed. Retry? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        git submodule update --init $amirobltdir 2>&1 | tee -a $LOG_FILE;;
+      N|n)
+        printWarning "AMiRo-BLT initialization aborted by user\n"
+        cd $userdir
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  done
+  cd $userdir
+
+  return 0
+}
+
+### enter AMiRo-BLT setup ######################################################
+# Enter AMiRo-BLT submodule setup.
+#
+# usage:      amiroBltSetup
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: AMiRo-BLT submodule not initialized yet.
+#
+function amiroBltSetup {
+  local amirobltdir=$(dirname $(realpath ${BASH_SOURCE[0]}))/AMiRo-BLT
+
+  # check if AMiRo-BLT submodule is initialized
+  if [ -z "$(ls -A $amirobltdir)" ]; then
+    printError "$amirobltdir is empty. Please initialize first.\n"
+    return -1
+  else
+    printInfo "entering AMiRo-BLT setup\n"
+    printf "\n"
+    if [ -z "$LOG_FILE" ]; then
+      ${amirobltdir}/setup.sh --noinfo
+    else
+      ${amirobltdir}/setup.sh --LOG="$LOG_FILE" --noinfo
+    fi
+    return 0
+  fi
+}
+
+### reset AMiRo-BLT submodule and wipe directory ###############################
+# Resets the AMiRo-BLT Git submodule and wipes the directory.
+#
+# usage:      wipeAmiroBlt
+# arguments:  n/a
+# return:     n/a
+function wipeAmiroBlt {
+  printInfo "reset and wipe Git submodule $amirobltdir\n"
+  local userdir=$(pwd)
+  local bootloaderdir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local amirobltdir=${bootloaderdir}/AMiRo-BLT
+
+  # if the AMiRo-BLT folder is empty
+  if [ -z "$(ls -A $amirobltdir)" ]; then
+    printWarning "$amirobltdir is already empty\n"
+    return 1
+  else
+    # get some information from Git
+    cd $bootloaderdir
+    local git_basehash=($(git ls-tree -d HEAD $amirobltdir)); git_basehash=${git_basehash[2]}
+    cd $amirobltdir
+    local git_branch_current=$(git rev-parse --abbrev-ref HEAD)
+    local git_difftobase="$(git diff ${git_basehash}..HEAD)"
+    local git_commits=$(git log --format=oneline ${git_basehash}..HEAD)
+    local git_dirtyfiles=($(git ls-files -dmo --exclude-standard --exclude=/doc))
+    cd $userdir
+    local issues=0
+    # if HEAD is ahead of submodule base commit
+    if [ -n "$git_difftobase" ]; then
+      issues=$((issues + 1))
+      printWarning "HEAD is ahead of submodule base\n"
+    fi
+    # if there are untracked, modified, or deleted files
+    if [ ${#git_dirtyfiles[@]} != 0 ]; then
+      issues=$((issues + 1))
+      printWarning "there are ${#git_dirtyfiles[@]} untracked, modified, or deleted files\n"
+    fi
+    if [ $issues -gt 0 ]; then
+      local userinput=""
+      printWarning "$issues issues detected. Do you want to continue? [y/n]\n"
+      readUserInput "YyNn" userinput
+      case "$userinput" in
+        Y|y)
+          ;;
+        N|n)
+          printfWarning "wiping AMiRo-BLT Git submodule aborted by user\n"
+          return 2
+          ;;
+        *) # sanity check (return error)
+          printError "unexpected input: $userinput\n"; return -1;;
+      esac
+    fi
+
+    # checkout base commit and delete all local branches
+    cd $bootloaderdir
+    git submodule update --force --checkout $amirobltdir | tee -a $LOG_FILE
+    cd $amirobltdir
+    local git_branches=($(git for-each-ref --format="%(refname)"))
+    for branch in $git_branches; do
+      if [[ $branch = *"heads/"* ]]; then
+        git branch -D ${branch##*/} | tee -a $LOG_FILE
+      fi
+    done
+    cd $userdir
+
+    # deinitialize AMiRo-BLT submodule and delete any remaining files
+    cd $bootloaderdir
+    git submodule deinit -f $amirobltdir 2>&1 | tee -a $LOG_FILE
+    rm -rf $amirobltdir/*
+    cd $userdir
+
+    return 0
+  fi
+}
+
+### main function of this script ###############################################
+# Initializes or wipes the AMiRo-BLT Git submodule, and provides an entry point
+# to its setup.
+#
+# usage:      see function printHelp
+# arguments:  see function printHelp
+# return:     0
+#                 No error or warning occurred.
+#
+function main {
+  # print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  printf "\n"
+
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
+
+  # set log file if specified
+  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
+    # get the parameter (file name)
+    local cmdidx=1
+    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
+      cmdidx=$[cmdidx + 1]
+    done
+    local cmd="${!cmdidx}"
+    local logfile=""
+    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
+      logfile=${cmd#*=}
+    else
+      local filenameidx=$((cmdidx + 1))
+      logfile="${!filenameidx}"
+    fi
+    # optionally force silent appending
+    if [[ "$cmd" = "--LOG"* ]]; then
+      setLogFile --option=c --quiet "$logfile" LOG_FILE
+    else
+      setLogFile "$logfile" LOG_FILE
+      printf "\n"
+    fi
+  fi
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -i|--init)
+           initAmiroBlt; printf "\n"; shift 1;;
+        -s|--setup)
+           amiroBltSetup; printf "\n"; shift 1;;
+        -w|--wipe)
+           wipeAmiroBlt; printf "\n"; shift 1;;
+        -q|--quit)
+          quitScript; shift 1;;
+        --log=*|--LOG=*) # already handled; ignore
+          shift 1;;
+        --log|--LOG) # already handled; ignore
+          shift 2;;
+        --noinfo) # already handled; ignore
+          shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "Bootloader setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [I] - initialize AMiRo-BLT submodule\n"
+    printf "  [S] - enter AMiRo-BLT setup\n"
+    printf "  [W] - wipe AMiRo-BLT submodule\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "IiSsWwQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      I|i)
+        initAmiroBlt; printf "\n";;
+      S|s)
+        amiroBltSetup; printf "\n";;
+      W|w)
+        wipeAmiroBlt; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
+
diff --git a/components/Color.cpp b/components/Color.cpp
deleted file mode 100644
index 4723da7..0000000
--- a/components/Color.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/Color.h>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-Color::Color()
-    : red(0),
-      green(0),
-      blue(0) {
-}
-
-Color::Color(const Color& color)
-    : red(color.red),
-      green(color.green),
-      blue(color.blue) {
-}
-
-Color::Color(int r, int g, int b)
-    : red(r),
-      green(g),
-      blue(b) {
-}
-
-Color::Color(GlobalColor color) {
-  static const struct {
-    unsigned char red;
-    unsigned char green;
-    unsigned char blue;
-  } global_colors[] = {
-      { 240, 248, 255 },
-      { 250, 235, 215 },
-      { 0, 255, 255 },
-      { 127, 255, 212 },
-      { 240, 255, 255 },
-      { 245, 245, 220 },
-      { 255, 228, 196 },
-      { 0, 0, 0 },
-      { 255, 235, 205 },
-      { 0, 0, 255 },
-      { 138, 43, 226 },
-      { 165, 42, 42 },
-      { 222, 184, 135 },
-      { 95, 158, 160 },
-      { 127, 255, 0 },
-      { 210, 105, 30 },
-      { 255, 127, 80 },
-      { 100, 149, 237 },
-      { 255, 248, 220 },
-      { 220, 20, 60 },
-      { 0, 255, 255 },
-      { 0, 0, 139 },
-      { 0, 139, 139 },
-      { 184, 134, 11 },
-      { 169, 169, 169 },
-      { 0, 100, 0 },
-      { 169, 169, 169 },
-      { 189, 183, 107 },
-      { 139, 0, 139 },
-      { 85, 107, 47 },
-      { 255, 140, 0 },
-      { 153, 50, 204 },
-      { 139, 0, 0 },
-      { 233, 150, 122 },
-      { 143, 188, 143 },
-      { 72, 61, 139 },
-      { 47, 79, 79 },
-      { 47, 79, 79 },
-      { 0, 206, 209 },
-      { 148, 0, 211 },
-      { 255, 20, 147 },
-      { 0, 191, 255 },
-      { 105, 105, 105 },
-      { 105, 105, 105 },
-      { 30, 144, 255 },
-      { 178, 34, 34 },
-      { 255, 250, 240 },
-      { 34, 139, 34 },
-      { 255, 0, 255 },
-      { 220, 220, 220 },
-      { 248, 248, 255 },
-      { 255, 215, 0 },
-      { 218, 165, 32 },
-      { 128, 128, 128 },
-      { 128, 128, 128 },
-      { 0, 128, 0 },
-      { 173, 255, 47 },
-      { 240, 255, 240 },
-      { 255, 105, 180 },
-      { 205, 92, 92 },
-      { 75, 0, 130 },
-      { 255, 255, 240 },
-      { 240, 230, 140 },
-      { 230, 230, 250 },
-      { 255, 240, 245 },
-      { 124, 252, 0 },
-      { 255, 250, 205 },
-      { 173, 216, 230 },
-      { 240, 128, 128 },
-      { 224, 255, 255 },
-      { 250, 250, 210 },
-      { 211, 211, 211 },
-      { 144, 238, 144 },
-      { 211, 211, 211 },
-      { 255, 182, 193 },
-      { 255, 160, 122 },
-      { 32, 178, 170 },
-      { 135, 206, 250 },
-      { 119, 136, 153 },
-      { 119, 136, 153 },
-      { 176, 196, 222 },
-      { 255, 255, 224 },
-      { 0, 255, 0 },
-      { 50, 205, 50 },
-      { 250, 240, 230 },
-      { 255, 0, 255 },
-      { 128, 0, 0 },
-      { 102, 205, 170 },
-      { 0, 0, 205 },
-      { 186, 85, 211 },
-      { 147, 112, 219 },
-      { 60, 179, 113 },
-      { 123, 104, 238 },
-      { 0, 250, 154 },
-      { 72, 209, 204 },
-      { 199, 21, 133 },
-      { 25, 25, 112 },
-      { 245, 255, 250 },
-      { 255, 228, 225 },
-      { 255, 228, 181 },
-      { 255, 222, 173 },
-      { 0, 0, 128 },
-      { 253, 245, 230 },
-      { 128, 128, 0 },
-      { 107, 142, 35 },
-      { 255, 165, 0 },
-      { 255, 69, 0 },
-      { 218, 112, 214 },
-      { 238, 232, 170 },
-      { 152, 251, 152 },
-      { 175, 238, 238 },
-      { 219, 112, 147 },
-      { 255, 239, 213 },
-      { 255, 218, 185 },
-      { 205, 133, 63 },
-      { 255, 192, 203 },
-      { 221, 160, 221 },
-      { 176, 224, 230 },
-      { 128, 0, 128 },
-      { 255, 0, 0 },
-      { 188, 143, 143 },
-      { 65, 105, 225 },
-      { 139, 69, 19 },
-      { 250, 128, 114 },
-      { 244, 164, 96 },
-      { 46, 139, 87 },
-      { 255, 245, 238 },
-      { 160, 82, 45 },
-      { 192, 192, 192 },
-      { 135, 206, 235 },
-      { 106, 90, 205 },
-      { 112, 128, 144 },
-      { 112, 128, 144 },
-      { 255, 250, 250 },
-      { 0, 255, 127 },
-      { 70, 130, 180 },
-      { 210, 180, 140 },
-      { 0, 128, 128 },
-      { 216, 191, 216 },
-      { 255, 99, 71 },
-      { 64, 224, 208 },
-      { 238, 130, 238 },
-      { 245, 222, 179 },
-      { 255, 255, 255 },
-      { 245, 245, 245 },
-      { 255, 255, 0 },
-      { 154, 205, 50 }, };
-  this->setRedGreenBlue(global_colors[color].red, global_colors[color].green,
-                        global_colors[color].blue);
-}
-
-Color Color::darker(int factor) {
-  if (factor <= 0)
-    return *this;
-  else if (factor < 100)
-    return this->lighter(10000 / factor);
-
-  int red = 100 * this->red / factor;
-  int green = 100 * this->green / factor;
-  int blue = 100 * this->blue / factor;
-
-  return Color(red, green, blue);
-}
-
-void Color::getRedGreenBlue(int* r, int* g, int* b) {
-  *r = this->red;
-  *g = this->green;
-  *b = this->blue;
-}
-
-int Color::getRed() {
-  return this->red;
-}
-
-int Color::getGreen() {
-  return this->green;
-}
-
-int Color::getBlue() {
-  return this->blue;
-}
-
-Color Color::lighter(int factor) {
-  if (factor <= 0)
-    return *this;
-  else if (factor < 100)
-    return this->darker(10000 / factor);
-
-  int red = factor * this->red / 100;
-  int green = factor * this->green / 100;
-  int blue = factor * this->blue / 100;
-
-  red = (red < 0) ? 0 : (red > 255) ? 255 : red;
-  green = (green < 0) ? 0 : (green > 255) ? 255 : green;
-  blue = (blue < 0) ? 0 : (blue > 255) ? 255 : blue;
-
-  return Color(red, green, blue);
-}
-
-void Color::setRedGreenBlue(int red, int green, int blue) {
-  this->red = red;
-  this->green = green;
-  this->blue = blue;
-}
-
-Color& Color::operator=(Color const& color) {
-  if (this != &color) {
-    this->red = color.red;
-    this->green = color.green;
-    this->blue = color.blue;
-  }
-  return *this;
-}
-
-Color& Color::operator=(GlobalColor color) {
-  return operator=(Color(color));
-}
diff --git a/components/ControllerAreaNetworkRx.cpp b/components/ControllerAreaNetworkRx.cpp
deleted file mode 100644
index 30fbe1e..0000000
--- a/components/ControllerAreaNetworkRx.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-#include <string.h>  // memcpy
-
-#include <amiro/Constants.h>
-#include <amiro/ControllerAreaNetworkRx.h>
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-extern Global global;
-
-using namespace types;
-using namespace amiro::constants;
-
-ControllerAreaNetworkRx::ControllerAreaNetworkRx(CANDriver *can, const uint8_t boardId)
-    : BaseStaticThread<128>(),
-      boardId(boardId),
-      canDriver(can) {
-#ifdef STM32F4XX
-  this->canConfig.mcr = CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP;
-  this->canConfig.btr = CAN_BTR_SJW(1) | CAN_BTR_TS2(3) | CAN_BTR_TS1(15)
-                        | CAN_BTR_BRP(1);
-#else
-  this->canConfig.mcr = CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP;
-  this->canConfig.btr = CAN_BTR_SJW(1) | CAN_BTR_TS2(2) | CAN_BTR_TS1(13)
-                        | CAN_BTR_BRP(1);
-#endif
-}
-
-ControllerAreaNetworkRx::
-~ControllerAreaNetworkRx() {
-
-}
-
-//----------------------------------------------------------------
-
-msg_t ControllerAreaNetworkRx::receiveSensorVal(CANRxFrame *frame) {
-  int deviceId = this->decodeDeviceId(frame);
-
-  // chprintf((BaseSequentialStream*) &global.sercanmux1, "DeviceId: %d\r\n",deviceId);
-
-  switch (deviceId) {
-    case CAN::PROXIMITY_RING_ID(0):
-    case CAN::PROXIMITY_RING_ID(1):
-    case CAN::PROXIMITY_RING_ID(2):
-    case CAN::PROXIMITY_RING_ID(3):
-    case CAN::PROXIMITY_RING_ID(4):
-    case CAN::PROXIMITY_RING_ID(5):
-    case CAN::PROXIMITY_RING_ID(6):
-    case CAN::PROXIMITY_RING_ID(7):
-      if (frame->DLC == 2) {
-        int index = deviceId & 0x7;
-        proximityRingValue[index] = frame->data16[0];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::ACTUAL_SPEED_ID:
-      if (frame->DLC == 8) {
-        actualSpeed[0] = frame->data32[0];
-        actualSpeed[1] = frame->data32[1];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::ODOMETRY_ID:
-      if (frame->DLC == 8) {
-        this->robotPosition.x = (frame->data8[0] << 8 | frame->data8[1] << 16 | frame->data8[2] << 24);
-        this->robotPosition.y = (frame->data8[3] << 8 | frame->data8[4] << 16 | frame->data8[5] << 24);
-        this->robotPosition.f_z = (frame->data8[6] << 8 | frame->data8[7] << 16);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::PROXIMITY_FLOOR_ID:
-      // chprintf((BaseSequentialStream*) &global.sercanmux1, "CAN::PROXIMITY_FLOOR_ID");
-      if (frame->DLC == 8) {
-        proximityFloorValue[0] = frame->data16[0];
-        proximityFloorValue[1] = frame->data16[1];
-        proximityFloorValue[2] = frame->data16[2];
-        proximityFloorValue[3] = frame->data16[3];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::POWER_STATUS_ID:
-      if (frame->DLC == 6) {
-        powerStatus.charging_flags.value = frame->data8[0];
-        powerStatus.state_of_charge = frame->data8[1];
-        powerStatus.minutes_remaining = frame->data16[1];
-        powerStatus.power_consumption = frame->data16[2];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::ROBOT_ID:
-      if (frame->DLC == 1) {
-        robotId = frame->data8[0];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::MAGNETOMETER_X_ID:
-      if (frame->DLC == 4) {
-        magnetometerValue[0] = frame->data32[0];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::MAGNETOMETER_Y_ID:
-      if (frame->DLC == 4) {
-        magnetometerValue[1] = frame->data32[0];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::MAGNETOMETER_Z_ID:
-      if (frame->DLC == 4) {
-        magnetometerValue[2] = frame->data32[0];
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::GYROSCOPE_ID:
-      if (frame->DLC == 6) {
-        gyroscopeValue[0] = frame->data16[0];
-        gyroscopeValue[1] = frame->data16[1];
-        gyroscopeValue[2] = frame->data16[2];
-        return RDY_OK;
-      }
-      break;
-
-    default:
-      break;
-  }
-
-  return RDY_RESET;
-}
-
-uint16_t ControllerAreaNetworkRx::getProximityRingValue(int index) {
-  return this->proximityRingValue[index];
-}
-
-void ControllerAreaNetworkRx::getActualSpeed(types::kinematic &targetSpeed) {
-  targetSpeed.x = this->actualSpeed[0];
-  targetSpeed.w_z = this->actualSpeed[1];
-}
-
-types::position ControllerAreaNetworkRx::getOdometry() {
-  return this->robotPosition;
-}
-
-power_status &ControllerAreaNetworkRx::getPowerStatus() {
-  return this->powerStatus;
-}
-
-uint8_t ControllerAreaNetworkRx::getRobotID() {
-  return this->robotId;
-}
-
-int32_t ControllerAreaNetworkRx::getMagnetometerValue(int axis)
-{
-  return this->magnetometerValue[axis];
-}
-
-int16_t ControllerAreaNetworkRx::getGyroscopeValue(int axis)
-{
-  return this->gyroscopeValue[axis];
-}
-
-
-uint16_t ControllerAreaNetworkRx::getProximityFloorValue(int index) {
-  return this->proximityFloorValue[index];
-}
-
-//----------------------------------------------------------------
-
-msg_t ControllerAreaNetworkRx::main(void) {
-
-  this->rxFullCanEvtSource = reinterpret_cast<EvtSource *>(&this->canDriver->rxfull_event);
-
-  this->rxFullCanEvtSource->registerOne(&this->rxFullCanEvtListener, CAN::RECEIVED_ID);
-
-  canStart(this->canDriver, &this->canConfig);
-
-  this->setName("ControllerAreaNetworkRx");
-
-  while (!this->shouldTerminate()) {
-    eventmask_t eventMask = this->waitOneEventTimeout(ALL_EVENTS, MS2ST(10000));
-    switch (eventMask) {
-
-      case EVENT_MASK(CAN::RECEIVED_ID):
-        CANRxFrame rxframe;
-        msg_t message = canReceive(this->canDriver, CAN_ANY_MAILBOX, &rxframe, TIME_IMMEDIATE);
-        if (message == RDY_OK) {
-          // chprintf((BaseSequentialStream*) &global.sercanmux1, "Rx Message");
-          message = this->receiveMessage(&rxframe);
-          if (message != RDY_OK)
-            this->receiveSensorVal(&rxframe);
-        }
-        break;
-    }
-  }
-
-  canStop(this->canDriver);
-  this->rxFullCanEvtSource->unregister(&this->rxFullCanEvtListener);
-
-  return RDY_OK;
-}
-
-msg_t ControllerAreaNetworkRx::receiveMessage(CANRxFrame *frame) {
-  (void)frame;
-  return RDY_OK;
-}
-
-//----------------------------------------------------------------
-
-int ControllerAreaNetworkRx::decodeBoardId(CANRxFrame *frame) {
-  return (frame->SID >> CAN::BOARD_ID_SHIFT) & CAN::BOARD_ID_MASK;
-}
-
-int ControllerAreaNetworkRx::decodeDeviceId(CANRxFrame *frame) {
-  return (frame->SID >> CAN::DEVICE_ID_SHIFT) & CAN::DEVICE_ID_MASK;
-}
-
-int ControllerAreaNetworkRx::decodeIndexId(CANRxFrame *frame) {
-  return (frame->SID >> CAN::INDEX_ID_SHIFT) & CAN::INDEX_ID_MASK;
-}
-
-//----------------------------------------------------------------
-
-int ControllerAreaNetworkRx::rxCmdShell(CANRxFrame *frame) {
-  return (frame->SID >> CAN::BOARD_ID_SHIFT) & CAN::BOARD_ID_MASK;
-}
diff --git a/components/ControllerAreaNetworkTx.cpp b/components/ControllerAreaNetworkTx.cpp
deleted file mode 100644
index 911cb89..0000000
--- a/components/ControllerAreaNetworkTx.cpp
+++ /dev/null
@@ -1,229 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-#include <string.h>  // memcpy
-
-#include <amiro/Constants.h>
-#include <amiro/ControllerAreaNetworkTx.h>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-using namespace types;
-using namespace amiro::constants;
-
-ControllerAreaNetworkTx::ControllerAreaNetworkTx(CANDriver *can, const uint8_t boardId)
-    : BaseStaticThread<128>(),
-      boardId(boardId),
-      canDriver(can)
-{
-#ifdef STM32F4XX
-  this->canConfig.mcr = CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP;
-  this->canConfig.btr = CAN_BTR_SJW(1) | CAN_BTR_TS2(3) | CAN_BTR_TS1(15)
-                        | CAN_BTR_BRP(1);
-#else
-  this->canConfig.mcr = CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP;
-  this->canConfig.btr = CAN_BTR_SJW(1) | CAN_BTR_TS2(2) | CAN_BTR_TS1(13)
-                        | CAN_BTR_BRP(1);
-#endif
-}
-
-ControllerAreaNetworkTx::
-~ControllerAreaNetworkTx() {
-
-}
-
-//----------------------------------------------------------------
-
-void ControllerAreaNetworkTx::setLightBrightness(int brightness) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::BRIGHTNESS_ID);
-  frame.data8[0] = brightness;
-  frame.DLC = 1;
-  this->transmitMessage(&frame);
-}
-
-void ControllerAreaNetworkTx::setLightColor(int index, Color color) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::COLOR_ID(index));
-  frame.data8[0] = color.getRed();
-  frame.data8[1] = color.getGreen();
-  frame.data8[2] = color.getBlue();
-  frame.DLC = 3;
-  this->transmitMessage(&frame);
-}
-
-void ControllerAreaNetworkTx::setOdometry(types::position robotPosition) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::SET_ODOMETRY_ID);
-  // Cut of the first byte, which precission is not needed
-  int32_t x_mm = (robotPosition.x >> 8);
-  int32_t y_mm = (robotPosition.y >> 8);
-  int16_t f_z_mrad = int16_t(robotPosition.f_z >> 8 );
-  // Copy the data structure
-  memcpy((uint8_t *)&(frame.data8[0]), (uint8_t *)&x_mm, 3);
-  memcpy((uint8_t *)&(frame.data8[3]), (uint8_t *)&y_mm, 3);
-  memcpy((uint8_t *)&(frame.data8[6]), (uint8_t *)&f_z_mrad, 2);
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-}
-
-//----------------------------------------------------------------
-
-void ControllerAreaNetworkTx::setTargetSpeed(int32_t leftURpm, int32_t rightURpm) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::TARGET_RPM_ID);
-  frame.data32[0] = leftURpm;
-  frame.data32[1] = rightURpm;
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-}
-
-void ControllerAreaNetworkTx::setTargetSpeed(kinematic &targetSpeed) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::TARGET_SPEED_ID);
-  frame.data32[0] = targetSpeed.x;
-  frame.data32[1] = targetSpeed.w_z;
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-}
-
-void ControllerAreaNetworkTx::setTargetPosition(types::position &targetPosition, uint32_t targetTime) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::TARGET_POSITION_ID);
-  frame.data32[0] = targetPosition.x;
-  frame.data32[1] = targetPosition.f_z;
-  frame.data32[1] = targetTime;
-  frame.DLC = 12;
-  this->transmitMessage(&frame);
-}
-
-void ControllerAreaNetworkTx::setKinematicConstants(float Ed, float Eb) {
-  CANTxFrame frame;
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::SET_KINEMATIC_CONST_ID);
-  frame.data32[0] = Ed;
-  frame.data32[1] = Eb;
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-}
-
-void ControllerAreaNetworkTx::broadcastShutdown() {
-    CANTxFrame frame;
-    frame.SID = 0x00u;
-    this->encodeDeviceId(&frame, CAN::BROADCAST_SHUTDOWN);
-    frame.data16[0] = CAN::SHUTDOWN_MAGIC;
-    frame.DLC = 2;
-    this->transmitMessage(&frame);
-
-}
-
-//----------------------------------------------------------------
-
-void ControllerAreaNetworkTx::txQueryShell(uint8_t toBoardId, char *textdata, uint16_t size) {
-    uint16_t cnt = size;
-    CANTxFrame frame;
-    frame.SID = 0;
-    frame.DLC = 8;
-    this->encodeDeviceId(&frame, CAN::SHELL_QUERY_ID(toBoardId));
-
-    while (cnt > 8) {
-        memcpy(frame.data8,&textdata[size-cnt],8) ;
-        this->transmitMessage(&frame);
-        cnt -= 8;
-    }
-    memcpy(frame.data8,&textdata[size-cnt],cnt) ;
-    frame.DLC = cnt;
-    this->transmitMessage(&frame);
-}
-
-
-void ControllerAreaNetworkTx::txReplyShell(uint8_t toBoardId, char *textdata, uint16_t size) {
-    uint16_t cnt = size;
-    CANTxFrame frame;
-    frame.SID = 0;
-    frame.DLC = 8;
-    this->encodeDeviceId(&frame, CAN::SHELL_REPLY_ID(toBoardId));
-
-    while (cnt > 8) {
-        memcpy(frame.data8,&textdata[size-cnt],8) ;
-        this->transmitMessage(&frame);
-        cnt -= 8;
-    }
-    memcpy(frame.data8,&textdata[size-cnt],cnt) ;
-    frame.DLC = cnt;
-    this->transmitMessage(&frame);
-}
-
-//----------------------------------------------------------------
-
-msg_t ControllerAreaNetworkTx::main(void) {
-  evtInit(&this->evtimer, CAN::UPDATE_PERIOD);
-
-  this->eventTimerEvtSource = reinterpret_cast<EvtSource *>(&this->evtimer.et_es);
-
-  this->eventTimerEvtSource->registerOne(&this->eventTimerEvtListener, CAN::PERIODIC_TIMER_ID);
-
-  evtStart(&this->evtimer);
-
-  this->setName("ControllerAreaNetworkTx");
-
-  while (!this->shouldTerminate()) {
-    eventmask_t eventMask = this->waitOneEvent(ALL_EVENTS);
-    switch (eventMask) {
-      case EVENT_MASK(CAN::PERIODIC_TIMER_ID):
-        updateSensorVal();
-        periodicBroadcast();
-        break;
-    }
-  }
-
-  evtStop(&this->evtimer);
-  this->eventTimerEvtSource->unregister(&this->eventTimerEvtListener);
-
-  return RDY_OK;
-}
-
-msg_t ControllerAreaNetworkTx::updateSensorVal() {
-  return RDY_OK;
-}
-
-//----------------------------------------------------------------
-
-void ControllerAreaNetworkTx::encodeBoardId(CANTxFrame *frame, int board) {
-  frame->SID |= (board & CAN::BOARD_ID_MASK) << CAN::BOARD_ID_SHIFT;
-}
-
-void ControllerAreaNetworkTx::encodeDeviceId(CANTxFrame *frame, int device) {
-  frame->SID |= (device & CAN::DEVICE_ID_MASK) << CAN::DEVICE_ID_SHIFT;
-}
-
-void ControllerAreaNetworkTx::encodeIndexId(CANTxFrame *frame, int index) {
-  frame->SID |= (index & CAN::INDEX_ID_MASK) << CAN::INDEX_ID_SHIFT;
-}
-
-//----------------------------------------------------------------
-
-void ControllerAreaNetworkTx::transmitMessage(CANTxFrame *frame) {
-  this->encodeBoardId(frame, boardId);
-  frame->IDE = CAN_IDE_STD;
-  frame->RTR = CAN_RTR_DATA;
-  /**
-   * We cannot use TIME_INFINITE here b/c
-   * lower boards might crash/power down etc.
-   * and block CAN bus (though they should not...).
-   * Then, we get stuck here and cannot terminate CAN thread
-   * Therefore:
-   *
-   * 1 us       * (  1 + 11 +   1 +   1 +   1 +   4 +   64 +  15 +     1 +   1 +     1 +   7) * 5        = 545 us
-   * 1/ (1 MHz) * (SOF + ID + RTR + IDE + RES + DLC + DATA + CRC + DELIM + ACK + DELIM + EOF) * #RETRIES
-   */
-
-  BaseThread::sleep(MS2ST(2));
-  canTransmit(this->canDriver, CAN_TX_MAILBOXES, frame, US2ST(545));
-}
diff --git a/components/Debug.c b/components/Debug.c
deleted file mode 100644
index b1bd957..0000000
--- a/components/Debug.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#include <ch.h>
-#include <hal.h>
-
-/*
- * System_halt
- * error code
- *
- *            - 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.
- */
-
-static inline void serialWaitForEmpty(void) {
-  while (!((SD1.usart->SR) & USART_SR_TC)) {
-    ;
-  }
-}
-
-void haltErrorCode(void) {
-#if CH_DBG_SYSTEM_STATE_CHECK
-  char errorCode[26]="\nSystem halt! Error Code:\0";
-  int i=0;
-  rccEnableUSART1(FALSE);
-  nvicEnableVector(USART1_IRQn,CORTEX_PRIORITY_MASK(STM32_SERIAL_USART1_PRIORITY));
-  SD1.state = SD_READY;
-
-  SD1.usart->CR1 = 0;
-  SD1.usart->CR2 = 0;
-  SD1.usart->CR3 = 0;
-
-  SD1.usart->CR1 |= USART_CR1_UE | USART_CR1_TE;
-  SD1.usart->CR2 |= USART_CR2_STOP;
-  SD1.usart->BRR = STM32_PCLK2 / 115200;
-
-  while(errorCode[i]!='\0') {
-    SD1.usart->DR = errorCode[i];
-    serialWaitForEmpty();
-    i++;
-  }
-  i=0;
-  while(dbg_panic_msg[i]!='\0') {
-    SD1.usart->DR = dbg_panic_msg[i];
-    serialWaitForEmpty();
-    i++;
-  }
-
-  SD1.usart->DR = '\n';
-  serialWaitForEmpty();
-#endif
-}
diff --git a/components/DistControl.cpp b/components/DistControl.cpp
deleted file mode 100644
index a416533..0000000
--- a/components/DistControl.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <qei.h>
-
-#include <amiro/DistControl.h>
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace types;
-using namespace constants;
-using namespace constants::DiWheelDrive;
-
-extern Global global;
-
-DistControl::DistControl(MotorControl* mc, MotorIncrements* mi)
-    : BaseStaticThread<256>(),
-      motorControl(mc),
-      motorIncrements(mi),
-      period(10)
-       {
-
-  // initialize velocities
-  this->maxVelocity.y = 0;
-  this->maxVelocity.z = 0;
-  this->maxVelocity.w_x = 0;
-  this->maxVelocity.w_y = 0;
-  this->targetVelocity.x = 0;
-  this->targetVelocity.y = 0;
-  this->targetVelocity.z = 0;
-  this->targetVelocity.w_x = 0;
-  this->targetVelocity.w_y = 0;
-  this->targetVelocity.w_z = 0;
-  this->minVelocity.y = 0;
-  this->minVelocity.z = 0;
-  this->minVelocity.w_x = 0;
-  this->minVelocity.w_y = 0;
-  this->minVelocity.w_z = 0;
-
-  // set max and min velocities
-  this->maxVelocity.x = 0.15 * 1e6; // 15 cm/s
-  this->minVelocity.x = 0.02 * 1e6; // 2 cm/s
-  this->maxVelocity.w_z = 2*maxVelocity.x / MotorControl::actualWheelBaseDistanceSI;
-  this->minVelocity.w_z = 2*minVelocity.x / MotorControl::actualWheelBaseDistanceSI;
-}
-
-int DistControl::getCurrentTargetDist() {
-  return (int)(targetDistance*1e6);
-}
-
-int DistControl::getCurrentTargetAngle() {
-  return (int)(targetAngle*1e6);
-}
-
-void DistControl::setTargetPosition(int32_t distance, int32_t angle, uint16_t time) {
-  chSysLock();
-  targetDistance = distance; // um
-  drivingForward = distance > 0;
-  if (!drivingForward) {
-    targetDistance *= -1;
-  }
-  targetAngle = angle; // urad
-  turningLeft = angle > 0;
-  if (!turningLeft) {
-    targetAngle *= -1;
-  }
-  restTime = time * 1e3; // us
-  controllerActive = true;
-  chSysUnlock();
-  fullDistance[LEFT_WHEEL] = 0;
-  fullDistance[RIGHT_WHEEL] = 0;
-  motorControl->updateIncrements(motorIncrements, increment, incrementDifference);
-}
-
-bool DistControl::isActive(void) {
-  return controllerActive;
-}
-
-void DistControl::deactivateController(void) {
-  chSysLock();
-  controllerActive = false;
-  targetDistance = 0;
-  targetAngle = 0;
-  restTime = 0;
-  for (int idx=0; idx < 2; idx++) {
-    increment[idx] = 0;
-    incrementDifference[idx] = 0;
-    actualDistance[idx] = 0;
-    fullDistance[idx] = 0;
-  }
-  chSysUnlock();
-}
-
-msg_t DistControl::main(void) {
-  systime_t time = System::getTime();
-  systime_t printTime = time;
-  this->setName("DistControl");
-
-  DistControl::deactivateController();
-
-  while (!this->shouldTerminate()) {
-    time += MS2ST(this->period);
-
-    if (controllerActive) {
-      // get increment differences for each wheel
-      motorControl->updateIncrements(motorIncrements, increment, incrementDifference); // ticks
-
-      // calculate driven distance difference for each wheel
-      motorControl->updateDistance(incrementDifference, actualDistance); // m
-
-      // calculate full driven distance for each wheel
-      for (int idxWheel = 0; idxWheel < 2; idxWheel++) {
-        fullDistance[idxWheel] += (int32_t)(actualDistance[idxWheel]*1e6);
-      }
-
-      // calculate whole driven distance and angle
-      realDistance = (fullDistance[LEFT_WHEEL] + fullDistance[RIGHT_WHEEL]) / 2.0; // um
-      if (!drivingForward) {
-        realDistance *= -1;
-      }
-      realAngle = (fullDistance[RIGHT_WHEEL] - fullDistance[LEFT_WHEEL]) / MotorControl::actualWheelBaseDistanceSI; // urad
-      if (!turningLeft) {
-        realAngle *= -1;
-      }
-
-      // calculate distance and angle to drive
-      errorDistance = targetDistance - realDistance; // um
-      if (errorDistance < 0) {
-        errorDistance = 0;
-      }
-      errorAngle = targetAngle - realAngle; // urad
-      if (errorAngle < 0) {
-        errorAngle = 0;
-      }
-
-      // calculate velocities for motor control
-      DistControl::calcVelocities();
-
-      if (controllerActive && newVelocities) {
-        // set target velocities
-        this->motorControl->setTargetSpeed(targetVelocity);
-        newVelocities = false;
-      }
-
-/*
-      if (time-printTime > MS2ST(100)) {
-        chprintf((BaseSequentialStream*) &global.sercanmux1, "dist = %i um, angle = %i urad, ed = %i um, ea = %i, v = %i um/s, w = %i urad/s\n", realDistance, realAngle, errorDistance, errorAngle, targetVelocity.x, targetVelocity.w_z);
-        printTime = time;
-      }
-*/
-
-      // reduce rest time (us)
-      restTime -= period*1e3;
-      if (restTime < 1) {
-        restTime = 1;
-      }
-
-      // deactivate controller if necessary
-      if (errorDistance == 0 && errorAngle == 0) {
-        deactivateController();
-      }
-
-    }
-
-    chThdSleepUntil(time);
-  }
-
-  return true;
-}
-
-void DistControl::calcVelocities(void) {
-  // TODO calculate target velocities better
-
-  // set intuitive velocities
-  int32_t forwardSpeed = (int32_t) (errorDistance * 1e6 / (1.0f*restTime)); // um/s
-  int32_t angleSpeed = (int32_t) (errorAngle * 1e6 / (1.0f*restTime)); // urad/s
-
-  int32_t maxForward = maxVelocity.x;
-  if (maxForward > errorDistance) {
-    maxForward = errorDistance;
-  }
-
-  int32_t maxTurn = maxVelocity.w_z;
-  if (maxTurn > errorAngle) {
-    maxTurn = errorAngle;
-  }
-
-  // check max forward speed
-  if (forwardSpeed > maxForward) {
-    forwardSpeed = maxForward;
-    angleSpeed = (int32_t) (forwardSpeed * ((1.0f*errorAngle) / (1.0f*errorDistance)));
-  }
-
-  // check max angle speed
-  if (angleSpeed > maxTurn) {
-    angleSpeed = maxTurn;
-    forwardSpeed = (int32_t) (angleSpeed * ((1.0f*errorDistance) / (1.0f*errorAngle)));
-  }
-
-  // check for too small speeds
-  if (errorDistance > 0 && forwardSpeed < minVelocity.x) {
-    forwardSpeed = minVelocity.x;
-  }
-  if (errorAngle > 0 && errorDistance == 0 && angleSpeed < minVelocity.w_z) {
-    angleSpeed = minVelocity.w_z;
-  }
-
-  // set velocity directions
-  if (!drivingForward) {
-    forwardSpeed *= -1;
-  }
-  if (!turningLeft) {
-    angleSpeed *= -1;
-  }
-
-  // if nessecary set new target velocities
-  if (forwardSpeed != targetVelocity.x || angleSpeed != targetVelocity.w_z) {
-    newVelocities = true;
-    targetVelocity.x = forwardSpeed;
-    targetVelocity.w_z = angleSpeed;
-  }
-}
diff --git a/components/FileSystemInputOutput/FSIODiWheelDrive.cpp b/components/FileSystemInputOutput/FSIODiWheelDrive.cpp
deleted file mode 100644
index f7ce6e3..0000000
--- a/components/FileSystemInputOutput/FSIODiWheelDrive.cpp
+++ /dev/null
@@ -1,406 +0,0 @@
-#include <amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp>
-
-using namespace amiro;
-using namespace amiro::fileSystemIo;
-
-msg_t
-FSIODiWheelDrive::
-getVcnl4020Offset (uint16_t *buffer, uint8_t idx) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(uint16_t);
-
-  // Check if the vcnl index is in a valid range
-  if (idx >= sizeof(DiWheelDrive_1_1::vcnl4020offset)) {
-    return WRONG_INDEX;
-  }
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_1, vcnl4020offset[idx]));
-      if (this->bsmv >= 0x01u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-msg_t
-FSIODiWheelDrive::
-setVcnl4020Offset (uint16_t buffer, uint8_t idx) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(uint16_t);
-
-  // Check if the vcnl index is in a valid range
-  if (idx >= sizeof(DiWheelDrive_1_1::vcnl4020offset)) {
-    return WRONG_INDEX;
-  }
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_1, vcnl4020offset[idx]));
-      if (this->bsmv >= 0x01u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-msg_t
-FSIODiWheelDrive::
-setwheelfactor (float buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, wheelfactor));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-msg_t
-FSIODiWheelDrive::
-getWheelFactor (float *buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, wheelfactor));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-msg_t
-FSIODiWheelDrive::
-setiGain (float buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, igain));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-msg_t
-FSIODiWheelDrive::
-getiGain (float *buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, igain));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-
-
-msg_t
-FSIODiWheelDrive::
-setdGain (float buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, dgain));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-msg_t
-FSIODiWheelDrive::
-getdGain (float *buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, dgain));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-
-
-msg_t
-FSIODiWheelDrive::
-setpGain (int buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, pgain));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-msg_t
-FSIODiWheelDrive::
-getpGain (int *buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_3, pgain));
-      if (this->bsmv >= 0x03u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-
-
-msg_t
-FSIODiWheelDrive::
-getEd (float *buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_2, Ed));
-      if (this->bsmv >= 0x02u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-msg_t
-FSIODiWheelDrive::
-setEd (float buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_2, Ed));
-      if (this->bsmv >= 0x02u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-msg_t
-FSIODiWheelDrive::
-getEb (float *buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_2, Eb));
-      if (this->bsmv >= 0x02u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
-
-msg_t
-FSIODiWheelDrive::
-setEb (float buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(float);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIODiWheelDrive::DiWheelDrive_1_2, Eb));
-      if (this->bsmv >= 0x02u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-  }
-
-  if (bytesWritten != bufferSize) {
-    return IO_ERROR;
-  } else {
-    return OK;
-  }
-}
diff --git a/components/FileSystemInputOutput/FSIOLightRing.cpp b/components/FileSystemInputOutput/FSIOLightRing.cpp
deleted file mode 100644
index a9cf982..0000000
--- a/components/FileSystemInputOutput/FSIOLightRing.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-#include <amiro/FileSystemInputOutput/FSIOLightRing.hpp>
-
-using namespace amiro;
-using namespace amiro::fileSystemIo;
\ No newline at end of file
diff --git a/components/FileSystemInputOutput/FSIOPowerManagement.cpp b/components/FileSystemInputOutput/FSIOPowerManagement.cpp
deleted file mode 100644
index 31c9058..0000000
--- a/components/FileSystemInputOutput/FSIOPowerManagement.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <amiro/FileSystemInputOutput/FSIOPowerManagement.hpp>
-
-using namespace amiro;
-using namespace amiro::fileSystemIo;
-
-msg_t
-FSIOPowerManagement::
-getVcnl4020Offset (uint16_t *buffer, uint8_t idx) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(uint16_t);
-
-  // Check if the vcnl index is in a valid range
-  if (idx >= sizeof(PowerManagement_1_1::vcnl4020offset)) {
-    return WRONG_INDEX;
-  }
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIOPowerManagement::PowerManagement_1_1, vcnl4020offset[idx]));
-      if (this->bsmv >= 0x01u) {
-        bytesWritten = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-    }
-
-    if (bytesWritten != bufferSize) {
-      return IO_ERROR;
-    } else {
-      return OK;
-    }
-}
-
-msg_t
-FSIOPowerManagement::
-setVcnl4020Offset (uint16_t buffer, uint8_t idx) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(uint16_t);
-
-  // Check if the vcnl index is in a valid range
-  if (idx >= sizeof(PowerManagement_1_1::vcnl4020offset)) {
-    return WRONG_INDEX;
-  }
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FSIOPowerManagement::PowerManagement_1_1, vcnl4020offset[idx]));
-      if (this->bsmv >= 0x01u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-    }
-
-    if (bytesWritten != bufferSize) {
-      return IO_ERROR;
-    } else {
-      return OK;
-    }
-}
diff --git a/components/FileSystemInputOutput/FileSystemInputOutputBase.cpp b/components/FileSystemInputOutput/FileSystemInputOutputBase.cpp
deleted file mode 100644
index 7fe529e..0000000
--- a/components/FileSystemInputOutput/FileSystemInputOutputBase.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-#include <amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp>
-
-using namespace amiro;
-using namespace amiro::fileSystemIo;
-
-msg_t
-FileSystemIoBase::init()
-{
-  msg_t returnValue = OK;
-
-  // Get the preamble
-  const uint8_t bufferSize = sizeof(FileSystemIoBase::preamble_1_1);
-  uint8_t buffer[bufferSize];
-  chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FileSystemIoBase::preamble_1_1, magicByte));
-  const size_t bytesRead = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-
-  // reading failed -> error
-  if (bytesRead != bufferSize) {
-    returnValue |= IO_ERROR;
-    return returnValue;
-  }
-
-  // magic byte is incorrect -> error
-  if (buffer[offsetof(FileSystemIoBase::preamble_1_1, magicByte)] != magicByteValue()) {
-    returnValue |= WRONG_MAGICBYTE_VALUE;
-    return returnValue;
-  }
-
-  // BSMV is incorrect -> error
-  if (buffer[offsetof(FileSystemIoBase::preamble_1_1, byteStructureMajorVersion)] != BSMV) {
-    returnValue |= WRONG_BSMV;
-    return returnValue;
-  }
-
-  // bsmv in smaller -> initialize
-  if (buffer[offsetof(FileSystemIoBase::preamble_1_1, byteStructureMinorVersion)] < bsmv) {
-    returnValue |= WRONG_bsmv;
-    // initialize all missing data
-    for (uint8_t v = bsmv; v > buffer[offsetof(FileSystemIoBase::preamble_1_1, byteStructureMinorVersion)]; --v)
-    {
-      returnValue |= initPreamble(BSMV, v, false);
-    }
-  }
-
-  // HMV is incorrect -> error
-  if (buffer[offsetof(FileSystemIoBase::preamble_1_1, hardwareMajorVersion)] != HMV) {
-    returnValue |= WRONG_HMV;
-    return returnValue;
-  }
-
-  // hmv is incorrect -> error
-  if (buffer[offsetof(FileSystemIoBase::preamble_1_1, hardwareMinorVersion)] >= hmv) {
-    returnValue |= WRONG_hmv;
-  }
-
-  return returnValue;
-}
-
-msg_t
-FileSystemIoBase::
-getCheck() {
-
-  // Get the preamble
-  const uint8_t bufferSize = sizeof(FileSystemIoBase::preamble_1_1);
-  uint8_t buffer[bufferSize];
-  chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FileSystemIoBase::preamble_1_1, magicByte));
-  const size_t bytesRead = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) buffer, bufferSize);
-
-  if (bytesRead != bufferSize) {
-    return IO_ERROR;
-  } else if (buffer[offsetof(FileSystemIoBase::preamble_1_1, magicByte)] != magicByteValue()) {
-    return WRONG_MAGICBYTE_VALUE;
-  } else if (buffer[offsetof(FileSystemIoBase::preamble_1_1, byteStructureMajorVersion)] != BSMV) {
-    return WRONG_BSMV;
-  } else if (buffer[offsetof(FileSystemIoBase::preamble_1_1, byteStructureMinorVersion)] < bsmv) {
-    return WRONG_bsmv;
-  } else if (buffer[offsetof(FileSystemIoBase::preamble_1_1, hardwareMajorVersion)] != HMV) {
-    return WRONG_HMV;
-  } else if (buffer[offsetof(FileSystemIoBase::preamble_1_1, hardwareMinorVersion)] < hmv) {
-    return WRONG_hmv;
-  } else {
-    return OK;
-  }
-}
-
-msg_t
-FileSystemIoBase::initPreamble(const uint8_t BSMV, const uint8_t bsmv, const bool strict)
-{
-  uint8_t buffer[3] = {};
-
-  if (strict) {
-    // initialize the magic byte
-    chFileStreamSeek((BaseFileStream*)&this->at24c01, offsetof(FileSystemIoBase::preamble_1_1, magicByte));
-    buffer[0] = magicByteValue();
-    if (chSequentialStreamWrite((BaseFileStream*)&this->at24c01, buffer, 1) != 1) {
-      return IO_ERROR;
-    }
-  }
-
-  switch (BSMV)
-  {
-    case 1:
-      if (strict) {
-        // initialize the BSMV
-        chFileStreamSeek((BaseFileStream*)&this->at24c01, offsetof(FileSystemIoBase::preamble_1_1, byteStructureMajorVersion));
-        buffer[0] = BSMV;
-        if (chSequentialStreamWrite((BaseFileStream*)&this->at24c01, buffer, 1) != 1) {
-          return IO_ERROR;
-        }
-      }
-      // initialize the bsmv
-      chFileStreamSeek((BaseFileStream*)&this->at24c01, offsetof(FileSystemIoBase::preamble_1_1, byteStructureMinorVersion));
-      buffer[0] = bsmv;
-      if (chSequentialStreamWrite((BaseFileStream*)&this->at24c01, buffer, 1) != 1) {
-        return IO_ERROR;
-      }
-      // initialize the content
-      switch (bsmv)
-      {
-        case 2:
-          // initialize the board ID
-          chFileStreamSeek((BaseFileStream*)&this->at24c01, offsetof(FileSystemIoBase::preamble_1_2, boardId));
-          buffer[0] = 0;
-          if (chSequentialStreamWrite((BaseFileStream*)&this->at24c01, buffer, 1) != 1) {
-            return IO_ERROR;
-          }
-          if (!strict) {
-            break;
-          }
-
-        case 1:
-          // initialize the bsmv, the HMV and the hmv
-          chFileStreamSeek((BaseFileStream*)&this->at24c01, offsetof(FileSystemIoBase::preamble_1_1, byteStructureMinorVersion));
-          buffer[0] = bsmv;
-          buffer[1] = this->HMV;
-          buffer[2] = this->hmv;
-          if (chSequentialStreamWrite((BaseFileStream*)&this->at24c01, buffer, 3) != 3) {
-            return IO_ERROR;
-          }
-          if (!strict) {
-            break;
-          }
-
-        default:
-          break;
-
-      }
-      break;
-
-    default:
-      break;
-  }
-
-  return OK;
-}
-
-msg_t
-FileSystemIoBase::
-resetMemory() {
-  return initPreamble(this->BSMV, this->bsmv, true);
-}
-
-msg_t
-FileSystemIoBase::
-getBoardId (uint8_t *buffer) {
-
-  msg_t bytesRead = 0;
-  // Work around, because stm32f1 cannot read a single byte
-  const uint8_t bufferSize = 2;
-  uint8_t bufferTmp[bufferSize] = {};
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FileSystemIoBase::preamble_1_2, boardId));
-      if (this->bsmv >= 0x02u) {
-        bytesRead = chSequentialStreamRead((BaseFileStream*)&at24c01, (uint8_t*) bufferTmp, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-    }
-
-  // Store only the board id
-  *buffer = bufferTmp[0];
-
-    if (bytesRead != bufferSize) {
-      return IO_ERROR;
-    } else {
-      return OK;
-    }
-}
-
-msg_t
-FileSystemIoBase::
-setBoardId (uint8_t buffer) {
-
-  msg_t bytesWritten = 0;
-  const uint8_t bufferSize = sizeof(uint8_t);
-
-  // Get the data out of the memory
-  switch (this->BSMV) {
-    case 0x01u:
-      // Set the pointer to the address
-      chFileStreamSeek((BaseFileStream*)&at24c01, offsetof(FileSystemIoBase::preamble_1_2, boardId));
-      if (this->bsmv >= 0x02u) {
-        bytesWritten = chSequentialStreamWrite((BaseFileStream*)&at24c01, (const uint8_t*) &buffer, bufferSize);
-      } else {
-        return NOT_IMPLEMENTED;
-      }
-      break;
-    }
-
-    if (bytesWritten != bufferSize) {
-      return IO_ERROR;
-    } else {
-      return OK;
-    }
-}
diff --git a/components/Lidar.cpp b/components/Lidar.cpp
deleted file mode 100644
index a3b7a31..0000000
--- a/components/Lidar.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-#include <amiro/Lidar.h>
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-extern Global global;
-
-uint8_t Lidar::scannedData[NUMBER_OF_CHARACTERS + 1] = {};
-
-Lidar::Lidar(const uint8_t boardId, Lidar::SETUP setup)
-    : BaseStaticThread<256>(),
-      boardId(boardId),
-      setup(setup) {
-
-}
-
-Lidar::
-~Lidar() {
-
-  // Power down the LIDAR
-  // TODO Is it correct anyway
-  switch (boardId) {
-    case(CAN::LIGHT_RING_ID):
-      palWritePad(GPIOB, GPIOB_LASER_EN, PAL_LOW);
-      break;
-    default:
-      break;
-  }
-  this->isReady = false;
-};
-
-void Lidar::flushSD2InputQueue() {
-  chSysLock();
-  chIQResetI(&SD2.iqueue);
-  chSysUnlock();
-}
-
-msg_t Lidar::main(void) {
-
-
-  switch (this->boardId) {
-    case(CAN::LIGHT_RING_ID): {
-
-      // Power up the LIDAR
-      palWritePad(GPIOB, GPIOB_LASER_EN, PAL_HIGH);
-      BaseThread::sleep(MS2ST(5000));
-
-      // Setup the driver and lidar, if we want to communicate with it
-      if (setup != SETUP::POWER_ONLY) {
-        // Flush the queue because there is a "0" in it
-        flushSD2InputQueue();
-
-        // Configure LIDAR serial interface speed
-//       chprintf((BaseSequentialStream*) &global.sercanmux1, "Speed switch to " STR(SD_SPEED) "\n");
-        chprintf((BaseSequentialStream*) &SD2, "SS" STR(SD_SPEED_PREFIX) STR(SD_SPEED) LF);
-
-        // Check if the switch went well, otherwise terminate the thread
-        if (checkDataString("SS" STR(SD_SPEED_PREFIX) STR(SD_SPEED) "\n00P\n\n")) {
-          chprintf((BaseSequentialStream*) &global.sercanmux1, "Lidar speed switch OK\n");
-          // Configure serial interface of STM32
-          sdStop(&SD2);
-          SerialConfig sdLidarconf = { SD_SPEED, 0, 0, 0 };
-          sdStart(&SD2, &sdLidarconf);
-        } else {
-          chprintf((BaseSequentialStream*) &global.sercanmux1, "Lidar speed switch NOT OK: Terminating Lidar \n");
-          palWritePad(GPIOB, GPIOB_LASER_EN, PAL_LOW);
-          return -1;
-        }
-      }
-      break;
-    }
-    default:
-      break;
-  }
-
-  evtInit(&this->evtimer, UPDATE_LIDAR_PERIOD_MSEC);
-
-  EvtSource *eventTimerEvtSource = reinterpret_cast<EvtSource *>(&this->evtimer.et_es);
-
-  EvtListener eventTimerEvtListener;
-
-  // TODO Does PERIODIC_TIMER_ID has something to do with ControllerAreNetwork.h ?
-  eventTimerEvtSource->registerOne(&eventTimerEvtListener, CAN::PERIODIC_TIMER_ID);
-
-  evtStart(&this->evtimer);
-
-  this->setName("Lidar");
-
-  while (!this->shouldTerminate()) {
-
-    eventmask_t eventMask = this->waitOneEvent(ALL_EVENTS);
-    switch (eventMask) {
-      case EVENT_MASK(CAN::PERIODIC_TIMER_ID):
-//         printDetails();
-        if (setup != SETUP::POWER_ONLY) {
-          updateSensorVal();
-        }
-        break;
-    }
-  }
-
-  evtStop(&this->evtimer);
-  eventTimerEvtSource->unregister(&eventTimerEvtListener);
-
-  return RDY_OK;
-}
-
-bool_t Lidar::getScan(uint16_t (&scannedData)[NUMBER_OF_STEPS]) {
-  if (this->isReady && !this->isFail) {
-    chSysLock();
-      memcpy(&scannedData, &(Lidar::scannedData[0]), NUMBER_OF_CHARACTERS);
-      this->isReady = false;
-    chSysUnlock();
-    return true;
-  } else {
-    return false;
-  }
-}
-
-uint16_t Lidar::getNumberOfValues() {
-  return NUMBER_OF_STEPS;
-}
-
-uint16_t Lidar::twoCharacterEncoding(uint8_t &char1, uint8_t &char2) {
-  return uint16_t((((char1 - 0x30) & 0b00111111) << 6) | ((char2 - 0x30) & 0b00111111));
-}
-
-bool_t Lidar::getData(uint8_t &data, uint32_t timeoutMs) {
-
-//     data = sdGet(&SD2);
-    msg_t dataTmp = chIQGetTimeout(&SD2.iqueue, MS2ST(timeoutMs));
-    if  (dataTmp == Q_TIMEOUT || dataTmp == Q_RESET) {
-      return false;
-    } else {
-      data = uint8_t(dataTmp);
-      ++this->dataCounter;
-      return true;
-    }
-}
-
-msg_t Lidar::updateSensorVal() {
-
-  chSysLock();
-    // Set this flag so that the everyone knows, that scannedData will be filed right now
-    this->isReady = false;
-    // Reset the FAIL flag
-    this->isFail = false;
-  chSysUnlock();
-
-  while (!this->isReady) {
-    switch(step) {
-      case SEND_SCAN_CMD:
-        flushSD2InputQueue();
-//                     Read (725-(44-1))=682 values with two-character encoding what makes 1364 datapoints
-//                     1456 in total:
-//                     16 (Cmd-Echo) + ? (Remaining Scans) + 1 (LF) + ? (String Characters) + 1 (LF) + 2 (Status) + 1 (Sum) + 1 (LF) + ? (Timestamp) + 1 (LF) + 1364 (Data for a certain setup) + 1 (Sum) + 1 (LF) + 1 (LF)
-        chprintf((BaseSequentialStream*) &SD2,DATA_ACQ_CODE STR(STARTING_STEP_PREFIX) STR(STARTING_STEP) STR(END_STEP_PREFIX) STR(END_STEP) STR(CLUSTER_COUNT) STR(SCAN_INTERVALL) STR(NUMBER_OF_INTERVALL) LF);
-        step = DATA_VALID_CHECK;
-        this->dataCounter = 0;
-        break;
-      case DATA_VALID_CHECK:
-        if(getData(this->newInput, 200)) {
-          // TODO check for last data, if scan has a few errors
-          // HACK The timeout fix this issue at least, because after a while there
-          //      wont be any transmitts
-          if (this->newInput == validScanTag[this->checkStatusIdx]) {
-            if (++this->checkStatusIdx == 5) {
-              // scan_data is without error: Found the sting "\n99b\n"
-              step = DATA_START_CHECK;
-              this->checkStatusIdx = 0;
-            }
-          } else {
-            this->checkStatusIdx = 0;
-          }
-        } else {
-          step = FAIL;
-        }
-        break;
-      case DATA_START_CHECK:
-        // Check for the next linefeed to start the record
-        if(getData(this->newInput, 200)) {
-          if (this->newInput == 10) {
-            step = DATA_RECORD;
-            this->dataIdx = 0;
-          }
-        } else {
-          step = FAIL;
-        }
-        break;
-      case DATA_RECORD:
-        if(getData(this->newInput, 200)) {
-          if (this->lastInput == 10 && this->newInput == 10) {
-            // end of data
-            this->lastInput = 0x0;  // Just to delete this->lastInput value
-            step = DATA_DECODE;
-          } else if  (this->newInput != 10) {
-            Lidar::scannedData[this->dataIdx++] = this->newInput;
-            this->lastInput = this->newInput;
-          } else {  // this->lastInput != 10 && this->newInput == 10
-            // This is the case, where we know that the last character was the checksum.
-            // Therefore, we need to decrement the counter
-            --this->dataIdx;
-            this->lastInput = this->newInput;
-          }
-          //chprintf((BaseSequentialStream*) &global.sercanmux1, "%d ", this->newInput);
-        } else {
-          step = FAIL;
-        }
-        break;
-      case DATA_DECODE:
-        // Decode the recorded data
-        for (uint16_t idx=0; idx < NUMBER_OF_CHARACTERS; idx += 2) {
-          //TODO Check if +1 is right
-          *((uint16_t*) &(Lidar::scannedData[idx])) = twoCharacterEncoding(Lidar::scannedData[idx],Lidar::scannedData[idx+1]);
-        }
-        // To print out the data in this thread, choose "step = DATA_SHOW"
-        step = FINISH;
-        break;
-      case DATA_SHOW:
-        // Show the decoded data
-        chprintf((BaseSequentialStream*) &global.sercanmux1, "\n%d", this->dataCounter);
-        for (uint32_t idx=0; idx < this->dataIdx; idx+=2) {
-          chprintf((BaseSequentialStream*) &global.sercanmux1, "\n%d", *((uint16_t*) &(Lidar::scannedData[idx])));
-        }
-        step = FINISH;
-        break;
-      case FAIL:
-        // Set the FAIL flag
-        chSysLock();
-          // Set this flag so that the everyone knows, that scannedData holds wrong information
-          this->isFail = true;
-        chSysUnlock();
-        break;
-      case FINISH:
-        // Clean up
-        this->step = SEND_SCAN_CMD;
-        chSysLock();
-          // Set this flag so that the everyone knows, that scannedData holds the actual data
-          this->isReady = true;
-        chSysUnlock();
-        break;
-      default:
-        break;
-    }
-  }
-
-  return RDY_OK;
-}
-
-void Lidar::printData() {
-  uint8_t lastInput = 0xFF, newInput = 0xFF;
-  while (true) {
-    if(getData(newInput, 200)) {
-      if (lastInput == 10 && newInput == 10) {
-        return;
-      } else {
-        chprintf((BaseSequentialStream*) &global.sercanmux1, "%c", newInput);
-      }
-      lastInput = newInput;
-    } else {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "TIMEOUT\n", newInput);
-      return;
-    }
-  }
-}
-
-bool_t Lidar::checkDataString(const char compareString[]) {
-  uint8_t lastInput = 0xFF, newInput = 0xFF, recIdx = 0;
-  bool_t dataOk = true, processFlag = true;
-  while (processFlag) {
-    if (getData(newInput, 200)) {
-      // End of data received, quit processing
-      if (lastInput == 10 && newInput == 10) {
-        processFlag = false;
-      }
-      // Compare data if the characters before have been ok
-      // Otherwise do not compare anymore, because of possible
-      // segmentation fault
-      if (dataOk) {
-        if (newInput != compareString[recIdx++]) {
-          dataOk = false;
-        }
-      }
-      // Save the received character
-      lastInput = newInput;
-    } else {
-      processFlag = false;
-      dataOk = false;
-    }
-  }
-  return dataOk;
-}
-
-void Lidar::printDetails() {
-
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "Print sensor details:\n");
-
-  // Tell the sensor to transmit its details
-  chprintf((BaseSequentialStream*) &SD2, "VV\n");
-
-  // Print the transmitted data
-  printData();
-}
-
-void Lidar::printSpecification() {
-
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "Print sensor specification:\n");
-
-  // Tell the sensor to transmit its specifications
-  chprintf((BaseSequentialStream*) &SD2, "PP\n");
-
-  // Print the transmitted data
-  printData();
-}
-
-void Lidar::printInformation() {
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "Print sensor information:\n");
-
-  // Tell the sensor to transmit its information
-  chprintf((BaseSequentialStream*) &SD2, "II\n");
-
-  // Print the transmitted data
-  printData();
-}
-
-bool_t Lidar::getIsReady() {
-  return this->isReady;
-}
diff --git a/components/MotorControl.cpp b/components/MotorControl.cpp
deleted file mode 100644
index f5d72dd..0000000
--- a/components/MotorControl.cpp
+++ /dev/null
@@ -1,539 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <qei.h>
-#include <chprintf.h>
-#include <amiro/MotorControl.h>
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace types;
-using namespace constants;
-using namespace constants::DiWheelDrive;
-
-float MotorControl::wheelDiameterCorrectionFactor[2] = {1.0f, 1.0f};
-float MotorControl::actualWheelBaseDistanceSI = wheelBaseDistanceSI;
-extern Global global;
-
-MotorControl::MotorControl(PWMDriver* pwm, MotorIncrements* mi, GPIO_TypeDef* port, int pad, fileSystemIo::FSIODiWheelDrive *memory)
-    : BaseStaticThread<512>(),
-      pwmDriver(pwm),
-      motorIncrements(mi),
-      powerEnablePort(port),
-      powerEnablePad(pad),
-      eventSource(),
-      period(10),
-      memory(memory) {
-
-  this->pwmConfig.frequency = 7200000;
-  this->pwmConfig.period = 360;
-  this->pwmConfig.callback = NULL;
-  this->pwmConfig.channels[0].mode = PWM_OUTPUT_ACTIVE_HIGH;
-  this->pwmConfig.channels[0].callback = NULL;
-  this->pwmConfig.channels[1].mode = PWM_OUTPUT_ACTIVE_HIGH;
-  this->pwmConfig.channels[1].callback = NULL;
-  this->pwmConfig.channels[2].mode = PWM_OUTPUT_ACTIVE_HIGH;
-  this->pwmConfig.channels[2].callback = NULL;
-  this->pwmConfig.channels[3].mode = PWM_OUTPUT_ACTIVE_HIGH;
-  this->pwmConfig.channels[3].callback = NULL;
-  this->pwmConfig.cr2 = 0;
-
-  this->increment[0] = 0;
-  this->increment[1] = 0;
-
-  this->errorSum[0] = 0;
-  this->errorSum[1] = 0;
-
-  this->errorSumDiff = 0;
-
-  // Init the velocities
-  this->currentVelocity.x = 0;
-  this->currentVelocity.y = 0;
-  this->currentVelocity.z = 0;
-  this->currentVelocity.w_x = 0;
-  this->currentVelocity.w_y = 0;
-  this->currentVelocity.w_z = 0;
-  this->targetVelocity.x = 0;
-  this->targetVelocity.w_z = 0;
-
-  this->newTargetVelocities = false;
-  this->lastVelocitiesV[0] = 0;
-  this->lastVelocitiesV[1] = 0;
-  this->lastVelocitiesV[2] = 0;
-  this->lastVelocitiesV[3] = 0;
-  this->lastVelocitiesV[4] = 0;
-  this->lastVelocitiesV[5] = 0;
-
-  this->newTargetVelocities = true;
-
-  // calibration stuff;
-  for (int i =0; i<3; i++){
-    this->leftWValues[i] = i;
-    this->rightWValues[i] = i;
-  }
-
-}
-
-int MotorControl::getCurrentRPMLeft() {
-  return this->actualSpeed[LEFT_WHEEL];
-}
-
-int MotorControl::getCurrentRPMRight() {
-  return this->actualSpeed[RIGHT_WHEEL];
-}
-
-kinematic MotorControl::getCurrentVelocity() {
-  return this->currentVelocity;
-}
-
-msg_t MotorControl::setWheelDiameterCorrectionFactor(float Ed /* = 1.0f */, bool_t storeEdToMemory /* = false */) {
-  // cl (Eq. 17a)
-  MotorControl::wheelDiameterCorrectionFactor[LEFT_WHEEL] = 2.0f / (Ed + 1.0f);
-  // cl (Eq. 17a)
-  MotorControl::wheelDiameterCorrectionFactor[RIGHT_WHEEL] = 2.0f / ((1.0f / Ed) + 1.0f);
-  // Store Ed to memory
-  if (storeEdToMemory)
-    return memory->setEd(Ed);
-  else
-    return RDY_OK;
-}
-
-msg_t MotorControl::setActualWheelBaseDistance(float Eb /* = 1.0f */, bool_t storeEbToMemory /* = false */) {
-  // bActual (Eq. 4)
-  MotorControl::actualWheelBaseDistanceSI = wheelBaseDistanceSI * Eb;
-  // Store Eb to memory
-  if (storeEbToMemory)
-    return memory->setEb(Eb);
-  else
-    return RDY_OK;
-}
-
-EvtSource* MotorControl::getEventSource() {
-  return &this->eventSource;
-}
-
-void MotorControl::setTargetRPM(int32_t targetURpmLeft, int32_t targetURpmRight) {
-  // Velocity in µm/s in x direction
-  int32_t targetVelocityX = (wheelCircumferenceSI * (targetURpmLeft + targetURpmRight)) / secondsPerMinute / 2.0f;
-  // Angular velocity around z in µrad/s
-  int32_t targetVelocityWz = (wheelCircumferenceSI * (targetURpmRight - targetURpmLeft)) / secondsPerMinute / MotorControl::actualWheelBaseDistanceSI;
-  chSysLock();
-  this->targetVelocity.x = targetVelocityX;
-  this->targetVelocity.w_z = targetVelocityWz;
-  this->newTargetVelocities = true;
-  chSysUnlock();
-}
-
-void MotorControl::setTargetSpeed(const kinematic &targetVelocity) {
-  chSysLock();
-  this->targetVelocity.x = targetVelocity.x;
-  this->targetVelocity.w_z = targetVelocity.w_z;
-  this->newTargetVelocities = true;
-  chSysUnlock();
-}
-
-msg_t MotorControl::main(void) {
-  systime_t time = System::getTime();
-  this->setName("MotorControl");
-
-  // load controller parameters from memory
-  this->memory->getWheelFactor(&this->motorCalibrationFactor);
-  this->memory->getpGain(&this->pGain);
-  this->memory->getiGain(&this->iGain);
-  this->memory->getdGain(&this->dGain);
-  this->memory->getEb(&this->Eb);
-  this->memory->getEd(&this->Ed);
-
-  pwmStart(this->pwmDriver, &this->pwmConfig);
-
-  palSetPad(this->powerEnablePort, this->powerEnablePad);
-
-  while (!this->shouldTerminate()) {
-    time += MS2ST(this->period);
-
-    // Get the increments from the QEI
-    MotorControl::updateIncrements(this->motorIncrements, this->increment, this->incrementDifference);
-
-    // Get the actual speed from the gathered increments
-    MotorControl::updateSpeed(this->incrementDifference, this->actualSpeed, this->period);
-
-    // Calculate velocities
-    this->calcVelocity();
-
-    // updates past velocities for the derivate part of the controller
-    updateDerivativeLastVelocities();
-
-    controllerAndCalibrationLogic();
-
-    // Write the calculated duty cycle to the pwm driver
-    this->writePulseWidthModulation();
-
-    chThdSleepUntil(time);
-
-    delay ++;
-    if (delay > 50){
-      delay = 0;
-    }
-
-  }
-
-  // Reset the PWM befor shutdown
-  this->pwmPercentage[LEFT_WHEEL] = 0;
-  this->pwmPercentage[RIGHT_WHEEL] = 0;
-  this->writePulseWidthModulation();
-
-  return true;
-}
-
-void MotorControl::controllerAndCalibrationLogic(){
-  if (!isCalibrating){
-    this->PIDController();
-    startedZieglerCalibration = true;
-    startedWheelCalibration = true;
-  } else {
-    if (motorCalibration){
-      if (startedWheelCalibration){
-        wheelCalibrationTime = System::getTime();
-        startedWheelCalibration = false;
-      }
-      calibrate();
-    } else {
-      this->PIDController();
-      this->calibrateZiegler();
-      this->updatePastVelocities();
-
-      if (startedZieglerCalibration){
-        zieglerCalibrationTime = System::getTime();
-        startedZieglerCalibration = false;
-      }
-    }
-  }
-}
-
-void MotorControl::calibrate() {
-
-  this->pwmPercentage[LEFT_WHEEL] = 3000;
-  this->pwmPercentage[RIGHT_WHEEL] = 3000;
-
-  this->rightWValues[0] = this->rightWValues[1];
-  this->rightWValues[1] = this->rightWValues[2];
-  this->rightWValues[2] = getRightWheelSpeed();
-
-  this->leftWValues[0] = this->leftWValues[1];
-  this->leftWValues[1] = this->leftWValues[2];
-  this->leftWValues[2] = getLeftWheelSpeed();
-
-
-  if (this->rightWValues[0] == this->rightWValues[1] &&
-      this->rightWValues[1] == this->rightWValues[2] &&
-      this->leftWValues[0] == this->leftWValues[1] &&
-      this->leftWValues[1] == this->leftWValues[2] &&
-      System::getTime() - this->wheelCalibrationTime > 1500) {
-    this->motorCalibrationFactor = (float)this->rightWValues[0]/(float)this->leftWValues[0];
-
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "motorCalibrationFactor =   %f  \n" ,this->motorCalibrationFactor);
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "rw =   %i  \n" ,this->rightWValues[0]);
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "lw =   %i  \n" ,this->leftWValues[0]);
-
-    this->pwmPercentage[LEFT_WHEEL] = 0;
-    this->pwmPercentage[RIGHT_WHEEL] = 0;
-    this->motorCalibration = false;
-    this->memory->setwheelfactor(motorCalibrationFactor);
-  }
-}
-
-void MotorControl::calibrateZiegler() {
-
-    this->iGain =0;
-    this->dGain = 0;
-    int nsc  = this->getNumberofSignChanges();
-
-    if (System::getTime() - this->zieglerCalibrationTime > 1000){
-        this->zieglerCalibrationTime = System::getTime() ;
-        this->ziegler2 =true;
-    }
-
-    if (ziegler && ziegler2){
-        this->targetVelocity.x = 200000 * ((zieglerHelp%2 == 0) ? 1 : -1);
-        this->pGain = 1000 + 100 * zieglerHelp;
-        chprintf((BaseSequentialStream*) &global.sercanmux1, "pgain =  %i  \n" , this->pGain);
-        zieglerHelp++;
-        ziegler = false;
-        ziegler2 = false;
-    }
-
-    if (!ziegler  && ziegler2){
-        this->targetVelocity.x = 0;
-        ziegler2= false;
-        ziegler = true;
-    }
-
-    if (zieglerHelp > 20){
-        this->isCalibrating = false;
-        this->targetVelocity.x = 0;
-        this->iGain = 0.08;
-        this->pGain = 1000;
-    }
-
-
-    if ( nsc > 8){
-        zieglerHelp2++;
-        if (zieglerHelp2 > 20){
-           this->zieglerPeriod  = numberOfLastVelocitiesV * this->period / nsc;
-           chprintf((BaseSequentialStream*) &global.sercanmux1, "zieglerPeriod =   %f  \n" ,this->zieglerPeriod);
-
-           this->targetVelocity.x = 0;
-           this->pGain = (int) (this->pGain* 0.6);
-           this->iGain = (float) ((1/(0.5*(this->zieglerPeriod/1000))/this->pGain));
-           this->dGain = (float) ((1/(0.125*(this->zieglerPeriod/1000))/this->pGain));
-           this->memory->setpGain(this->pGain);
-           this->memory->setiGain(this->iGain);
-           this->memory->setdGain(this->dGain);
-           chprintf((BaseSequentialStream*) &global.sercanmux1, "pgain =   %i  \n" ,this->pGain);
-           chprintf((BaseSequentialStream*) &global.sercanmux1, "igain =   %f  \n" ,this->iGain);
-           chprintf((BaseSequentialStream*) &global.sercanmux1, "dgain =   %f  \n" ,this->dGain);
-
-           this->motorCalibration = true;
-           ziegler = true;
-           ziegler2 = true;
-           this->isCalibrating = false;
-           zieglerHelp = 0;
-           zieglerCalibrationTime = 0;
-           zieglerHelp2 = 0;
-
-           for (int i = 0; i< numberOfLastVelocitiesV ; i ++){
-               lastVelocitiesVBig[i] = 0;
-           }
-        }
-    }
-
-}
-
-void MotorControl::PIDController(){
-
-    //pgain #####################################
-    chSysLock();
-    int diffv =this->targetVelocity.x - this->currentVelocity.x;
-    int diffw = this->targetVelocity.w_z - this->currentVelocity.w_z;
-    chSysUnlock();
-
-    //igain ####################################
-   this->accumulatedErrorV += diffv;
-   this->accumulatedErrorW += diffw;
-
-    if (this->accumulatedErrorV > this->antiWindupV)
-      this->accumulatedErrorV = this->antiWindupV;
-    else if (this->accumulatedErrorV < -this->antiWindupV)
-      this->accumulatedErrorV = -this->antiWindupV;
-
-    if (this->accumulatedErrorW > this->antiWindupW)
-      this->accumulatedErrorW = this->antiWindupW;
-    else if (this->accumulatedErrorW < -this->antiWindupW)
-      this->accumulatedErrorW = -this->antiWindupW;
-
-    diffv += (int) (this->accumulatedErrorV*this->iGain);
-    diffw += (int) (this->accumulatedErrorW*this->iGain);
-
-    //dgain ###################################
-    int derivativeV;
-    int derivativeW;
-    int tmp1;
-    int tmp2;
-
-   tmp1 = static_cast<int32_t>((lastVelocitiesV[0]+lastVelocitiesV[1]+lastVelocitiesV[2])/3);
-   tmp2 = static_cast<int32_t>((lastVelocitiesV[3]+lastVelocitiesV[4]+lastVelocitiesV[5])/3);
-   derivativeV = static_cast<int32_t> ((tmp2-tmp1)/(int)(this->period));
-   tmp1 = static_cast<int32_t>((lastVelocitiesW[0]+lastVelocitiesW[1]+lastVelocitiesW[2])/3);
-   tmp2 = static_cast<int32_t>((lastVelocitiesW[3]+lastVelocitiesW[4]+lastVelocitiesW[5])/3);
-   derivativeW = static_cast<int32_t> ((tmp2-tmp1)/(int)(this->period));
-
-
-    diffv += (int) (dGain*derivativeV);
-    diffw += (int) (dGain*derivativeW);
-
-    setLeftWheelSpeed(diffv,diffw);
-    setRightWheelSpeed(diffv, diffw);
-}
-
-
-
-void MotorControl::setLeftWheelSpeed(int diffv, int diffw){
-    this->pwmPercentage[LEFT_WHEEL] = (int) (this->pGain*2*(diffv-0.5*diffw*wheelBaseDistanceSI*this->Eb)/(wheelDiameter*this->wheelDiameterCorrectionFactor[LEFT_WHEEL]));
-
-}
-
-void MotorControl::setRightWheelSpeed(int diffv, int diffw){
-    this->pwmPercentage[RIGHT_WHEEL] = (int) (motorCalibrationFactor*this->pGain*2*(diffv+0.5*diffw*wheelBaseDistanceSI*this->Eb)/(wheelDiameter*this->wheelDiameterCorrectionFactor[RIGHT_WHEEL]));
-}
-
-
-// speed in um
-int MotorControl::getRightWheelSpeed(){
-    int omega = 2*M_PI*this->actualSpeed[RIGHT_WHEEL]/60; // syslock noetig ? todo
-    return  omega * wheelDiameter*this->wheelDiameterCorrectionFactor[RIGHT_WHEEL];
-}
-// speed in um
-int MotorControl::getLeftWheelSpeed(){
-    int omega = 2*M_PI*this->actualSpeed[LEFT_WHEEL]/60;
-    return  omega * wheelDiameter*this->wheelDiameterCorrectionFactor[LEFT_WHEEL];
-}
-
-
-void MotorControl::updatePastVelocities(){
-    for (int i=0; i<numberOfLastVelocitiesV-1;i++){
-        lastVelocitiesVBig[i] = lastVelocitiesVBig[i+1];
-    }
-
-    lastVelocitiesVBig[numberOfLastVelocitiesV-1] = this->currentVelocity.x;
-
-}
-
-
-void MotorControl::updateDerivativeLastVelocities(){
-    for (int i=0; i<5;i++){
-        lastVelocitiesV[i] = lastVelocitiesV[i+1];
-        lastVelocitiesW[i] = lastVelocitiesW[i+1];
-    }
-
-
-    lastVelocitiesV[5] = this->currentVelocity.x;
-    lastVelocitiesW[5] = this->currentVelocity.w_z;
-
-
-}
-
-int MotorControl::getNumberofSignChanges(){
-    int nsc= 0;
-    bool ispositive = true;
-    bool tmpbool = true;
-    if (lastVelocitiesVBig[0] < 0){
-        ispositive =false;
-        tmpbool =false;
-    }
-    for (int i=0; i<numberOfLastVelocitiesV-1; i++){
-        if (lastVelocitiesVBig[i] < 0){
-            ispositive= false;
-        } else {
-            ispositive = true;
-        }
-        if (ispositive != tmpbool){
-            nsc++;
-            tmpbool = ispositive;
-        }
-
-    }
-
-    return nsc;
-}
-
-void MotorControl::printGains(){
-    chprintf((BaseSequentialStream*)&global.sercanmux1, "motorCalibrationFactor %f\n", this->motorCalibrationFactor );
-    chprintf((BaseSequentialStream*)&global.sercanmux1, "pGain %i\n", this->pGain );
-    chprintf((BaseSequentialStream*)&global.sercanmux1, "iGain %f\n", this->iGain );
-    chprintf((BaseSequentialStream*)&global.sercanmux1, "dGain %f\n", this->dGain );
-}
-
-void MotorControl::resetGains()
-{
-  // reset factors
-  chSysLock();
-  this->motorCalibrationFactor = 1.0f;
-  this->pGain = 1000;
-  this->iGain = 0.08f;
-  this->dGain = 0.01f;
-  chSysUnlock();
-
-  // write reset factors to memory
-  this->memory->setwheelfactor(this->motorCalibrationFactor);
-  this->memory->setpGain(this->pGain);
-  this->memory->setiGain(this->iGain);
-  this->memory->setdGain(this->dGain);
-
-  return;
-}
-
-
-
-void MotorControl::calcVelocity() {
-  // Velocity in µm/s in x direction
-  currentVelocity.x = (1.0f*wheelCircumference * (this->actualSpeed[LEFT_WHEEL] + this->actualSpeed[RIGHT_WHEEL])) / secondsPerMinute / 2.0f;
-  // Angular velocity around z in µrad/s
-  currentVelocity.w_z = (1.0f*wheelCircumference * (this->actualSpeed[RIGHT_WHEEL] - this->actualSpeed[LEFT_WHEEL])) / (1.0f*secondsPerMinute) / (wheelBaseDistanceSI*this->Eb);
-
-}
-
-
-
-void MotorControl::updateIncrements(MotorIncrements* motorIncrements, int32_t (&oldIncrement)[2], float (&incrementDifference)[2]) {
-  int32_t currentIncrement[2];
-
-  chSysLock();
-  for (uint8_t idxWheel = 0; idxWheel < 2; idxWheel++) {
-    currentIncrement[idxWheel] = motorIncrements->qeiGetPosition(idxWheel);
-  }
-  chSysUnlock();
-
-  // Calculate the difference between the last and
-  // actual increments and therefor the actual speed or distance
-  for (uint8_t idxWheel = 0; idxWheel < 2; idxWheel++) {
-
-    // Get the difference
-    int32_t tmpIncrementDifference =  oldIncrement[idxWheel] - currentIncrement[idxWheel];
-
-    // Handle overflow of increments
-    int range = motorIncrements->getQeiConfigRange();
-    if (tmpIncrementDifference > (range >> 1))
-      tmpIncrementDifference -= motorIncrements->getQeiConfigRange();
-    else if (tmpIncrementDifference < -(range >> 1))
-      tmpIncrementDifference += motorIncrements->getQeiConfigRange();
-
-    // Correct the difference
-    incrementDifference[idxWheel] =  static_cast<float>(tmpIncrementDifference) * MotorControl::wheelDiameterCorrectionFactor[idxWheel];
-
-    // Save the actual increments
-    oldIncrement[idxWheel] = currentIncrement[idxWheel];
-  }
-}
-
-void MotorControl::updateSpeed(const float (&incrementDifference)[2], int32_t (&actualSpeed)[2], const uint32_t period) {
-  const int32_t updatesPerMinute = 60 * 1000 / period;
-
-  for (uint8_t idxWheel = 0; idxWheel < 2; idxWheel++) {
-    // Save the actual speed
-    actualSpeed[idxWheel] = static_cast<int32_t>(static_cast<float>(updatesPerMinute * incrementDifference[idxWheel])) / incrementsPerRevolution;
-  }
-}
-
-void MotorControl::updateDistance(const float (&incrementDifference)[2], float (&actualDistance)[2]) {
-
-  for (uint8_t idxWheel = 0; idxWheel < 2; idxWheel++) {
-    // Calc. the distance per wheel in meter
-    actualDistance[idxWheel] = wheelCircumferenceSI * incrementDifference[idxWheel] / static_cast<float>(incrementsPerRevolution);
-  }
-}
-
-void MotorControl::writePulseWidthModulation() {
-  for (int idxWheel = 0; idxWheel < 2; idxWheel++) {
-    int percentage = this->pwmPercentage[idxWheel];
-    unsigned int widths[2];
-
-    // 10000 is the max. duty cicle
-    if (percentage > 10000) {
-      percentage = 10000;
-    } else if (percentage < -10000) {
-      percentage = -10000;
-    }
-
-    if (percentage < 0) {
-      widths[0] = 0;
-      widths[1] = PWM_PERCENTAGE_TO_WIDTH(this->pwmDriver, -percentage);
-    } else {
-      widths[0] = PWM_PERCENTAGE_TO_WIDTH(this->pwmDriver, percentage);
-      widths[1] = 0;
-    }
-
-    for (int idxPWM = 0; idxPWM < 2; idxPWM++)
-      pwmEnableChannel(this->pwmDriver, (idxWheel * 2) + idxPWM, widths[idxPWM]);
-  }
-}
diff --git a/components/MotorIncrements.cpp b/components/MotorIncrements.cpp
deleted file mode 100644
index ef6cc00..0000000
--- a/components/MotorIncrements.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <qei.h>
-
-#include <amiro/MotorIncrements.h>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-MotorIncrements::MotorIncrements(QEIDriver* qei0, QEIDriver* qei1) {
-  this->qeiDriver[0] = qei0;
-  this->qeiDriver[1] = qei1;
-
-  this->qeiConfig.mode = QEI_COUNT_BOTH;
-  this->qeiConfig.channels[0].mode = QEI_INPUT_INVERTED;
-  this->qeiConfig.channels[1].mode = QEI_INPUT_NONINVERTED;
-  this->qeiConfig.range = 0x10000;
-}
-
-void MotorIncrements::start() {
-  qeiStart(this->qeiDriver[0], &this->qeiConfig);
-  qeiStart(this->qeiDriver[1], &this->qeiConfig);
-
-  qeiEnable(this->qeiDriver[0]);
-  qeiEnable(this->qeiDriver[1]);
-}
-
-int MotorIncrements::qeiGetPosition(int idxQei) {
-  return qeiGetPositionI(this->qeiDriver[idxQei]);
-}
-
-int MotorIncrements::getQeiConfigRange() {
-  return this->qeiConfig.range;
-}
\ No newline at end of file
diff --git a/components/Odometry.cpp b/components/Odometry.cpp
deleted file mode 100644
index 2083bd1..0000000
--- a/components/Odometry.cpp
+++ /dev/null
@@ -1,250 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <qei.h>
-
-#include <amiro/Odometry.h>
-
-#include <math.h> // cos(), sin()
-#include <Matrix.h> // Matrixoperations "Matrix::*"
-#include <amiro/Constants.h> // Constants "constants::*"
-#include <chprintf.h>
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace constants::DiWheelDrive;
-
-extern Global global;
-
-
-Odometry::Odometry(MotorIncrements* mi, L3G4200D* gyroscope)
-    : BaseStaticThread<512>(),
-      motorIncrements(mi),
-      gyro(gyroscope),
-      eventSource(),
-      period(50),
-      incrementsPerRevolution(incrementsPerRevolution),
-      updatesPerMinute(constants::secondsPerMinute * constants::millisecondsPerSecond / this->period),
-      wheelCircumference(wheelCircumferenceSI),
-      wheelBaseDistanceSI(wheelBaseDistanceSI) {
-
-
-//  this-> = constants::secondsPerMinute * constants::millisecondsPerSecond / this->period;
-//  this->wheelCircumference = constants::wheelCircumferenceSI;
-//  this->wheelBaseDistanceSI = constants::wheelBaseDistanceSI;
-
-  this->distance[LEFT_WHEEL] = 0.0f;
-  this->distance[RIGHT_WHEEL] = 0.0f;
-  this->increment[LEFT_WHEEL] = 0;
-  this->increment[RIGHT_WHEEL] = 0;
-  this->incrementDifference[LEFT_WHEEL] = 0.0f;
-  this->incrementDifference[RIGHT_WHEEL] = 0.0f;
-  this->distance[LEFT_WHEEL] = 0.0f;
-  this->distance[RIGHT_WHEEL] = 0.0f;
-
-  this->wheelError[LEFT_WHEEL] = wheelErrorSI[LEFT_WHEEL];
-  this->wheelError[RIGHT_WHEEL] = wheelErrorSI[RIGHT_WHEEL];
-
-  this->resetPosition(); // Init position
-
-  this->resetError(); // Init error Cp
-
-}
-
-types::position Odometry::getPosition() {
-  types::position robotPosition;
-  const int32_t piScaled = int32_t(2 * M_PI * 1e6);
-  chSysLock();
-    // Conversion from standard unit to µ unit
-    robotPosition.x = this->pX * 1e6;
-    robotPosition.y = this->pY * 1e6;
-    robotPosition.f_z = (int32_t(this->pPhi * 1e6) % piScaled) + ((this->pPhi < 0) ? piScaled : 0);  // Get only the postitve angel f_z in [0 .. 2 * pi]
-  chSysUnlock();
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "X:%d Y:%d Phi:%d", robotPosition.x,robotPosition.y, robotPosition.f_z);
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "\r\n");
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "X:%f Y:%f Phi:%f", this->pX,this->pY, this->pPhi);
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "\r\n");
-  return robotPosition;
-}
-
-void Odometry::setPosition(float pX, float pY, float pPhi) {
-  chSysLock();
-    this->pX = pX;
-    this->pY = pY;
-    this->pPhi = pPhi;
-  chSysUnlock();
-}
-
-void Odometry::resetPosition() {
-  this->setPosition(0.0f,0.0f,0.0f);
-}
-
-void Odometry::setError(float* Cp3x3) {
-  chSysLock();
-    Matrix::copy<float>(Cp3x3,3,3, &(this->Cp3x3[0]),3,3);
-  chSysUnlock();
-}
-
-void Odometry::resetError() {
-  Matrix::init<float>(&(this->Cp3x3[0]),3,3,0.0f);
-}
-
-EvtSource* Odometry::getEventSource() {
-  return &this->eventSource;
-}
-
-msg_t Odometry::main(void) {
-  systime_t time = System::getTime();
-  this->setName("Odometry");
-
-  while (!this->shouldTerminate()) {
-    time += MS2ST(this->period);
-
-    // Update the base distance, because it may have changed after a calibration
-    this->updateWheelBaseDistance();
-
-    // Get the actual speed
-    this->updateDistance();
-
-    // Calculate the odometry
-    this->updateOdometry();
-
-
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "X:%f Y:%f Phi:%f", this->pX,this->pY, this->pPhi);
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "\r\n");
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "distance_left:%f distance_right:%f", this->distance[0],this->distance[1]);
-//     chprintf((BaseSequentialStream*) &global.sercanmux1, "\r\n");
-
-    if (time >= System::getTime()) {
-        chThdSleepUntil(time);
-    } else {
-        chprintf((BaseSequentialStream*) &global.sercanmux1, "WARNING Odometry: Unable to keep track\r\n");
-    }
-  }
-
-  return true;
-}
-
-void Odometry::updateOdometry() {
-
-  // Get the temporary position and error
-  float Cp3x3[9];
-  int32_t angular_ud;
-  int32_t angularRate_udps;
-  chSysLock();
-    float pX = this->pX;
-    float pY = this->pY;
-    float pPhi = this->pPhi;
-    Matrix::copy<float>(this->Cp3x3,3,3,Cp3x3,3,3);
-    // TODO Get the gyro (or gyro rate) information and do something with it
-    // angular_ud = gyro->getAngular_ud(L3G4200D::AXIS_Z);
-    // angularRate_udps = gyro->getAngularRate_udps(L3G4200D::AXIS_Z);
-  chSysUnlock();
-
-  ////////////////
-  // Temporary calculations
-  ////////////////
-
-  // TMP: Rotated angular
-  float dPhi = (this->distance[RIGHT_WHEEL] - this->distance[LEFT_WHEEL]) / this->wheelBaseDistanceSI;
-  // TODO Calculate the differential angel dPhi from either the angular (1. line) or angular rate (2.+3. line)
-  // float dPhi = ((float(angular_ud * 1e-3) * M_PI ) * 1e-3) / 180.0f;
-  // const float angular_md = float((angularRate_udps * this->period / constants::millisecondsPerSecond) * 1e-3);
-  // float dPhi = ((angular_md * M_PI) * 1e-3) / 180.0f;
-
-  // TMP: Moved distance
-  float dDistance = (this->distance[RIGHT_WHEEL] + this->distance[LEFT_WHEEL]) / 2.0f;
-
-  // TMP: Argument for the trigonometric functions
-  float trigArg = pPhi + dPhi / 2.0f;
-
-  // TMP: Trigonometric functions
-  float cosArg = cos(trigArg);
-  float sinArg = sin(trigArg);
-
-  // TMP: Delta distance
-  float dPX = dDistance * cosArg;
-  float dPY = dDistance * sinArg;
-
-  ////////////////
-  // Position Update
-  ////////////////
-
-  // Update distance
-  pX += dPX;
-  pY += dPY;
-  pPhi += dPhi;
-
-  ////////////////
-  // Temporary error calculations
-  ////////////////
-
-  // position propagation error (3x3 matrix)
-  float Fp3x3[9]  = {1.0f, 0.0f, -dPY,
-                     0.0f, 1.0f,  dPX,
-                     0.0f, 0.0f, 1.0f};
-  // steering error (2x2 matrix)
-  float Cs2x2[4] = {abs(this->distance[RIGHT_WHEEL])*wheelError[RIGHT_WHEEL],0.0f,
-                    0.0f, abs(this->distance[LEFT_WHEEL])*wheelError[LEFT_WHEEL]};
-  // steering propagation error (3x2 matrix)
-  float Fs3x2[6] = {(cosArg+dDistance*sinArg/this->wheelBaseDistanceSI)/2.0f, (sinArg+dDistance*cosArg/this->wheelBaseDistanceSI)/2.0f,
-                 (sinArg-dDistance*cosArg/this->wheelBaseDistanceSI)/2.0f, (cosArg-dDistance*sinArg/this->wheelBaseDistanceSI)/2.0f,
-                 -1.0f/this->wheelBaseDistanceSI                         , 1.0f/this->wheelBaseDistanceSI};
-
-  ////////////////
-  // Error calculations tmpCp = Fp*Cp*~Fp
-  ////////////////
-  // New position error
-  float tmpCp3x3[9] = {0.0f};
-  float tmpFpCp3x3[9] = {0.0f};
-  // tmpFpCp = Fp*Cp
-  Matrix::XdotY<float>(&(Fp3x3[0]),3,3,&(Cp3x3[0]),3,3,&(tmpFpCp3x3[0]),3,3);
-  // tmpCp = tmpFpCp*~Fp
-  Matrix::XdotYtrans<float>(&(tmpFpCp3x3[0]),3,3,&(Fp3x3[0]),3,3,&(tmpCp3x3[0]),3,3);
-
-  ////////////////
-  // Error calculations tmpCs = Fs*Cs*~Fs
-  ////////////////
-  // New steering error
-  float tmpCs3x3[9] = {0.0f};
-  float tmpFsCs3x2[6] = {0.0f};
-  // tmpFsCs = Fs*Cs
-  Matrix::XdotY<float>(&(Fs3x2[0]),3,2,&(Cs2x2[0]),2,2,&(tmpFsCs3x2[0]),3,2);
-  // tmpCs = tmpFsCs*~Fs
-  Matrix::XdotYtrans<float>(&(tmpFsCs3x2[0]),3,2,&(Fs3x2[0]),3,2,&(tmpCs3x3[0]),3,3);
-
-  ////////////////
-  // Error calculations Cp = Fp*Cp*~Fp + Fs*Cs*~Fs
-  ////////////////
-  Matrix::XplusY<float>(tmpCp3x3,3,3,tmpCs3x3,3,3,Cp3x3,3,3);
-
-  ////////////////
-  // Write back
-  ////////////////
-
-  // Write back
-  this->setPosition(pX,pY,pPhi);
-  chSysLock();
-    Matrix::copy<float>(Cp3x3,3,3,this->Cp3x3,3,3);
-  chSysUnlock();
-
-}
-
-void Odometry::updateWheelBaseDistance() {
-  this->wheelBaseDistanceSI = MotorControl::actualWheelBaseDistanceSI;
-}
-
-void Odometry::updateDistance() {
-
-  // Get the current increments of the QEI
-  MotorControl::updateIncrements(this->motorIncrements, this->increment, this->incrementDifference);
-//
-//  chprintf((BaseSequentialStream*) &global.sercanmux1, "\ni_right = %d \t i_left = %d", this->increment[RIGHT_WHEEL], this->increment[LEFT_WHEEL]);
-//  chprintf((BaseSequentialStream*) &global.sercanmux1, "\niDiff_right = %d \t iDiff_left = %d", this->incrementDifference[RIGHT_WHEEL], this->incrementDifference[LEFT_WHEEL]);
-
-  // Get the driven distance for each wheel
-  MotorControl::updateDistance(this->incrementDifference, this->distance);
-
-//  chprintf((BaseSequentialStream*) &global.sercanmux1, "\nx_right = %f \t x_left = %f", this->distance[RIGHT_WHEEL], this->distance[LEFT_WHEEL]);
-}
diff --git a/components/accel/lis331dlh.cpp b/components/accel/lis331dlh.cpp
deleted file mode 100644
index fb45447..0000000
--- a/components/accel/lis331dlh.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-#include <string.h>
-
-#include <amiro/util/util.h>
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/accel/lis331dlh.hpp>
-#include <chprintf.h>
-#include <cmath>  // abs()
-#include <amiro/Constants.h>
-#include <global.hpp>
-
-namespace amiro {
-
-extern Global global;
-
-LIS331DLH::
-LIS331DLH(HWSPIDriver *driver) :
-  driver(driver),
-  currentFullScaleConfiguration(FS_2G) {
-
-}
-
-LIS331DLH::
-~LIS331DLH() {
-
-}
-
-chibios_rt::EvtSource*
-LIS331DLH::
-getEventSource() {
-  return &this->eventSource;
-}
-
-int16_t
-LIS331DLH::
-getAcceleration(const uint8_t axis) {
-
-  return this->accelerations[axis];
-
-}
-
-int16_t
-LIS331DLH::
-getAccelerationForce(const uint8_t axis) {
-
-  int16_t result;
-
-  switch(this->currentFullScaleConfiguration) {
-  default:
-  case(FS_2G):
-    // Should be this->accelerations[axis] * 0.9765625
-    result = this->accelerations[axis];
-    break;
-  case(FS_4G):
-      // Should be this->accelerations[axis] * 1.953125
-      result =  this->accelerations[axis] << 1;
-    break;
-  case(FS_8G):
-      // Should be this->accelerations[axis] * 3.90625
-      result =  this->accelerations[axis] << 2;
-    break;
-  }
-
-  return result;
-
-}
-
-msg_t
-LIS331DLH::
-main() {
-
-  this->setName("Lis331dlh");
-
-  while (!this->shouldTerminate()) {
-
-    updateSensorData();
-
-    this->eventSource.broadcastFlags(0);
-
-    this->waitAnyEventTimeout(ALL_EVENTS, CAN::UPDATE_PERIOD);
-
-  }
-  return RDY_OK;
-}
-
-void
-LIS331DLH::
-updateSensorData() {
-
-  const size_t buffer_size = offsetof(LIS331DLH::registers, out_z)
-                             - offsetof(LIS331DLH::registers, status_reg)
-                             + MEMBER_SIZE(LIS331DLH::registers, out_z)
-                             + 1; /* addressing */
-  uint8_t buffer[buffer_size];
-  uint8_t sreg;
-
-  // this might be three-wire so we need to send ones
-  memset(buffer, 0xFFu, buffer_size);
-  buffer[0] = offsetof(LIS331DLH::registers, status_reg) | LIS331DLH::SPI_MULT | LIS331DLH::SPI_READ;
-  this->driver->exchange(buffer, buffer, buffer_size);
-
-  // assemble data
-  sreg = buffer[1];
-
-  if (sreg & LIS331DLH::XDA)
-    this->accelerations[LIS331DLH::AXIS_X] = int16_t((buffer[3] << 8) | buffer[2]) >> 4;
-
-  if (sreg & LIS331DLH::YDA)
-    this->accelerations[LIS331DLH::AXIS_Y] = int16_t((buffer[5] << 8) | buffer[4]) >> 4;
-
-  if (sreg & LIS331DLH::ZDA)
-    this->accelerations[LIS331DLH::AXIS_Z] = int16_t((buffer[7] << 8) | buffer[6]) >> 4;
-
-}
-
-msg_t
-LIS331DLH::
-configure(LIS331DLHConfig *config) {
-
-  const size_t ctrl_reg_size = offsetof(LIS331DLH::registers, ctrl_reg5)
-                               - offsetof(LIS331DLH::registers, ctrl_reg1)
-                               + MEMBER_SIZE(LIS331DLH::registers, ctrl_reg5)
-                               + 1; /* addressing */
-  const size_t int_reg_size = offsetof(LIS331DLH::registers, int1_duration)
-                              - offsetof(LIS331DLH::registers, int1_cfg)
-                              + MEMBER_SIZE(LIS331DLH::registers, int1_duration) /* linear interrupt config */
-                              + MEMBER_SIZE(LIS331DLH::registers, int1_src)
-                              + MEMBER_SIZE(LIS331DLH::registers, int1_src) /* 2x size of int1_src */
-                              + 1; /* addressing */
-  const size_t buffer_size = ctrl_reg_size > int_reg_size ? ctrl_reg_size : int_reg_size;
-
-  uint8_t buffer[buffer_size];
-  InterruptConfig *int_cfg = &config->int1_cfg;
-  uint8_t i;
-
-  // write interrupt config first
-  for (i = 0x00u; i < 2; i++, int_cfg++) {
-    // this might be three-wire so we need to send ones
-    memset(buffer, 0xFFu, buffer_size);
-    if (!i)
-      buffer[0] = offsetof(LIS331DLH::registers, int1_cfg);
-    else
-      buffer[0] = offsetof(LIS331DLH::registers, int2_cfg);
-    buffer[5] = buffer[0] + offsetof(LIS331DLH::registers, int1_src) - offsetof(LIS331DLH::registers, int1_cfg);
-    buffer[5] |= LIS331DLH::SPI_READ;
-    buffer[6] = 0xFFu,
-    buffer[0] |= LIS331DLH::SPI_MULT | LIS331DLH::SPI_WRITE;
-    buffer[1] = int_cfg->config;
-    buffer[2] = 0xFFu; /* skip source register */
-    buffer[3] = int_cfg->ths;
-    buffer[4] = int_cfg->duration;
-    this->driver->write(&buffer[0], 5);
-    // read intN_src register to clear IA
-    this->driver->exchange(&buffer[5], &buffer[5], 2);
-  }
-
-  // write control config
-  // this might be three-wire so we need to send ones
-  memset(buffer, 0xFFu, buffer_size);
-  buffer[0] = offsetof(LIS331DLH::registers, ctrl_reg1) | LIS331DLH::SPI_MULT | LIS331DLH::SPI_WRITE;
-  buffer[1] = config->ctrl1;
-  buffer[2] = config->ctrl2;
-  buffer[3] = config->ctrl3;
-  buffer[4] = config->ctrl4;
-  buffer[5] = config->ctrl5;
-  this->driver->write(buffer, 6);
-
-  // reset hp filter
-  buffer[0] = offsetof(LIS331DLH::registers, hp_filter_reset) | LIS331DLH::SPI_WRITE;
-  this->driver->write(buffer, 1);
-
-  // Store the full scale configuration for acceleration decoding
-  this->currentFullScaleConfiguration = config->ctrl4 & LIS331DLH::FS_8G;
-
-  return RDY_OK;
-
-}
-
-uint8_t
-LIS331DLH::
-getCheck() {
-
-  const size_t buffer_size = 1 /* addressing */
-                             + 1; /* who am i */
-  uint8_t buffer[buffer_size];
-
-  // Exchange the data with the LIS331DLH accelerometer
-  // Specify the adress and the mode
-  buffer[0] = offsetof(LIS331DLH::registers, who_am_i) | LIS331DLH::SPI_READ;
-  this->driver->exchange(buffer, buffer, buffer_size);
-  // Check
-  if (buffer[1] == LIS331DLH::LIS331DLH_ID) {
-    return LIS331DLH::CHECK_OK;
-  } else {
-    return LIS331DLH::CHECK_FAIL;
-  }
-
-}
-
-void
-LIS331DLH::
-printSelfTest(LIS331DLHConfig* config) {
-
-  // Running the build in test from LIS331DLH manual and compare the
-  // measured values against table 3
-
-  const uint8_t amountOfMeanValues = 10;
-  const uint32_t sleepBetweenMeasurementMs = 500;
-  int32_t accel;
-
-  // Choose a defined config, if none is given
-  LIS331DLH::LIS331DLHConfig test_accel_run_cfg;
-  if (config == NULL) {
-    LIS331DLH::LIS331DLHConfig accel_run_cfg_tmp = {
-    /* ctrl1    */LIS331DLH::PM_ODR | LIS331DLH::DR_50HZ_37LP | LIS331DLH::ZEN
-        | LIS331DLH::YEN | LIS331DLH::XEN,
-    /* ctrl2    */0x00u,
-    /* ctrl3    */LIS331DLH::INT_LOW | LIS331DLH::I1_CFG_DRY,
-    /* ctrl4    */LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE | LIS331DLH::FS_8G
-        | LIS331DLH::SIM_4WI,
-    /* ctrl5    */LIS331DLH::SLEEP_TO_WAKE_OFF,
-    /* int1_cfg */
-    {
-    /* config   */LIS331DLH::AOI_OR_INT,
-    /* ths      */0x00u,
-    /* duration */0x00u, },
-    /* int2_cfg */
-    {
-    /* config   */LIS331DLH::AOI_OR_INT,
-    /* ths      */0x00u,
-    /* duration */0x00u, }, };
-    test_accel_run_cfg = accel_run_cfg_tmp;
-  } else {
-    // Save the given config
-    test_accel_run_cfg = *config;
-  }
-
-  // 1. Get some standard values
-  // Configure for the test
-  test_accel_run_cfg.ctrl4 = LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE
-      | LIS331DLH::FS_2G | LIS331DLH::SIM_4WI;
-  this->configure(&test_accel_run_cfg);
-  BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
-  // Grep some values and build the mean value
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\nACC: Get acc std values\n");
-  int32_t stdAccValues[3] = { this->getAcceleration(LIS331DLH::AXIS_X), this
-      ->getAcceleration(LIS331DLH::AXIS_Y), this->getAcceleration(
-      LIS331DLH::AXIS_Z) };
-
-  for (uint8_t n = 1; n < amountOfMeanValues; ++n) {
-    BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
-    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
-      accel = int32_t(this->getAcceleration(i));
-      stdAccValues[i] = (stdAccValues[i] * n + accel) / (n + 1);
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%c%d:%d ", accel < 0 ? '-' : '+',
-                accel < 0 ? -accel : accel, stdAccValues[i]);
-    }
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-  }
-
-  // 2. Apply negative offset
-  // Configure for the test
-  test_accel_run_cfg.ctrl4 = LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE
-      | LIS331DLH::FS_2G | LIS331DLH::SIM_4WI | LIS331DLH::ST_ENABLE
-      | LIS331DLH::STSIGN_NEG;
-  this->configure(&test_accel_run_cfg);
-  BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
-  // Grep some values and build the mean value
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\nACC: Get acc neg values\n");
-  int16_t negAccValues[3] = { this->getAcceleration(LIS331DLH::AXIS_X), this
-      ->getAcceleration(LIS331DLH::AXIS_Y), this->getAcceleration(
-      LIS331DLH::AXIS_Z) };
-
-  for (uint8_t n = 1; n < amountOfMeanValues; ++n) {
-    BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
-    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
-      accel = int32_t(this->getAcceleration(i));
-      negAccValues[i] = (negAccValues[i] * n + accel) / (n + 1);
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%c%d:%d ", accel < 0 ? '-' : '+',
-                accel < 0 ? -accel : accel, negAccValues[i]);
-    }
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-  }
-
-  // 2. Apply positive offset
-  // Configure for the test
-  test_accel_run_cfg.ctrl4 = LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE
-      | LIS331DLH::FS_2G | LIS331DLH::SIM_4WI | LIS331DLH::ST_ENABLE
-      | LIS331DLH::STSIGN_POS;
-  this->configure(&test_accel_run_cfg);
-  BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
-  // Grep some values and build the mean value
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\nACC: Get acc pos values\n");
-  int16_t posAccValues[3] = { this->getAcceleration(LIS331DLH::AXIS_X), this
-      ->getAcceleration(LIS331DLH::AXIS_Y), this->getAcceleration(
-      LIS331DLH::AXIS_Z) };
-
-  for (uint8_t n = 1; n < amountOfMeanValues; ++n) {
-    BaseThread::sleep(MS2ST(sleepBetweenMeasurementMs));
-    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
-      accel = int32_t(this->getAcceleration(i));
-      posAccValues[i] = (posAccValues[i] * n + accel) / (n + 1);
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%c%d:%d ", accel < 0 ? '-' : '+',
-                accel < 0 ? -accel : accel, posAccValues[i]);
-    }
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-  }
-
-  // Get the amplitude change and compare it to the standard values from LIS331DLH manual table 3
-  int32_t amp;
-  const int32_t ampXmax = 550, ampYmax = 550, ampZmax = 750;
-  const int32_t ampXmin = 120, ampYmin = 120, ampZmin = 140;
-
-  // TEST
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\n\nACC: Testresult\n");
-  amp = std::abs(
-      stdAccValues[LIS331DLH::AXIS_X] - negAccValues[LIS331DLH::AXIS_X]);
-  if (amp < ampXmin || amp > ampXmax)
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "ACC: Negative x-axis faulty\n");
-  amp = std::abs(
-      stdAccValues[LIS331DLH::AXIS_Y] - negAccValues[LIS331DLH::AXIS_Y]);
-  if (amp < ampYmin || amp > ampYmax)
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "ACC: Negative y-axis faulty\n");
-  amp = std::abs(
-      stdAccValues[LIS331DLH::AXIS_Z] - negAccValues[LIS331DLH::AXIS_Z]);
-  if (amp < ampZmin || amp > ampZmax)
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "ACC: Negative z-axis faulty\n");
-  amp = std::abs(
-      stdAccValues[LIS331DLH::AXIS_X] - posAccValues[LIS331DLH::AXIS_X]);
-  if (amp < ampXmin || amp > ampXmax)
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "ACC: Positive x-axis faulty\n");
-  amp = std::abs(
-      stdAccValues[LIS331DLH::AXIS_Y] - posAccValues[LIS331DLH::AXIS_Y]);
-  if (amp < ampYmin || amp > ampYmax)
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "ACC: Positive y-axis faulty\n");
-  amp = std::abs(
-      stdAccValues[LIS331DLH::AXIS_Z] - posAccValues[LIS331DLH::AXIS_Z]);
-  if (amp < ampZmin || amp > ampZmax)
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "ACC: Positive z-axis faulty\n");
-
-  // Write back the original config
-  this->configure(config);
-}
-
-} /* amiro */
diff --git a/components/bluetooth/bluetooth-connector.cpp b/components/bluetooth/bluetooth-connector.cpp
deleted file mode 100644
index 0f7ba25..0000000
--- a/components/bluetooth/bluetooth-connector.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <string.h>
-#include <chprintf.h>
-
-#include <amiro/bluetooth/bluetooth-connector.hpp>
-#include <amiro/bluetooth/bluetooth-serial.hpp>
-#include <amiro/bluetooth/bluetooth-wiimote.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-/*
- * Class constructor
- */
-BluetoothConnector::BluetoothConnector(BLUETOOTH *bluetooth, void *bluetoothDev, const char *typeConn) {
-  iwrap = &(bluetooth->iwrap);
-  objDev = bluetoothDev;
-  typeDev = typeConn;
-}
-
-//----------------------------------------------------------------
-
-
-void BluetoothConnector::bluetoothConnectorListen(const char *addr) {
-  BluetoothProfile profile;
-  profile.addr = (strstr(addr, "ALL")) ? "free" : addr;
-  profile.connector = this;
-  profile.connect = &BluetoothConnector::bluetoothConnectorActivate;
-  profile.disconnect = &BluetoothConnector::bluetoothConnectorDeactivate;
-  profile.linkid = 0xFF;
-
-  /* Listen all address can have only one profile at the last profile,
-     otherwise a fixed address will take it at first */
-  if (strstr(addr, "ALL") && (iwrap->profiles[7].addr == NULL)) {
-    iwrap->profiles[7] = profile;
-    return;
-  }
-
-  for(int i = 0; i < 8; i++) {
-    if(iwrap->profiles[i].addr == NULL) {
-      iwrap->profiles[i] = profile;
-      break;
-    }
-  }
-}
-
-void BluetoothConnector::bluetoothConnectorConnect(const char *addr) {
-  int size = strlen(addr) + 17;
-  char cmd[size];
-  strcpy(cmd, "CALL ");
-  strcat(cmd, addr);
-
-  for (int i = 0; i < 8; i++) {
-    if (strstr(iwrap->profiles[i].addr, addr) && (iwrap->profiles[i].linkid == 0xFF)) {
-      switch (typeDev[0]) {
-      case 'S':           // 'S' for "SERIAL"
-        strcat(cmd, " 1101 RFCOMM");
-        break;
-      case 'W':           // 'W' for "WIIMOTE"
-        strcat(cmd, " 0013 L2CAP ");
-        break;
-      }
-      iwrap->bluetoothIwrapSendCommand(cmd);
-      BaseThread::sleep(MS2ST(1000));    // waiting connection establish
-      break;
-    }
-  }
-}
-
-void BluetoothConnector::bluetoothConnectorDisconnect(const char *addr) {
-  char cmd[8];
-  strcpy(cmd, "CLOSE ");
-
-  for (int i = 0; i < 8; i++) {
-    if (strstr(iwrap->profiles[i].addr, addr) && (iwrap->profiles[i].linkid != 0xFF)) {
-      cmd[6] = iwrap->profiles[i].linkid + 0x30;
-      cmd[7]= '\0';
-      iwrap->bluetoothIwrapSendCommand(cmd);
-      BaseThread::sleep(MS2ST(2000));    // waiting disconnection
-      break;
-    }
-  }
-}
-
-void BluetoothConnector::bluetoothConnectorActivate(uint8_t linkid) {
-  if (strstr(typeDev, "SERIAL"))
-    ((BluetoothSerial *) objDev)->bluetoothSerialStart(linkid);
-  else
-    ((BluetoothWiimote *) objDev)->bluetoothWiimoteStart(linkid);
-}
-
-void BluetoothConnector::bluetoothConnectorDeactivate() {
-  if (strstr(typeDev, "SERIAL"))
-    ((BluetoothSerial *) objDev)->bluetoothSerialStop();
-  else
-    ((BluetoothWiimote *) objDev)->bluetoothWiimoteStop();
-}
diff --git a/components/bluetooth/bluetooth-descriptor.cpp b/components/bluetooth/bluetooth-descriptor.cpp
deleted file mode 100644
index cb425b7..0000000
--- a/components/bluetooth/bluetooth-descriptor.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/bluetooth/bluetooth-descriptor.hpp>
-
-
-using namespace chibios_rt;
-using namespace amiro;
-
-
-BluetoothDescriptor::BluetoothDescriptor() :
-  linkId(0), length(0), buffer{0} {
-}
-
-//----------------------------------------------------------------
-
-
-void BluetoothDescriptor::bluetoothDescriptorSetLinkId(uint8_t linkId) {
-  this->linkId = linkId;
-}
-
-void BluetoothDescriptor::bluetoothDescriptorSetPayloadLength(size_t length) {
-  this->length = length;
-}
-
-uint8_t BluetoothDescriptor::bluetoothDescriptorGetLinkId() {
-  return this->linkId;
-}
-
-size_t BluetoothDescriptor::bluetoothDescriptorGetBufferLength() {
-  return sizeof(this->buffer);
-}
-
-size_t BluetoothDescriptor::bluetoothDescriptorGetPayloadLength() {
-  return this->length;
-}
-
-uint8_t* BluetoothDescriptor::bluetoothDescriptorGetBuffer() {
-  return this->buffer;
-}
-
-uint8_t* BluetoothDescriptor::bluetoothDescriptorGetPayload() {
-  return this->buffer;
-}
diff --git a/components/bluetooth/bluetooth-iwrap.cpp b/components/bluetooth/bluetooth-iwrap.cpp
deleted file mode 100644
index e1c7bb4..0000000
--- a/components/bluetooth/bluetooth-iwrap.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <string.h>
-
-#include <amiro/bluetooth/bluetooth-iwrap.hpp>
-#include <amiro/bluetooth/bluetooth-connector.hpp>
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-extern Global global;
-
-/*
- * Class constructor
- */
-BluetoothIwrap::BluetoothIwrap(UARTDriver* uart) :
-  BaseStaticThread<128>(), transport(uart), profiles{},
-  mailbox(mailboxBuffer, BLUETOOTH_IWRAP_MAILBOX_SIZE), connAddr{0} {
-  iwrapblock = 0;
-}
-
-//----------------------------------------------------------------
-
-msg_t BluetoothIwrap::main(void) {
-  setName("BluetoothIwrap");
-
-  // To set the receive mailbox[9] for plain communication (WT12->host)
-  transport.bluetoothTransportSetReceiveMailbox(HOST_IWRAP_PLAIN_LINKID, &this->mailbox);
-
-  transport.start(NORMALPRIO);
-
-  while (!this->shouldTerminate()) {
-    iwrapReceive();
-  }
-  return RDY_OK;
-}
-
-/*
- * Member functions
- */
-msg_t BluetoothIwrap::iwrapReceive() {
-  BluetoothDescriptor* descriptor = NULL;
-  const char* buffer;
-  size_t length;
-  msg_t msg;
-
-  msg = mailbox.fetch((msg_t*) &descriptor, TIME_INFINITE);
-  if (msg == RDY_RESET)
-    return RDY_RESET;
-
-  buffer = (const char*)descriptor->bluetoothDescriptorGetPayload();
-  length = descriptor->bluetoothDescriptorGetPayloadLength();
-
-  for (size_t i = 0; i < length; i++) {
-    // print out received chars
-    chSequentialStreamPut((BaseSequentialStream*) &global.sercanmux1, buffer[i]);
-  }
-
-  // reset block
-  iwrapblock = 0;
-
-  // if RING or CONNECT event is received, then look for profile with correct MAC-address and connect.
-  if (strstr(buffer, "CONNECT ") && (strstr(buffer, " RFCOMM 1") || strstr(buffer, " L2CAP 1"))) {
-  // if CONNECT event serial RFCOMM 1 or wiimote (control) L2CAP 11 or wiimote (data) L2CAP 13
-    for (int i = 0; i < 8; i++) {
-      if ((profiles[i].addr != NULL) && strstr(connAddr, profiles[i].addr)) {
-        BluetoothProfile* bp =  &(profiles[i]);
-        bp->linkid = buffer[8] - '0';     // look for linkid and convert linkid to int
-        (((BluetoothConnector*)(bp->connector))->*(bp->connect))(bp->linkid);
-        break;
-      }
-    }
-  } else if (strstr(buffer, "RING") && strstr(buffer, "1 RFCOMM ")) {
-  // if RING event (be called by other device) in 1 RFCOMM mode
-    for (int i = 0; i < 8; i++) {
-      if ((profiles[i].addr != NULL) && (strstr(buffer, profiles[i].addr) || strstr(profiles[i].addr, "free"))) {
-        BluetoothProfile* bp =  &(profiles[i]);
-        bp->linkid  = buffer[5] - '0';    // look for linkid and convert linkid to int
-        (((BluetoothConnector*)(bp->connector))->*(bp->connect))(bp->linkid );
-        break;
-      }
-    }
-  } else if (strstr(buffer, "NO CARRIER ") && strstr(buffer, "ERROR ")) {
-  // if NO CARRIER ERROR 0 event, then look for profile and disconnect
-    uint8_t linkid = buffer[11] - '0';
-    for (int i = 0; i < 8; i++) {
-      if ((profiles[i].addr != NULL) && (profiles[i].linkid == linkid)) {
-        BluetoothProfile* bp =  &(profiles[i]);
-        bp->linkid = 0xFF;
-        (((BluetoothConnector*)(bp->connector))->*(bp->disconnect))();
-        break;
-      }
-    }
-  }
-
-  msg = (transport.bluetoothTransportGetStorageMailbox())->post((msg_t) descriptor, TIME_INFINITE);
-  if (msg == RDY_RESET)
-    return RDY_RESET;
-
-  return RDY_OK;
-}
-
-msg_t BluetoothIwrap::iwrapTransmit(uint8_t linkid, const uint8_t* txdata, size_t length) {
-  BluetoothDescriptor* descriptor = NULL;
-  uint8_t *buffer;
-  msg_t msg;
-
-  msg = transport.bluetoothTransportGetStorageMailbox()->fetch((msg_t*) &descriptor, TIME_INFINITE);
-  if (msg == RDY_RESET)
-    return RDY_RESET;
-
-  buffer = descriptor->bluetoothDescriptorGetPayload();
-  memcpy(buffer, txdata, length);
-
-  descriptor->bluetoothDescriptorSetLinkId(linkid);
-  descriptor->bluetoothDescriptorSetPayloadLength(length);
-
-  msg = transport.bluetoothTransportGetTransmitMailbox()->post((msg_t) descriptor, TIME_INFINITE);
-  if (msg == RDY_RESET)
-    return RDY_RESET;
-
-  return RDY_OK;
-}
-
-void BluetoothIwrap::bluetoothIwrapSendCommand(const char* cmd) {
-  // Wait until another previous command finished.
-  while(iwrapblock == 1) {
-    BaseThread::sleep(MS2ST(500));
-  }
-
-  iwrapblock = 1;
-
-  if (strstr(cmd, "CALL ") && (strstr(cmd, " RFCOMM") || strstr(cmd, " L2CAP"))) {
-    memcpy(connAddr, cmd+5, 17);
-  }
-
-  size_t length = strlen(cmd);
-//  for (size_t i = 0; i < length; i++)
-//    chSequentialStreamPut((BaseSequentialStream*) &global.sercanmux1, cmd[i]);   // To display the command
-
-  // To send the string command to WT12 bluetooth chip
-  iwrapTransmit(HOST_IWRAP_PLAIN_LINKID,(uint8_t*) cmd, length);
-
-  // Clear iwrapblock flag because these commands don't return an answer
-  if(strstr(cmd, "SET BT NAME") || strstr(cmd, "SET BT AUTH") || strstr(cmd, "SET BT SSP")
-    || strstr(cmd, "SET BT PAGEMODE") || strstr(cmd, "SET BT PAIR *")
-    || strstr(cmd, "SET CONTROL MUX") || (strstr(cmd, "SET") && strlen(cmd) == 3)) {
-    iwrapblock = 0;
-  }
-
-  BaseThread::sleep(MS2ST(500));
-}
diff --git a/components/bluetooth/bluetooth-serial.cpp b/components/bluetooth/bluetooth-serial.cpp
deleted file mode 100644
index b554d17..0000000
--- a/components/bluetooth/bluetooth-serial.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/bluetooth/bluetooth-serial.hpp>
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-extern Global global;
-
-/*
- * Class constructor
- */
-BluetoothSerial::BluetoothSerial(BLUETOOTH *bluetooth, uint8_t rxtx) :
-  BaseStaticThread<128>(), serialConn(bluetooth, this, "SERIAL"),
-  mailbox(mailboxBuffer, BLUETOOTH_SERIAL_MAILBOX_SIZE) {
-  iwrap = &(bluetooth->iwrap);
-  rx_tx = rxtx;
-  linkId = 0xFF;
-  stopflag = 0;
-}
-
-//----------------------------------------------------------------
-
-msg_t BluetoothSerial::main(void) {
-  setName("BluetoothSerial");
-
-  while (!this->shouldTerminate()) {
-    if (serialReceive())
-      this->requestTerminate();
-  }
-  return RDY_OK;
-}
-
-/*
- * Member functions
- */
-msg_t BluetoothSerial::serialReceive() {
-  BluetoothDescriptor* recv_descriptor = NULL;
-  uint8_t *buffer;
-  size_t length;
-  msg_t msg;
-
-  msg = mailbox.fetch((msg_t*) &recv_descriptor, TIME_INFINITE);
-  if ((msg == RDY_RESET) || stopflag)
-    return RDY_RESET;
-
-  buffer = recv_descriptor->bluetoothDescriptorGetPayload();
-  length = recv_descriptor->bluetoothDescriptorGetPayloadLength();
-
-  for (size_t i = 0; i < length; i++)
-    chSequentialStreamPut((BaseSequentialStream*) &global.sercanmux1, buffer[i]);
-
-  msg = iwrap->transport.bluetoothTransportGetStorageMailbox()->post((msg_t) recv_descriptor, TIME_INFINITE);
-  if ((msg == RDY_RESET) || stopflag)
-    return RDY_RESET;
-
-  return RDY_OK;
-}
-
-msg_t BluetoothSerial::serialTransmit(const uint8_t* serialdata, size_t length) {
-  msg_t msg;
-
-  if ((rx_tx & 0x01) && (linkId != 0xFF) && (!stopflag))
-    msg = iwrap->iwrapTransmit(linkId, serialdata, length);
-  else
-    msg = RDY_RESET;
-
-  return msg;
-}
-
-void BluetoothSerial::bluetoothSerialStart(uint8_t linkid) {
-  linkId = linkid;
-  iwrap->transport.bluetoothTransportSetReceiveMailbox(linkId, &this->mailbox);
-
-  if ((rx_tx & 0x02)) { // && (!stopflag)) {
-    this->start(NORMALPRIO);
-  }
-  stopflag = 0;
-}
-
-void BluetoothSerial::bluetoothSerialStop() {
-  linkId = 0xFF;
-  stopflag = 1;
-  mailbox.post(RDY_RESET, TIME_INFINITE);        // TIME_IMMEDIATE TIME_INFINITE
-}
-
-bool BluetoothSerial::bluetoothSerialIsConnected() {
-  if (linkId == 0xFF)
-    return false;
-
-  return true;
-}
-
-void BluetoothSerial::bluetoothSerialListen(const char *addr) {
-  serialConn.bluetoothConnectorListen(addr);
-}
-
-void BluetoothSerial::bluetoothSerialConnect(const char *addr){
-  serialConn.bluetoothConnectorConnect(addr);
-}
-
-void BluetoothSerial::bluetoothSerialDisconnect(const char *addr) {
-  serialConn.bluetoothConnectorDisconnect(addr);
-}
diff --git a/components/bluetooth/bluetooth-transport.cpp b/components/bluetooth/bluetooth-transport.cpp
deleted file mode 100644
index 1b8a740..0000000
--- a/components/bluetooth/bluetooth-transport.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <uart.h>
-#include <chprintf.h>
-
-#include <amiro/bluetooth/bluetooth-transport.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-/*
- * Class constructor
- */
-BluetoothTransport::BluetoothTransport(UARTDriver* uart) :
-  BaseStaticThread<128>(), UARTConfig(), uart(uart), receiveMailbox{NULL},
-  storageMailbox(storageMailboxBuffer, BLUETOOTH_TRANSPORT_STORAGE_MAILBOX_SIZE),
-  transmitMailbox(transmitMailboxBuffer, BLUETOOTH_TRANSPORT_TRANSMIT_MAILBOX_SIZE) {
-
-  UARTConfig::txend1_cb = bluetoothTransportTransmitCompleted_cb;
-  UARTConfig::txend2_cb = NULL;
-  UARTConfig::rxend_cb  = bluetoothTransportReceiveCompleted_cb;
-  UARTConfig::rxchar_cb = bluetoothTransportCharacterReceived_cb;
-  UARTConfig::rxerr_cb  = NULL;
-  speed = 115200;
-  cr1   = 0;
-  cr2   = 0;
-  cr3   = 0;
-
-  transmitState = BLUETOOTH_TRANSPORT_PLAIN;
-  receiveState = BLUETOOTH_TRANSPORT_PLAIN;
-
-  transmit = NULL;
-  receive = NULL;
-}
-
-//----------------------------------------------------------------
-
-msg_t BluetoothTransport::main(void) {
-  setName("BluetoothTransport");
-
-  for (int i = 0; i < BLUETOOTH_TRANSPORT_STORAGE_MAILBOX_SIZE; i++)
-    storageMailbox.post((msg_t) &descriptor[i], TIME_INFINITE);
-
-  BaseThread::sleep(MS2ST(200));
-  uartStart(uart, this);
-
-  while (!this->shouldTerminate()) {
-
-    if (!this->transmitMailbox.fetch((msg_t *) &transmit, TIME_INFINITE)) {
-
-      if (!transmit->bluetoothDescriptorGetPayloadLength()) {
-        storageMailbox.post((msg_t) transmit, TIME_INFINITE);
-            continue;
-      }
-
-      if (transmitState == BLUETOOTH_TRANSPORT_PLAIN) {
-        uint8_t* buffer = transmit->bluetoothDescriptorGetPayload();
-        size_t length = transmit->bluetoothDescriptorGetPayloadLength();
-
-        memcpy(buffer+length, "\r\n", 2);
-
-        uartStartSend(uart, length + 2, buffer);
-      } else {
-        transmitState = BLUETOOTH_TRANSPORT_PAYLOAD;
-        uartStartSend(uart, FRAME_HEADER_SIZE, getEncodeHeader());
-      }
-      waitAnyEvent((eventmask_t) TRANSMIT_COMPLETED_EVENT);
-    }
-  }
-  return RDY_OK;
-}
-
-/*
- * Interrupt callback handlers
- */
-void BluetoothTransport::bluetoothTransportTransmitCompleted_cb(UARTDriver *uart) {
-  BluetoothTransport *u = (BluetoothTransport *) uart->config;
-  u->bluetoothTransportTransmitCompleted();
-}
-
-void BluetoothTransport::bluetoothTransportTransmitCompleted() {
-  switch (transmitState) {
-    case BLUETOOTH_TRANSPORT_PLAIN: {
-      postTransmitDescriptorI();
-
-      System::lockFromIsr();
-      signalEventsI((eventmask_t) TRANSMIT_COMPLETED_EVENT);
-      System::unlockFromIsr();
-      break;
-    }
-    case BLUETOOTH_TRANSPORT_HEADER: {
-      System::lockFromIsr();
-      uartStartSendI(uart, FRAME_HEADER_SIZE, getEncodeHeader());
-      System::unlockFromIsr();
-      transmitState = BLUETOOTH_TRANSPORT_PAYLOAD;
-      /* no break */
-    }
-    case BLUETOOTH_TRANSPORT_PAYLOAD: {
-      System::lockFromIsr();
-      uartStartSendI(uart, transmit->bluetoothDescriptorGetPayloadLength(), transmit->bluetoothDescriptorGetPayload());
-      System::unlockFromIsr();
-      transmitState = BLUETOOTH_TRANSPORT_TRAILER;
-      break;
-    }
-    case BLUETOOTH_TRANSPORT_TRAILER: {
-      postTransmitDescriptorI();
-
-      System::lockFromIsr();
-      uartStartSendI(uart, FRAME_TRAILER_SIZE, getEncodeTailer());
-
-      // check whether any new transmision in the mailbox during the present tranmmision
-      msg_t msg = transmitMailbox.fetchI((msg_t *) &transmit);
-      System::unlockFromIsr();
-
-      if (msg == RDY_OK) {
-        if (transmit->bluetoothDescriptorGetPayloadLength()) {
-          transmitState = BLUETOOTH_TRANSPORT_HEADER;
-        } else {
-          postTransmitDescriptorI();
-          transmitState = BLUETOOTH_TRANSPORT_IDLE;
-        }
-      } else {
-        transmitState = BLUETOOTH_TRANSPORT_IDLE;
-      }
-      break;
-    }
-    case BLUETOOTH_TRANSPORT_IDLE: {
-      System::lockFromIsr();
-      signalEventsI((eventmask_t) TRANSMIT_COMPLETED_EVENT);
-      System::unlockFromIsr();
-      break;
-    }
-    default: {
-      break;
-    }
-  }
-}
-
-void BluetoothTransport::bluetoothTransportCharacterReceived_cb(UARTDriver *uart, uint16_t c) {
-  BluetoothTransport *u = (BluetoothTransport *) uart->config;
-  u->bluetoothTransportCharacterReceived(c);
-}
-
-void BluetoothTransport::bluetoothTransportCharacterReceived(uint16_t c) {
-  if (c == 0xbf) {
-    receiveFrameBuffer[1] = 0xbf;
-    System::lockFromIsr();
-    uartStartReceiveI(uart, 3, (void *) &receiveFrameBuffer[2]);
-    System::unlockFromIsr();
-
-    receiveState = BLUETOOTH_TRANSPORT_DECODE;
-    if (transmitState == BLUETOOTH_TRANSPORT_PLAIN)
-      transmitState = BLUETOOTH_TRANSPORT_IDLE;
-  }
-
-  if (receiveState != BLUETOOTH_TRANSPORT_PLAIN)
-    return;
-
-  if (!receive) {
-    System::lockFromIsr();
-    msg_t msg = storageMailbox.fetchI((msg_t *) &receive);
-    System::unlockFromIsr();
-
-    if (msg)
-      return;
-
-    receive->bluetoothDescriptorSetLinkId(0xFF);
-    rcvlength = 0;
-  }
-
-  uint8_t* buffer = receive->bluetoothDescriptorGetPayload();
-  buffer[rcvlength++] = c;
-
-  if (rcvlength == receive->bluetoothDescriptorGetBufferLength() || c == '\n') {
-    receive->bluetoothDescriptorSetPayloadLength(rcvlength);
-    postReceiveDescriptorI();
-  }
-}
-
-void BluetoothTransport::bluetoothTransportReceiveCompleted_cb(UARTDriver *uart) {
-  BluetoothTransport *u = (BluetoothTransport *) uart->config;
-  u->bluetoothTransportReceiveCompleted();
-}
-
-void BluetoothTransport::bluetoothTransportReceiveCompleted() {
-  switch (receiveState) {
-    case BLUETOOTH_TRANSPORT_HEADER: {
-      if ((uint8_t) ~receiveFrameBuffer[0] != receive->bluetoothDescriptorGetLinkId()) {
-        receiveState = BLUETOOTH_TRANSPORT_IDLE;
-        break;
-      }
-      System::lockFromIsr();
-      uartStartReceiveI(uart, 4, (void *) &receiveFrameBuffer[1]);
-      System::unlockFromIsr();
-
-      receiveState = BLUETOOTH_TRANSPORT_DECODE;
-      break;
-    }
-    case BLUETOOTH_TRANSPORT_DECODE: {
-      if (decodeHeader()) {
-        receiveState = BLUETOOTH_TRANSPORT_IDLE;
-        break;
-      }
-      receiveState = BLUETOOTH_TRANSPORT_PAYLOAD;
-      /* no break */
-    }
-    case BLUETOOTH_TRANSPORT_PAYLOAD: {
-      if (receive)
-        postReceiveDescriptorI();
-
-      System::lockFromIsr();
-      msg_t msg = storageMailbox.fetchI((msg_t *) &receive);
-      System::unlockFromIsr();
-
-      if (msg) {
-        receiveState = BLUETOOTH_TRANSPORT_IDLE;
-        break;
-      }
-
-      receive->bluetoothDescriptorSetLinkId(receiveFrameBuffer[2]);
-      if (rcvlength > receive->bluetoothDescriptorGetBufferLength())
-        receive->bluetoothDescriptorSetPayloadLength(receive->bluetoothDescriptorGetBufferLength());
-      else
-        receive->bluetoothDescriptorSetPayloadLength(rcvlength);
-
-      System::lockFromIsr();
-      uartStartReceiveI(uart, receive->bluetoothDescriptorGetPayloadLength(), receive->bluetoothDescriptorGetPayload());
-      System::unlockFromIsr();
-
-      rcvlength -= receive->bluetoothDescriptorGetPayloadLength();
-
-      if (!rcvlength)
-        receiveState = BLUETOOTH_TRANSPORT_TRAILER;
-
-      break;
-    }
-    case BLUETOOTH_TRANSPORT_TRAILER: {
-      postReceiveDescriptorI();
-
-      System::lockFromIsr();
-      uartStartReceiveI(uart, 1, (void *) &receiveFrameBuffer[0]);
-      System::unlockFromIsr();
-
-      receiveState = BLUETOOTH_TRANSPORT_HEADER;
-      break;
-    }
-    default: {
-      break;
-    }
-  }
-}
-
-/*
- * Member functions
- */
-
-void BluetoothTransport::bluetoothTransportResetState() {
-  transmitState = BLUETOOTH_TRANSPORT_PLAIN;
-  receiveState = BLUETOOTH_TRANSPORT_PLAIN;
-}
-
-bool BluetoothTransport::bluetoothTransportIsMuxMode() {
-  if (receiveState == BLUETOOTH_TRANSPORT_PLAIN)
-    return false;
-
-  return true;
-}
-
-chibios_rt::Mailbox* BluetoothTransport::bluetoothTransportGetStorageMailbox() {
-  return &storageMailbox;
-}
-
-chibios_rt::Mailbox* BluetoothTransport::bluetoothTransportGetTransmitMailbox() {
-  return &transmitMailbox;
-}
-
-void BluetoothTransport::bluetoothTransportSetReceiveMailbox(uint8_t linkId, chibios_rt::Mailbox* mailbox) {
-  System::lock();
-  receiveMailbox[(linkId > 9) ? 9 : linkId] = mailbox;
-  System::unlock();
-}
-
-void BluetoothTransport::postReceiveDescriptorI() {
-  uint8_t linkId = receive->bluetoothDescriptorGetLinkId();
-  linkId > 9 ? linkId = 9 : linkId;
-
-  System::lockFromIsr();
-  msg_t msg = receiveMailbox[linkId]->postI((msg_t) receive);
-  if (msg)
-    storageMailbox.postI((msg_t) receive);
-  receive = NULL;
-  System::unlockFromIsr();
-}
-
-void BluetoothTransport::postTransmitDescriptorI() {
-  System::lockFromIsr();
-  storageMailbox.postI((msg_t) transmit);
-  transmit = NULL;
-  System::unlockFromIsr();
-}
-
-/*
- * The header encode/decode are in compliance with of the multiplexing mode
- * Reference: iWRAP4 user guide Version 4.1 page 142-143
- */
-uint8_t*  BluetoothTransport::getEncodeHeader() {
-  transmitFrameBuffer[1] = 0xbf;
-  transmitFrameBuffer[2] = transmit->bluetoothDescriptorGetLinkId();
-  transmitFrameBuffer[3] = (transmit->bluetoothDescriptorGetPayloadLength() >> 8) & 0x3;
-  transmitFrameBuffer[4] = transmit->bluetoothDescriptorGetPayloadLength() & 0xFF;
-  return &transmitFrameBuffer[1];
-}
-
-uint8_t* BluetoothTransport::getEncodeTailer() {
-  transmitFrameBuffer[0] = ~transmitFrameBuffer[2];
-  return &transmitFrameBuffer[0];
-}
-
-int BluetoothTransport::decodeHeader() {
-  if ((receiveFrameBuffer[1] != 0xbf) ||
-    ((receiveFrameBuffer[2] > 8) && (receiveFrameBuffer[2] != 0xFF)))
-    return -1;
-
-  rcvlength = (receiveFrameBuffer[3] << 8) | receiveFrameBuffer[4];
-  if (rcvlength > 1023)
-    return -1;
-
-  return RDY_OK;
-}
diff --git a/components/bluetooth/bluetooth-wiimote.cpp b/components/bluetooth/bluetooth-wiimote.cpp
deleted file mode 100644
index a8939b6..0000000
--- a/components/bluetooth/bluetooth-wiimote.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/bluetooth/bluetooth-wiimote.hpp>
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-extern Global global;
-
-/*
- * Class constructor
- */
-BluetoothWiimote::BluetoothWiimote(BLUETOOTH *bluetooth, uint8_t rxtx) :
-  BaseStaticThread<128>(), wiimoteConn(bluetooth, this, "WIIMOTE"),
-  mailbox(mailboxBuffer, BLUETOOTH_WIIMOTE_MAILBOX_SIZE), accelerometer{0,0,0} {
-  iwrap = &(bluetooth->iwrap);
-  rx_tx = rxtx;
-  linkId = 0xFF;
-  stopflag = 0;
-}
-
-//----------------------------------------------------------------
-
-msg_t BluetoothWiimote::main(void) {
-  setName("BluetoothWiimote");
-
-  while (!this->shouldTerminate()) {
-    if (wiimoteReceive())
-      this->requestTerminate();
-  }
-  return RDY_OK;
-}
-
-/*
- * Member functions
- */
-msg_t BluetoothWiimote::wiimoteReceive() {
-  BluetoothDescriptor* recv_descriptor = NULL;
-  uint8_t *buffer;
-  size_t length;
-  msg_t msg;
-
-  msg = mailbox.fetch((msg_t*) &recv_descriptor, TIME_INFINITE);
-  if ((msg == RDY_RESET) || stopflag)
-    return RDY_RESET;
-
-  buffer = recv_descriptor->bluetoothDescriptorGetPayload();
-  length = recv_descriptor->bluetoothDescriptorGetPayloadLength();
-
-  if (buffer[0] == 0xA1 && (buffer[1] == 0x30 || buffer[1] == 0x31)) {
-      buttons.left  = (buffer[2] & 0x01) ? 1 : 0;
-      buttons.right = (buffer[2] & 0x02) ? 1 : 0;
-      buttons.down  = (buffer[2] & 0x04) ? 1 : 0;
-      buttons.up    = (buffer[2] & 0x08) ? 1 : 0;
-      buttons.plus  = (buffer[2] & 0x10) ? 1 : 0;
-      buttons.two   = (buffer[3] & 0x01) ? 1 : 0;
-      buttons.one   = (buffer[3] & 0x02) ? 1 : 0;
-      buttons.B     = (buffer[3] & 0x04) ? 1 : 0;
-      buttons.A     = (buffer[3] & 0x08) ? 1 : 0;
-      buttons.minus = (buffer[3] & 0x10) ? 1 : 0;
-      buttons.home  = (buffer[3] & 0x80) ? 1 : 0;
-
-      accelerometer.x_axis = (buffer[4] << 2) + ((buffer[2] & 0x60) >> 5) - 0x1FF;
-      accelerometer.y_axis = (buffer[5] << 2) + ((buffer[3] & 0x20) >> 4) - 0x1FF;
-      accelerometer.z_axis = (buffer[6] << 2) + ((buffer[3] & 0x40) >> 5) - 0x1FF;
-
-      bluetoothWiimoteDataBtnAcc();
-  } else {
-    chSequentialStreamWrite((BaseSequentialStream*) &global.sercanmux1, buffer, length);
-  }
-
-  msg = iwrap->transport.bluetoothTransportGetStorageMailbox()->post((msg_t) recv_descriptor, TIME_INFINITE);
-  if ((msg == RDY_RESET) || stopflag)
-    return RDY_RESET;
-
-  return RDY_OK;
-}
-
-msg_t BluetoothWiimote::wiimoteTransmit(const uint8_t* wiimotecmd, size_t length) {
-  msg_t msg;
-
-  if ((rx_tx & 0x01) && (linkId != 0xFF) && (!stopflag))
-    msg = iwrap->iwrapTransmit(linkId, wiimotecmd, length);
-  else
-    msg = RDY_RESET;
-
-  return msg;
-}
-
-void BluetoothWiimote::bluetoothWiimoteStart(uint8_t linkid) {
-  linkId = linkid;
-  iwrap->transport.bluetoothTransportSetReceiveMailbox(linkId, &this->mailbox);
-
-  if ((rx_tx & 0x02)) {   // && (!stopflag)
-    this->start(NORMALPRIO);
-  }
-  stopflag = 0;
-}
-
-void BluetoothWiimote::bluetoothWiimoteStop() {
-  linkId = 0xFF;
-  stopflag = 1;
-  mailbox.post(RDY_RESET, TIME_INFINITE);        // TIME_IMMEDIATE TIME_INFINITE
-}
-
-bool BluetoothWiimote::bluetoothWiimoteIsConnected() {
-  if (linkId == 0xFF)
-    return false;
-
-  return true;
-}
-
-void BluetoothWiimote::bluetoothWiimoteListen(const char *addr) {
-  wiimoteConn.bluetoothConnectorListen(addr);
-}
-
-void BluetoothWiimote::bluetoothWiimoteConnect(const char *addr) {
-  wiimoteConn.bluetoothConnectorConnect(addr);
-}
-
-void BluetoothWiimote::bluetoothWiimoteDisconnect(const char *addr) {
-  wiimoteConn.bluetoothConnectorDisconnect(addr);
-}
-
-BluetoothWiimote::Accelerometer * BluetoothWiimote::getAccelerometer() {
-  return &accelerometer;
-}
-
-BluetoothWiimote::Buttons * BluetoothWiimote::getButtons() {
-  return &buttons;
-}
-
-/*
- * @brief :  On-off LEDs and Motor of Wiimote.
- *
- * @param[in] ledid_flag     On-off flag of LEDs 1,2,3,4
- *                           (LED1: 0x10, LED2: 0x20, LED3: 0x40, LED4: 0x80)
- * @param[in] vibrate_flag   On-off flag of Vibration Motor (On: 1, off: 0)
- */
-void BluetoothWiimote::bluetoothWiimoteLedVibrate(uint8_t ledid_flag, uint8_t vibrate_flag) {
-  const uint8_t data[] = {0xA2, 0x11, (uint8_t) (ledid_flag | vibrate_flag)};
-  wiimoteTransmit(data, 3);
-}
-
-/*
- * @brief :  Show status information of Wiimote.
- */
-void BluetoothWiimote::bluetoothWiimoteStatusInfo() {
-  const uint8_t data[] = {0xA2, 0x15, 0x00};
-  wiimoteTransmit(data, 3);
-}
-
-/*
- * @brief :  Send button status (change event) of Wiimote.
- */
-void BluetoothWiimote::bluetoothWiimoteDataBtn() {
-  const uint8_t data[] = {0xA2, 0x12, 0x00, 0x30};
-  wiimoteTransmit(data, 4);
-}
-
-/*
- * @brief :  Send button & accelerometer status (change event) of Wiimote.
- */
-void BluetoothWiimote::bluetoothWiimoteDataBtnAcc() {
-  const uint8_t data[] = {0xA2, 0x12, 0x00, 0x31};
-  wiimoteTransmit(data, 4);
-}
diff --git a/components/bluetooth/bluetooth.cpp b/components/bluetooth/bluetooth.cpp
deleted file mode 100644
index d3e8bf9..0000000
--- a/components/bluetooth/bluetooth.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <string.h>
-
-#include <amiro/bluetooth/bluetooth.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-/*
- * Class constructor
- */
-BLUETOOTH::BLUETOOTH(UARTDriver* uart) : iwrap(uart) {
-}
-
-/*
- * Member functions
- */
-void BLUETOOTH::bluetoothStart() {
-  iwrap.start(NORMALPRIO);
-  BaseThread::sleep(MS2ST(1000));
-  // Reset bluetooth chip to get the first msg. (cmd/data mode or mux Mode)
-  bluetoothReset();
-}
-
-void BLUETOOTH::bluetoothReset() {
-  palWritePad(GPIOC, GPIOC_BT_RST, 1);
-  BaseThread::sleep(MS2ST(10));
-  palWritePad(GPIOC, GPIOC_BT_RST, 0);
-  iwrap.transport.bluetoothTransportResetState();
-    BaseThread::sleep(MS2ST(1000));
-}
-
-void BLUETOOTH::bluetoothEnableMux() {
-  iwrap.bluetoothIwrapSendCommand("SET CONTROL MUX 1");
-}
-
-void BLUETOOTH::bluetoothDisableMux() {
-  iwrap.bluetoothIwrapSendCommand("SET CONTROL MUX 0");
-}
-
-void BLUETOOTH::bluetoothDiscoverDevices() {
-  iwrap.bluetoothIwrapSendCommand("INQUIRY 5");
-  BaseThread::sleep(MS2ST(6000));
-}
-
-void BLUETOOTH::bluetoothListAllConnections() {
-  iwrap.bluetoothIwrapSendCommand("List");
-}
-
-void BLUETOOTH::bluetoothSetName(const char *name) {
-  int size = strlen(name) + 14;
-  char cmd[size];
-  strcpy(cmd, "SET BT NAME ");
-  strcat(cmd, name);
-  iwrap.bluetoothIwrapSendCommand(cmd);
-}
-
-void BLUETOOTH::bluetoothSetPin(const char *pin) {
-  int size = strlen(pin) + 15;
-  char cmd[size];
-  strcpy(cmd, "SET BT AUTH * ");
-  strcat(cmd, pin);
-  iwrap.bluetoothIwrapSendCommand(cmd);
-}
-
-void BLUETOOTH::bluetoothCloseConnection(uint8_t linkid) {
-  char cmd[8];
-  strcpy(cmd, "CLOSE ");
-  cmd[6] = linkid + '0';
-  cmd[7]= '\0';
-  iwrap.bluetoothIwrapSendCommand(cmd);
-}
-
-void BLUETOOTH::bluetoothSendCommand(const char *cmd) {
-  iwrap.bluetoothIwrapSendCommand(cmd);
-}
-
-bool BLUETOOTH::bluetoothIsMuxMode() {
-  return iwrap.transport.bluetoothTransportIsMuxMode();
-}
diff --git a/components/bluetooth/checkutility.cpp b/components/bluetooth/checkutility.cpp
deleted file mode 100644
index 6cf0ff5..0000000
--- a/components/bluetooth/checkutility.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-#include <amiro/bluetooth/checkutility.hpp>
-
-#include <chprintf.h>
-#include <hal.h>
-
-#include <cstring>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-WT12CheckUtility::WT12CheckUtility()
-{}
-
-WT12CheckUtility::~WT12CheckUtility()
-{}
-
-void
-WT12CheckUtility::reset()
-{
-  palWritePad(GPIOC, GPIOC_BT_RST, PAL_HIGH);
-  BaseThread::sleep(MS2ST(10));
-  palWritePad(GPIOC, GPIOC_BT_RST, PAL_LOW);
-
-  return;
-}
-
-bool
-WT12CheckUtility::waitForReady(const bool print)
-{
-  char buffer[8];
-  const uint16_t length = this->receiveMessage(buffer, 8);
-
-  if (print) {
-    msgPrint(buffer, length);
-  }
-
-  return (strcmp(buffer, "READY.\r\n") == 0);
-}
-
-uint8_t
-WT12CheckUtility::selftest()
-{
-  return 0;
-}
-
-void
-WT12CheckUtility::msgPrint(const char* message, const uint16_t length)
-{
-  if (length > 0)
-  {
-    chSequentialStreamWrite((BaseSequentialStream*)&global.sercanmux1, (uint8_t*)message, length);
-//    chprintf((BaseSequentialStream*) &global.sercanmux1, "[%d]\n", length);
-  }
-  return;
-}
-
-void
-WT12CheckUtility::msgPrintMulti(const char* message_buf, const uint16_t* length_buf, const uint16_t num_messages)
-{
-  uint16_t pos = 0;
-  for (uint16_t i = 0; i < num_messages; ++i)
-  {
-    this->msgPrint(&message_buf[pos], length_buf[i]);
-    pos += length_buf[i];
-  }
-
-  return;
-}
-
-void
-WT12CheckUtility::sendMessage(char* message, uint8_t link_id)
-{
-  const uint16_t length = strlen(message);
-  if (length >= 1 << 10) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: message too long!\n", __FILE__ , __LINE__);
-    return;
-  }
-
-  Message msg;
-  msg.head.start_of_frame = MUX_StartOfFrame;
-  msg.head.link_id = link_id;
-  msg.head.flags = 0x00u;
-  msg.head.length = length;
-  msg.message = message;
-  msg.n_link = ~link_id;
-
-  chSequentialStreamPut((BaseSequentialStream*)&SD3, msg.head.start_of_frame);
-  chSequentialStreamPut((BaseSequentialStream*)&SD3, msg.head.link_id);
-  chSequentialStreamPut((BaseSequentialStream*)&SD3, msg.head.flags | (msg.head.length >> 8));
-  chSequentialStreamPut((BaseSequentialStream*)&SD3, msg.head.length & 0xFFu);
-  chSequentialStreamWrite((BaseSequentialStream*)&SD3, (uint8_t*)msg.message, msg.head.length);
-  chSequentialStreamPut((BaseSequentialStream*)&SD3, msg.n_link);
-
-  return;
-}
-
-void
-WT12CheckUtility::sendMessageRaw(const char* message)
-{
-  chSequentialStreamWrite((BaseSequentialStream*)&SD3, (uint8_t*)message, strlen(message));
-  return;
-}
-
-uint16_t
-WT12CheckUtility::receiveMessage(char* message, const uint16_t max_length)
-{
-  Message msg;
-  msg.message = message;
-
-  msg.head.start_of_frame = chSequentialStreamGet((BaseSequentialStream*)&SD3);
-  msg.head.link_id = chSequentialStreamGet((BaseSequentialStream*)&SD3);
-  msg.head.flags = chSequentialStreamGet((BaseSequentialStream*)&SD3);
-  msg.head.length = (msg.head.flags & 0x03u) << 8;
-  msg.head.flags = msg.head.flags >> 2;
-  msg.head.length += uint8_t(chSequentialStreamGet((BaseSequentialStream*)&SD3));
-
-  if (msg.head.length > max_length)
-  {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: message too long (%d of max %d bytes)!\n", __FILE__ , __LINE__, msg.head.length, max_length);
-
-    for (uint16_t i = 0; i < msg.head.length; ++i) {
-      chSequentialStreamGet((BaseSequentialStream*)&SD3);
-    }
-    msg.head.length = 0;
-  }
-  else
-  {
-    chSequentialStreamRead((BaseSequentialStream*)&SD3, (uint8_t*)msg.message, msg.head.length);
-  }
-
-  msg.n_link = chSequentialStreamGet((BaseSequentialStream*)&SD3);
-
-  if (uint8_t(msg.head.link_id ^ msg.n_link) != 0xFFu)
-  {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: message link id does not match (0x%02X vs 0x%02X)!\n", __FILE__ , __LINE__, msg.head.link_id, msg.n_link);
-  }
-
-  return msg.head.length;
-}
-
-uint16_t
-WT12CheckUtility::receiveMessages(char* message_buf, const uint16_t msg_buf_size, uint16_t* length_buf, const uint16_t len_buf_size, const char* last_msg, const char* filter_in, const char* filter_out)
-{
-  if (msg_buf_size == 0 || len_buf_size == 0) {
-    return 0;
-  }
-
-  for (uint16_t i = 0; i < len_buf_size; ++i) {
-    length_buf[i] = 0;
-  }
-
-  uint16_t msg_pos = 0;
-  uint16_t msg_count = 0;
-  while (true)
-  {
-    length_buf[msg_count] = this->receiveMessage(&message_buf[msg_pos], msg_buf_size-msg_pos);
-
-//    if (msg_count >= 0) {
-//      msgPrint(&message_buf[msg_pos], length_buf[msg_count]);
-//    }
-
-    if (length_buf[msg_count] == 0) {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): WARNING: receiving aborted after %d messages (%d bytes)\n", __FILE__ , __LINE__, msg_count, msg_pos);
-      return msg_count;
-    }
-
-    if (strncmp(&message_buf[msg_pos], last_msg, strlen(last_msg)) == 0) {
-      return msg_count+1;
-    }
-
-    if (strncmp(&message_buf[msg_pos], filter_in, strlen(filter_in)) == 0)
-    {
-      if (filter_out == NULL || strncmp(&message_buf[msg_pos], filter_out, strlen(filter_out)) != 0)
-      {
-        msg_pos += length_buf[msg_count];
-        ++msg_count;
-      }
-    }
-
-    if (msg_count > len_buf_size) {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: maximum messages received (%d)!\n", __FILE__ , __LINE__, len_buf_size);
-      return len_buf_size;
-    }
-
-  }
-
-  return 0xFFFFu; // unreachable
-}
-
-void
-WT12CheckUtility::receiveRaw(uint8_t* buffer, uint16_t num_bytes, const bool print)
-{
-  uint16_t i;
-
-  for (i = 0; i < num_bytes; ++i)
-  {
-    buffer[i] = chSequentialStreamGet((BaseSequentialStream*)&SD3);
-  }
-
-  if (print)
-  {
-    for (i = 0; i < num_bytes; ++i)
-    {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%02X ", buffer[i]);
-    }
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-  }
-
-  return;
-}
-
-void
-WT12CheckUtility::receiveRawLine(const bool print)
-{
-  uint8_t byte = 0;;
-  while (byte != '\n')
-  {
-    byte = chSequentialStreamGet((BaseSequentialStream*) &SD3);
-    if (print) {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "%c", byte);
-    }
-  }
-
-  return;
-}
-
-void
-WT12CheckUtility::clearMessageBuffer(const bool print)
-{
-  uint8_t byte;
-  while (!sdGetWouldBlock(&SD3))
-  {
-    byte = sdGet(&SD3);
-    //byte = chSequentialStreamGet((BaseSequentialStream*) &SD3);
-    if (print) {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "0x%02X <%c>\n", byte, byte);
-    }
-    BaseThread::sleep(MS2ST(1));
-  }
-
-  return;
-}
-
diff --git a/components/bus/i2c/HWI2CDriver.cpp b/components/bus/i2c/HWI2CDriver.cpp
deleted file mode 100644
index 2c99e32..0000000
--- a/components/bus/i2c/HWI2CDriver.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#include <amiro/bus/i2c/I2CParams.hpp>
-#include <amiro/bus/i2c/HWI2CDriver.hpp>
-
-namespace amiro {
-
-
-HWI2CDriver::
-HWI2CDriver(::I2CDriver *d) :
-  driver(d) {
-
-};
-
-void
-HWI2CDriver::
-start(const ::I2CConfig *config) {
-
-  i2cStart(this->driver, config);
-
-};
-
-void
-HWI2CDriver::
-stop() {
-
-  i2cStop(this->driver);
-
-}
-
-i2cflags_t
-HWI2CDriver::
-getErrors() {
-
-  return i2cGetErrors(this->driver);
-
-}
-
-msg_t
-HWI2CDriver::
-masterTransmit(const I2CTxParams *params, systime_t timeout) {
-
-  return i2cMasterTransmitTimeout(
-                                  this->driver,
-                                  params->addr,
-                                  params->txbuf,
-                                  params->txbytes,
-                                  params->rxbuf,
-                                  params->rxbytes,
-                                  timeout);
-
-}
-
-msg_t
-HWI2CDriver::
-masterReceive(const I2CRxParams *params, systime_t timeout) {
-
-  return i2cMasterReceiveTimeout(
-                                 this->driver,
-                                 params->addr,
-                                 params->rxbuf,
-                                 params->rxbytes,
-                                 timeout);
-
-}
-
-void
-HWI2CDriver::
-acquireBus() {
-
-#if I2C_USE_MUTUAL_EXCLUSION
-  i2cAcquireBus(this->driver);
-#endif /* I2C_USE_MUTUAL_EXCLUSION */
-}
-
-void
-HWI2CDriver::
-releaseBus() {
-
-#if I2C_USE_MUTUAL_EXCLUSION
-  i2cReleaseBus(this->driver);
-#endif /* I2C_USE_MUTUAL_EXCLUSION */
-
-}
-
-} /* amiro */
diff --git a/components/bus/i2c/I2CMultiplexer.cpp b/components/bus/i2c/I2CMultiplexer.cpp
deleted file mode 100644
index aab0f3f..0000000
--- a/components/bus/i2c/I2CMultiplexer.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#include <amiro/bus/i2c/I2CMultiplexer.hpp>
-
-namespace amiro {
-
-I2CMultiplexer::
-I2CMultiplexer(I2CDriver *driver) :
-  driver(driver) {
-
-#if CH_USE_MUTEXES
-  chMtxInit(&this->mutex);
-#else
-  chSemInit(&this->semaphore, 1);
-#endif /* CH_USE_MUTEXES */
-
-};
-
-I2CMultiplexer::
-~I2CMultiplexer() {
-
-}
-
-i2cflags_t
-I2CMultiplexer::
-getErrors() {
-
-  return this->driver->getErrors();
-
-}
-
-msg_t
-I2CMultiplexer::
-masterTransmit(const I2CTxParams *params, systime_t timeout) {
-
-  return this->driver->masterTransmit(params, timeout);
-
-}
-
-msg_t
-I2CMultiplexer::
-masterReceive(const I2CRxParams *params, systime_t timeout) {
-
-  return this->driver->masterReceive(params, timeout);
-
-}
-
-void
-I2CMultiplexer::
-acquireBus() {
-
-#if CH_USE_MUTEXES
-  chMtxLock(&this->mutex);
-#elif CH_USE_SEMAPHORES
-  chSemWait(&this->semaphore);
-#endif
-
-  this->driver->acquireBus();
-}
-
-void
-I2CMultiplexer::
-releaseBus() {
-
-  this->driver->releaseBus();
-
-#if CH_USE_MUTEXES
-  chMtxUnlock();
-#elif CH_USE_SEMAPHORES
-  chSemSignal(&this->semaphore);
-#endif
-
-}
-
-} /* amiro */
diff --git a/components/bus/i2c/VI2CDriver.cpp b/components/bus/i2c/VI2CDriver.cpp
deleted file mode 100644
index 7f40874..0000000
--- a/components/bus/i2c/VI2CDriver.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <chdebug.h>
-#include <amiro/bus/i2c/I2CMultiplexer.hpp>
-#include <amiro/bus/i2c/VI2CDriver.hpp>
-
-namespace amiro {
-
-VI2CDriver::
-VI2CDriver(I2CMultiplexer *driver, const uint8_t bus_id) :
-  driver(driver),
-  id(bus_id) {
-
-#if CH_USE_MUTEXES
-  chMtxInit(&this->mutex);
-#else
-  chSemInit(&this->semaphore, 1);
-#endif /* CH_USE_MUTEXES */
-
-};
-
-
-void
-VI2CDriver::
-start(const I2CConfig* config) {
-
-  /* silently discard config */
-  (void) config;
-  /* ignore starts */
-
-}
-
-void
-VI2CDriver::
-stop() {
-
-  /* ignore stops */
-
-}
-
-i2cflags_t
-VI2CDriver::
-getErrors() {
-
-  return this->driver->getErrors();
-
-}
-
-msg_t
-VI2CDriver::
-masterTransmit(const I2CTxParams *params, systime_t timeout) {
-
-  msg_t ret;
-
-  this->driver->acquireBus();
-
-  if (!(ret = this->driver->select(this->id))) {
-    ret = this->driver->masterTransmit(params, timeout);
-  }
-
-  this->driver->deselect();
-  this->driver->releaseBus();
-
-  return ret;
-}
-
-msg_t
-VI2CDriver::
-masterReceive(const I2CRxParams *params, systime_t timeout) {
-
-  msg_t ret;
-
-  this->driver->acquireBus();
-
-  if (!(ret = this->driver->select(this->id)))
-    ret = this->driver->masterReceive(params, timeout);
-
-  this->driver->deselect();
-  this->driver->releaseBus();
-
-  return ret;
-
-}
-
-
-void
-VI2CDriver::
-acquireBus() {
-
-#if CH_USE_MUTEXES
-  chMtxLock(&this->mutex);
-#elif CH_USE_SEMAPHORES
-  chSemWait(&this->semaphore);
-#endif
-
-}
-
-void
-VI2CDriver::
-releaseBus() {
-
-#if CH_USE_MUTEXES
-  chMtxUnlock();
-#elif CH_USE_SEMAPHORES
-  chSemSignal(&this->semaphore);
-#endif
-
-}
-
-}
-/* amiro */
diff --git a/components/bus/i2c/mux/pca9544.tpp b/components/bus/i2c/mux/pca9544.tpp
deleted file mode 100644
index c121b85..0000000
--- a/components/bus/i2c/mux/pca9544.tpp
+++ /dev/null
@@ -1,118 +0,0 @@
-#include <chdebug.h>
-
-namespace amiro {
-
-template <bool ignore_deselect>
-PCA9544<ignore_deselect>::
-PCA9544(I2CDriver *driver, const uint8_t master_id) :
-	I2CMultiplexer(driver),
-	master_id(master_id),
-	selected(-1) {
-
-	chDbgCheck(master_id <= 0x07u, "PCA9544 ctor master_id");
-	this->tx_params.addr = (PCA9544::SLA | this->master_id);
-	this->rx_params.addr = (PCA9544::SLA | this->master_id);
-
-}
-
-template <bool ignore_deselect>
-msg_t
-PCA9544<ignore_deselect>::
-select(const uint8_t bus_id) {
-
-	chDbgCheck(bus_id <= 0x03u, "PCA9544 select bus_id");
-
-	uint8_t tmp = PCA9544::BUS_ON | bus_id;
-
-	if (bus_id == this->selected)
-		return RDY_OK;
-
-	this->selected = bus_id;
-
-	this->tx_params.txbuf = &tmp;
-	this->tx_params.txbytes = 1;
-	this->tx_params.rxbytes = 0;
-	return this->masterTransmit(&this->tx_params); // TODO select timeout
-
-}
-
-template <>
-inline msg_t
-PCA9544<true>::
-deselect() {
-
-	return RDY_OK;
-
-}
-
-template <>
-inline msg_t
-PCA9544<false>::
-deselect() {
-
-	uint8_t tmp = PCA9544::BUS_OFF;
-
-	this->selected = -1;
-	this->tx_params.txbuf = &tmp;
-	this->tx_params.txbytes = 1;
-	this->tx_params.rxbytes = 0;
-	return this->masterTransmit(&this->tx_params); // TODO select timeout
-
-}
-
-template <bool ignore_deselect>
-uint8_t
-PCA9544<ignore_deselect>::
-getInterruptSource() {
-
-	uint8_t tmp;
-	this->rx_params.rxbuf = &tmp;
-	this->rx_params.rxbytes = 1;
-	this->masterReceive(&this->rx_params); // TODO select timeout
-	return tmp;
-
-}
-
-template <bool ignore_deselect>
-uint8_t
-PCA9544<ignore_deselect>::
-getCheck(void) {
-
-	const int8_t rxBufferMask = 0x07; /** We are only intrested in the first three bits*/
-	int8_t txBuffer, resTx, resRx;
-	uint8_t rxBuffer[2];
-
-	// Copy the data, because some virtual driver can write into it
-	I2CTxParams tx_params = this->tx_params;
-	I2CRxParams rx_params = this->rx_params;
-
-	tx_params.txbuf = (uint8_t*) &txBuffer;
-	tx_params.txbytes = 1;
-	tx_params.rxbytes = 0;
-	rx_params.rxbuf = rxBuffer;
-	rx_params.rxbytes = 2; /** This is a bug workaround: 1 byte is impossible to read*/
-
-	for (txBuffer = rxBufferMask; txBuffer >= 0x00; txBuffer--) {
-		this->acquireBus();
-		resTx = this->masterTransmit(&tx_params);
-		resRx = this->masterReceive(&rx_params);
-		this->releaseBus();
-		// Failed to transmit
-		if (resTx != RDY_OK || resRx != RDY_OK) {
-			break;
-		}
-		// Check data written to MUX register
-		if (txBuffer != (rxBuffer[0] & rxBufferMask)) {
-			break;
-		}
-	}
-
-	// Data analysis
-	if (txBuffer != -1) {
-		return PCA9544::CHECK_FAIL;
-	} else {
-		return PCA9544::CHECK_OK;
-	}
-}
-
-} /* amiro */
diff --git a/components/bus/spi/HWSPIDriver.cpp b/components/bus/spi/HWSPIDriver.cpp
deleted file mode 100644
index b33ab2a..0000000
--- a/components/bus/spi/HWSPIDriver.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#include <hal.h>
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-
-using namespace chibios_rt;
-
-namespace amiro {
-
-HWSPIDriver::
-HWSPIDriver(::SPIDriver *driver, const ::SPIConfig *config) :
-  driver(driver),
-  config(config) {
-
-}
-
-HWSPIDriver::
-~HWSPIDriver() {
-
-
-}
-
-void
-HWSPIDriver::
-exchange(uint8_t *readData, const uint8_t *writeData, size_t length) {
-  spiAcquireBus(this->driver);
-  spiStart(this->driver, this->config);
-  spiSelect(this->driver);
-  spiExchange(this->driver, length, writeData, readData);
-  spiUnselect(this->driver);
-  spiReleaseBus(this->driver);
-}
-
-void
-HWSPIDriver::
-read(uint8_t *data, size_t length) {
-  spiAcquireBus(this->driver);
-  spiStart(this->driver, this->config);
-  spiSelect(this->driver);
-  spiReceive(this->driver, length, data);
-  spiUnselect(this->driver);
-  spiReleaseBus(this->driver);
-}
-
-void
-HWSPIDriver::
-write(const uint8_t *data, size_t length) {
-  spiAcquireBus(this->driver);
-  spiStart(this->driver, this->config);
-  spiSelect(this->driver);
-  spiSend(this->driver, length, data);
-  spiUnselect(this->driver);
-  spiReleaseBus(this->driver);
-}
-
-} /* amiro */
diff --git a/components/eeprom/at24.cpp b/components/eeprom/at24.cpp
deleted file mode 100644
index 0db4e9a..0000000
--- a/components/eeprom/at24.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <type_traits>
-
-#include <amiro/bus/i2c/I2CDriver.hpp>
-#include <amiro/bus/i2c/I2CParams.hpp>
-
-#include <amiro/eeprom/at24.hpp>
-
-#define AT24_GET_PAGE_OFFSET(_ADDRESS_, _PAGE_SIZE_) (_ADDRESS_ & (_PAGE_SIZE_ - 1u))
-
-namespace amiro {
-
-const struct BaseFileStreamVMT eeprom_at24_base_file_stream_methods = {
-
-    /* .write       */ AT24::write,
-    /* .read        */ AT24::read,
-    /* .put         */ 0,
-    /* .get         */ 0,
-    /* .close       */ AT24::close,
-    /* .geterror    */ EEPROM::geterror,
-    /* .getsize     */ EEPROM::getsize,
-    /* .getposition */ EEPROM::getposition,
-    /* .lseek       */ EEPROM::lseek,
-
-};
-
-AT24::
-AT24(size_t size, uint8_t page_size, uint16_t max_t_wr, I2CDriver* i2c_driver) :
-  EEPROM(&eeprom_at24_base_file_stream_methods, size, page_size, max_t_wr, AT24_SLA, i2c_driver) {
-
-}
-
-AT24::
-~AT24() {
-
-}
-
-msg_t
-AT24::
-poll_ack(void* instance) {
-
-  EEPROM* bfs = (EEPROM*) instance;
-
-  register I2CDriver* bfs_i2c_driver = bfs->i2c_driver;
-  register msg_t ret_val = RDY_OK;
-  register i2cflags_t i2c_err_flags;
-
-  uint8_t dummy_buf[2];
-
-  I2CRxParams i2c_rxparams;
-  i2c_rxparams.addr = bfs->i2c_txparams.addr;
-  i2c_rxparams.rxbuf = dummy_buf;
-  i2c_rxparams.rxbytes = sizeof(dummy_buf);
-
-  for (register uint16_t wr_time = 0x0000u; wr_time < bfs->max_t_wr; wr_time++) {
-
-    bfs_i2c_driver->acquireBus();
-
-    ret_val = bfs_i2c_driver->masterReceive(&i2c_rxparams);
-
-    i2c_err_flags = bfs->i2c_driver->getErrors();
-
-    bfs_i2c_driver->releaseBus();
-
-    // Wait cycle over
-    if (ret_val == RDY_OK)
-      break;
-
-    // Check for errors, ignoring only I2CD_ACK_FAILURE
-    if (i2c_err_flags & ~I2CD_ACK_FAILURE) {
-      break;
-    }
-
-    chThdSleepMicroseconds(10);
-
-  }
-
-  // This can only be the case when
-  // * timeout reached
-  // * i2cError other than I2CD_ACK_FAILURE within time limit
-  if (ret_val != RDY_OK)
-    bfs->error = i2c_err_flags;
-
-  return ret_val;
-
-}
-
-
-size_t
-AT24::
-write(void* instance, const uint8_t* bp, size_t n) {
-
-  EEPROM* bfs = (EEPROM*) instance;
-
-  i2cflags_t i2c_err_flags;
-  uint8_t i;
-  uint8_t j;
-  uint8_t scratchpad[2 + AT24_MAX_PAGE_SIZE];
-  msg_t ret_val = RDY_OK;
-  fileoffset_t cur_pos = bfs->position;
-
-  register size_t tx_bytes;
-  register const uint8_t* ptr = bp;
-  register size_t num_bytes;
-  register uint8_t page_size = bfs->page_size;
-  register I2CTxParams* bfs_i2c_txparams = &bfs->i2c_txparams;
-
-  // If no bytes are to be written, shortcut stop
-  if (!n)
-    return 0;
-
-  // Clear error
-  bfs->error = EEPROM_ERROR_NONE;
-
-#if HAL_USE_I2C
-
-  // number of bytes remaining in page starting at cur_pos
-  // b/c of address rollover withing current page
-  tx_bytes = AT24_GET_PAGE_OFFSET(cur_pos, page_size);
-  // adjust for AT24_MAX_PAGE_SIZE < page_size
-  tx_bytes = AT24_MAX_PAGE_SIZE - AT24_GET_PAGE_OFFSET(tx_bytes, AT24_MAX_PAGE_SIZE);
-
-  for (num_bytes = n; num_bytes > 0;) {
-
-    // write address
-    i = 0;
-    // Support for 16bit-addressable devices
-    if (bfs->size > 0x0080u)
-      scratchpad[i++] = (cur_pos >> 8) & 0xFFu;
-
-    scratchpad[i++] = cur_pos & 0xFFu;
-
-    // adjust number of bytes to transfer if end of buffer
-    if (num_bytes < tx_bytes)
-      tx_bytes = num_bytes;
-
-    // copy data
-    for (j = 0; j < tx_bytes; j++) {
-      scratchpad[i++] = *ptr++;
-    }
-
-    // acknowledge polling
-
-    // acknowledge polling and
-    // address device
-    for (register uint16_t wr_time = 0x0000u; wr_time < bfs->max_t_wr; wr_time++) {
-
-      bfs->i2c_driver->acquireBus();
-
-      bfs_i2c_txparams->txbuf = scratchpad;
-      bfs_i2c_txparams->txbytes = i;
-      bfs_i2c_txparams->rxbytes = 0;
-
-      ret_val = bfs->i2c_driver->masterTransmit(bfs_i2c_txparams);
-
-      i2c_err_flags = bfs->i2c_driver->getErrors();
-
-      bfs->i2c_driver->releaseBus();
-
-      // Write cycle over
-      if (ret_val == RDY_OK)
-        break;
-
-      // Check for errors, ignoring only I2CD_ACK_FAILURE
-      if (i2c_err_flags & ~I2CD_ACK_FAILURE) {
-        break;
-      }
-
-      chThdSleepMicroseconds(10);
-
-    }
-
-    // This can only be the case when
-    // * timeout reached
-    // * i2cError other than I2CD_ACK_FAILURE within time limit
-    if (ret_val != RDY_OK)
-      break;
-
-    cur_pos += tx_bytes;
-    num_bytes -= tx_bytes;
-    tx_bytes = AT24_MAX_PAGE_SIZE;
-
-  }
-
-  if (ret_val != RDY_OK)
-    bfs->error = i2c_err_flags;
-
-#endif
-
-  bfs->position = cur_pos;
-
-  // number of bytes to transfer - number of bytes not transferred
-  return n - num_bytes;
-
-}
-
-size_t
-AT24::
-read(void* instance, uint8_t* bp, size_t n) {
-
-  EEPROM* bfs = (EEPROM*) instance;
-
-  uint8_t i;
-  uint8_t scratchpad[2];
-  msg_t ret_val;
-  register I2CTxParams* bfs_i2c_txparams = &bfs->i2c_txparams;
-
-  // If no bytes are to be read, shortcut stop
-  if (!n)
-    return 0;
-
-  // Clear error
-  bfs->error = EEPROM_ERROR_NONE;
-
-#if HAL_USE_I2C
-
-  // Fill address buffer
-  i = 0;
-  // Support for 16bit-addressable devices
-  if (bfs->size > 0x0080u)
-    scratchpad[i++] = (bfs->position >> 8) & 0xFFu;
-
-  scratchpad[i++] = bfs->position & 0xFFu;
-
-  // if device does not answer within timeout, don't read anything
-  if (poll_ack(bfs) != RDY_OK)
-    return 0;
-
-  bfs->i2c_driver->acquireBus();
-
-  bfs_i2c_txparams->txbuf = scratchpad;
-  bfs_i2c_txparams->txbytes = i;
-  bfs_i2c_txparams->rxbuf = bp;
-  bfs_i2c_txparams->rxbytes = n;
-
-  // address device
-  // and read data
-  ret_val = bfs->i2c_driver->masterTransmit(bfs_i2c_txparams);
-
-  if (ret_val != RDY_OK)
-    bfs->error = bfs->i2c_driver->getErrors();
-
-  bfs->i2c_driver->releaseBus();
-
-  // We cannot tell where I²C transfer went wrong
-  // therefore report 0 bytes read
-  if (ret_val != RDY_OK)
-    return 0;
-
-#endif
-
-  return n;
-
-}
-
-/**
- * Close EEPROM device.
- * \note EEPROMs do not support close semantics.
- * \return FILE_OK Closing an EEPROM device will never fail.
- */
-uint32_t
-AT24::
-close(void* instance) {
-
-  (void) instance;
-  return FILE_OK;
-
-}
-
-} /* amiro */
diff --git a/components/eeprom/eeprom.cpp b/components/eeprom/eeprom.cpp
deleted file mode 100644
index 8a5c340..0000000
--- a/components/eeprom/eeprom.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/eeprom/eeprom.hpp>
-
-namespace amiro {
-
-#if HAL_USE_I2C
-EEPROM::
-EEPROM(const struct BaseFileStreamVMT* vmt, size_t size, uint8_t page_size, uint16_t max_t_wr, uint8_t sla, I2CDriver* i2c_driver) :
-  error(EEPROM_ERROR_NONE),
-  position(0x00u),
-  size(size),
-  page_size(page_size),
-  max_t_wr(max_t_wr),
-  i2c_driver(i2c_driver) {
-
-#if CH_USE_MUTEXES
-  chMtxInit(&this->mutex);
-#elif CH_USE_SEMAPHORES
-  chSemInit(&this->semaphore, 1);
-#endif
-
-  this->bfs.vmt = vmt;
-  this->i2c_txparams.addr = sla;
-
-}
-#endif /* HAL_USE_I2C */
-
-#if HAL_USE_SPI
-EEPROM::
-EEPROM(const struct BaseFileStreamVMT* vmt, size_t size, uint8_t page_size, uint16_t max_t_wr, HWSPIDriver* spi_driver) :
-  error(EEPROM_ERROR_NONE),
-  position(0x00u),
-  size(size),
-  page_size(page_size),
-  max_t_wr(max_t_wr),
-  spi_driver(spi_driver) {
-
-#if CH_USE_MUTEXES
-  chMtxInit(&this->mutex);
-#elif CH_USE_SEMAPHORES
-  chSemInit(&this->semaphore, 1);
-#endif
-
-  this->bfs.vmt = vmt;
-
-}
-#endif /* HAL_USE_SPI */
-
-EEPROM::
-~EEPROM() {
-
-}
-
-void
-EEPROM::
-acquire() {
-
-#if CH_USE_MUTEXES
-  chMtxLock(&this->mutex);
-#elif CH_USE_SEMAPHORES
-  chSemWait(&this->semaphore);
-#endif
-
-}
-
-void
-EEPROM::
-release() {
-
-#if CH_USE_MUTEXES
-  chMtxUnlock();
-#elif CH_USE_SEMAPHORES
-  chSemSignal(&this->semaphore);
-#endif
-
-}
-
-int
-EEPROM::
-geterror(void* instance) {
-
-  return (int) ((EEPROM*) (instance))->error;
-
-}
-
-fileoffset_t
-EEPROM::
-getsize(void *instance) {
-
-  return ((EEPROM*) (instance))->size;
-
-}
-
-fileoffset_t
-EEPROM::
-getposition(void* instance) {
-
-  return ((EEPROM*) (instance))->position;
-
-
-}
-
-fileoffset_t
-EEPROM::
-lseek(void *instance, fileoffset_t offset) {
-
-  ((EEPROM*) (instance))->position = offset;
-  return FILE_OK;
-
-}
-
-};
diff --git a/components/gyro/l3g4200d.cpp b/components/gyro/l3g4200d.cpp
deleted file mode 100644
index a8e43c1..0000000
--- a/components/gyro/l3g4200d.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-#include <chprintf.h>
-#include <string.h>
-
-#include <amiro/util/util.h>
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/gyro/l3g4200d.hpp>
-#include <amiro/Constants.h>
-#include <global.hpp>
-
-using namespace chibios_rt;
-
-extern Global global;
-
-namespace amiro {
-
-L3G4200D::L3G4200D(HWSPIDriver *driver)
-    : driver(driver),
-      udpsPerTic(175000),
-      period_us(100000) {
-  this->period_ms = this->period_us * 1e-3;
-  this->period_st = US2ST(this->period_us);
-}
-
-L3G4200D::~L3G4200D() {
-
-}
-
-chibios_rt::EvtSource*
-L3G4200D::getEventSource() {
-  return &this->eventSource;
-}
-
-msg_t L3G4200D::main() {
-  systime_t time = System::getTime();
-  this->setName("l3g4200d");
-
-  while (!this->shouldTerminate()) {
-    time += this->period_st;
-
-    updateSensorData();
-    calcAngular();
-
-    this->eventSource.broadcastFlags(1);
-
-    if (time >= System::getTime()) {
-      chThdSleepUntil(time);
-    } else {
-      chprintf((BaseSequentialStream*) &global.sercanmux1, "WARNING l3g4200d: Unable to keep track\r\n");
-    }
-  }
-  return RDY_OK;
-}
-
-int16_t
-L3G4200D::
-getAngularRate(const uint8_t axis) {
-  return this->angularRate[axis];
-}
-
-int32_t
-L3G4200D::
-getAngularRate_udps(const uint8_t axis) {
-  return int32_t(this->angularRate[axis]) * this->udpsPerTic;
-}
-
-int32_t
-L3G4200D::
-getAngular(const uint8_t axis) {
-  return this->angular[axis];
-}
-
-int32_t
-L3G4200D::
-getAngular_ud(const uint8_t axis) {
-  const int32_t angularRate_mdps = this->getAngularRate_udps(axis) * 1e-3;
-  return angularRate_mdps * (this->integrationTic * this->period_ms);
-}
-
-void
-L3G4200D::
-calcAngular() {
-  // Need to check for overflow!
-  ++this->integrationTic;
-  chSysLock();
-  this->angular[L3G4200D::AXIS_X] += int32_t(this->angularRate[L3G4200D::AXIS_X]);
-  this->angular[L3G4200D::AXIS_Y] += int32_t(this->angularRate[L3G4200D::AXIS_Y]);
-  this->angular[L3G4200D::AXIS_Z] += int32_t(this->angularRate[L3G4200D::AXIS_Z]);
-  chSysUnlock();
-}
-
-// TODO: Outsource, so that everyone who needs this has an own instance of the integrator
-void
-L3G4200D::
-angularReset() {
-  this->angular[L3G4200D::AXIS_X] = 0;
-  this->angular[L3G4200D::AXIS_Y] = 0;
-  this->angular[L3G4200D::AXIS_Z] = 0;
-  this->integrationTic = 0;
-}
-
-
-void L3G4200D::updateSensorData() {
-
-  const size_t buffer_size = offsetof(L3G4200D::registers, OUT_Z)
-                             - offsetof(L3G4200D::registers, STATUS_REG)
-                             + MEMBER_SIZE(L3G4200D::registers, OUT_Z)
-                             + 1; /* addressing */
-  uint8_t buffer[buffer_size];
-  uint8_t sreg;
-
-  /*Address of first data register*/
-  memset(buffer, 0xFF, sizeof(buffer));
-  buffer[0] = offsetof(L3G4200D::registers, STATUS_REG) | L3G4200D::SPI_READ | L3G4200D::SPI_MULT;
-
-  this->driver->exchange(buffer, buffer, buffer_size);
-
-  // assemble data
-  sreg = buffer[1];
-
-  chSysLock();
-  if (sreg & L3G4200D::XDA)
-    this->angularRate[L3G4200D::AXIS_X] = (buffer[3] << 8) + buffer[2];
-
-  if (sreg & L3G4200D::YDA)
-    this->angularRate[L3G4200D::AXIS_Y] = (buffer[5] << 8) + buffer[4];
-
-  if (sreg & L3G4200D::ZDA)
-    this->angularRate[L3G4200D::AXIS_Z] = (buffer[7] << 8) + buffer[6];
-  chSysUnlock();
-}
-
-msg_t L3G4200D::configure(const L3G4200DConfig *config) {
-
-  const size_t ctrl_reg_size = offsetof(L3G4200D::registers, CTRL_REG5)
-                               - offsetof(L3G4200D::registers, CTRL_REG1)
-                               + MEMBER_SIZE(L3G4200D::registers, CTRL_REG5)
-                               + 1; /* addressing */
-
-  const size_t buffer_size = ctrl_reg_size;
-
-  uint8_t buffer[buffer_size];
-
-  // write control config
-  // this might be three-wire so we need to send ones
-  memset(buffer, 0xFFu, buffer_size);
-  buffer[0] = offsetof(L3G4200D::registers, CTRL_REG1) | L3G4200D::SPI_MULT | L3G4200D::SPI_WRITE;
-  buffer[1] = config->ctrl1;
-  buffer[2] = config->ctrl2;
-  buffer[3] = config->ctrl3;
-  buffer[4] = config->ctrl4;
-  buffer[5] = config->ctrl5;
-  this->driver->write(buffer, 6);
-
-  // Handle the new update time
-  switch(config->ctrl1 & L3G4200D::DR_MASK) {
-    case L3G4200D::DR_100_HZ: this->period_us = 10000; break;
-    case L3G4200D::DR_200_HZ: this->period_us =  5000; break;
-    case L3G4200D::DR_400_HZ: this->period_us =  2500; break;
-    case L3G4200D::DR_800_HZ: this->period_us =  1250; break;
-  }
-  this->period_st = US2ST(this->period_us);
-  this->period_ms = this->period_us * 1e-3;
-
-  // Handle the new full scale
-  switch(config->ctrl1 & L3G4200D::FS_MASK) {
-    case L3G4200D::FS_250_DPS:  this->udpsPerTic =  8750; break;
-    case L3G4200D::FS_500_DPS:  this->udpsPerTic = 17500; break;
-    case L3G4200D::FS_2000_DPS: this->udpsPerTic = 70000; break;
-  }
-
-  // Reset the integration
-  this->angularReset();
-
-  return RDY_OK;
-
-}
-
-uint8_t L3G4200D::getCheck() {
-
-  const size_t buffer_size = 1 /* addressing */
-  + 1; /* who am i */
-  uint8_t buffer[buffer_size];
-
-  // Exchange the data with the L3G4200D gyroscope
-  // Specify the adress and the mode
-  buffer[0] = offsetof(L3G4200D::registers, WHO_AM_I) | L3G4200D::SPI_READ;
-  this->driver->exchange(buffer, buffer, buffer_size);
-  // Check
-  if (buffer[1] == L3G4200D::L3G4200D_ID) {
-    return L3G4200D::CHECK_OK;
-  } else {
-    return L3G4200D::CHECK_FAIL;
-  }
-
-}
-
-} /* amiro */
diff --git a/components/input/mpr121.cpp b/components/input/mpr121.cpp
deleted file mode 100644
index 2509f67..0000000
--- a/components/input/mpr121.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-#include <amiro/bus/i2c/I2CDriver.hpp>
-#include <amiro/input/mpr121.hpp>
-#include <amiro/Constants.h>
-
-namespace amiro {
-
-MPR121::
-MPR121(I2CDriver *driver, const uint8_t master_id) :
-  BaseStaticThread<256>(),
-  driver(driver),
-  master_id(master_id),
-  button_state(0x0000u) {
-
-  chDbgCheck(master_id <= 0x03u, "MPR121 ctor master_id");
-  this->tx_params.addr = MPR121::SLA | this->master_id;
-
-}
-
-MPR121::
-~MPR121() {
-
-}
-
-msg_t
-MPR121::
-updateButtonData() {
-
-  msg_t res;
-  const uint8_t offset_touch = offsetof(MPR121::registers, touch_status);
-  const uint8_t offset_electrode = offsetof(MPR121::registers, ele_filt_data);
-  const uint8_t offset_baseline = offsetof(MPR121::registers, ele_baseline);
-  uint8_t buffer[offsetof(MPR121::registers, mhd_rising) - offset_touch];
-  uint8_t *tmp = buffer;
-  uint8_t reg = offset_touch;
-  uint8_t i;
-  this->tx_params.txbuf = &reg;
-  this->tx_params.txbytes = 1;
-  this->tx_params.rxbuf = buffer;
-  this->tx_params.rxbytes = sizeof(buffer);
-
-  res = this->driver->masterTransmit(&this->tx_params);
-
-  if (!res) {
-    tmp = buffer + offset_touch;
-    this->button_state = (*(tmp + 1) << 8) | *tmp;
-    tmp = buffer + offset_electrode;
-    for (i = 0x00; i < 13; i++) {
-      this->electrode_data[i] = (*(tmp + 1) << 8) | *tmp;
-      tmp += 2;
-    }
-    tmp = buffer + offset_baseline;
-    for (i = 0x00; i < 13; i++)
-      this->baseline_data[i] = *tmp++;
-
-  }
-
-  return res;
-
-}
-
-msg_t
-MPR121::
-softReset() {
-
-  msg_t res;
-  uint8_t buffer[2];
-
-  buffer[0] = offsetof(MPR121::registers, soft_reset);
-  buffer[1] = SOFT_RST_MAGIC;
-
-  this->tx_params.txbuf = buffer;
-  this->tx_params.txbytes = 2;
-  this->tx_params.rxbytes = 0;
-
-  res = this->driver->masterTransmit(&this->tx_params);
-
-  if (res)
-    return res;
-
-  buffer[0] = offsetof(MPR121::registers, ele_config);
-  buffer[1] = 0x00u; /* ele_config: make sure we are in stop mode */
-
-  return this->driver->masterTransmit(&this->tx_params);
-
-}
-
-msg_t
-MPR121::
-writeConfig(const MPR121Config *cfg) {
-
-  msg_t res;
-  uint8_t buffer[6];
-
-  buffer[0] = offsetof(MPR121::registers, auto_cfg_ctrl);
-  buffer[1] = (cfg->auto_config & 0x00FFu);
-  buffer[2] = (cfg->auto_config & 0xFF00u) >> 8;
-  buffer[3] = cfg->up_side_limit;
-  buffer[4] = cfg->low_side_limit;
-  buffer[5] = cfg->target_level;
-
-  this->tx_params.txbuf = buffer;
-  this->tx_params.txbytes = 6;
-  this->tx_params.rxbytes = 0;
-
-  res = this->driver->masterTransmit(&this->tx_params);
-
-  if (res)
-    return res;
-
-  buffer[0] = offsetof(MPR121::registers, cdc_config);
-  buffer[1] = (cfg->global_config & 0x00FFu);
-  buffer[2] = (cfg->global_config & 0xFF00u) >> 8;
-  buffer[3] = cfg->ele_config;
-
-  this->tx_params.txbytes = 4;
-
-  return this->driver->masterTransmit(&this->tx_params);
-
-}
-
-uint16_t
-MPR121::
-getButtonStatus() {
-
-  return this->button_state;
-
-}
-
-uint8_t
-MPR121::
-getButtonStatus(uint8_t ix) {
-
-  return this->button_state & (1u << ix);
-
-}
-
-uint8_t
-MPR121::
-getBaselineData(uint8_t ix) {
-
-  return this->baseline_data[ix];
-
-}
-
-uint16_t
-MPR121::
-getElectrodeData(uint8_t ix) {
-
-  return this->electrode_data[ix];
-
-}
-
-/**
- * Main Sensor Thread.
- * Will not check whether sensor was actually configured prior to running.
- * @note   You should configure the sensor while stopped, then start.
- * @return RDY_OK on exit.
- */
-msg_t
-MPR121::
-main(void) {
-
-  I2CDriver *drv = this->driver;
-
-  this->setName("MPR121");
-
-  while (!this->shouldTerminate()) {
-
-    drv->acquireBus();
-    this->updateButtonData();
-    drv->releaseBus();
-
-    this->eventSource.broadcastFlags(0);
-
-    this->waitAnyEventTimeout(ALL_EVENTS, CAN::UPDATE_PERIOD);
-  }
-
-  return RDY_OK;
-}
-
-/**
- * Configure the MPR121 touch sensor.
- * Will perform a soft reset and then apply the configuration \p cfg.
- * @note      Call only when sensor is stopped.
- * @param cfg The new configuration.
- * @return    RDY_OK if everything went well. Appropriate error otherwise.
- */
-msg_t
-MPR121::
-configure(const MPR121Config *cfg) {
-
-  I2CDriver *drv = this->driver;
-  msg_t res;
-
-  drv->acquireBus();
-
-  // do a soft reset, in case config changes config mode
-  // (auto config vs. configure all sensors individually)
-  res = this->softReset();
-
-  if (res == RDY_OK) {
-
-    res = this->writeConfig(cfg);
-
-  }
-
-  drv->releaseBus();
-
-  return res;
-}
-
-
-} /* amiro */
diff --git a/components/leds/tlc5947.cpp b/components/leds/tlc5947.cpp
deleted file mode 100644
index 89ca720..0000000
--- a/components/leds/tlc5947.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/leds/tlc5947.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-TLC5947::TLC5947(HWSPIDriver *spi, ioportid_t blankPort, int blankPad)
-    : BaseStaticThread<192>(),
-      spi(spi),
-      blankPort(blankPort),
-      blankPad(blankPad),
-      brightness(0x00u) {
-  for (int i = 0; i < 8; i++)
-    this->colors[i] = Color::BLACK;
-}
-
-TLC5947::
-~TLC5947() {
-
-}
-
-void TLC5947::disable() {
-  palWritePad(this->blankPort, this->blankPad, 1);
-}
-
-void TLC5947::enable() {
-  palWritePad(this->blankPort, this->blankPad, 0);
-}
-
-void TLC5947::setBrightness(int brightness) {
-  if (brightness < 0)
-    this->brightness = 0;
-  else if (brightness > 100)
-    this->brightness = 100;
-  else
-    this->brightness = brightness;
-}
-
-void TLC5947::setColor(int index, Color color) {
-  this->colors[index] = color;
-}
-
-void TLC5947::update() {
-  this->signalEvents(static_cast<eventmask_t>(1));
-}
-
-msg_t TLC5947::main(void) {
-  uint8_t buffer[36];
-
-  this->setName("Tlc5947");
-
-  while (!this->shouldTerminate()) {
-    int brightness = this->brightness;
-
-    for (int i = 0, j = 0; i < 8; i += 2) {
-      Color color1 = this->colors[i];
-      Color color2 = this->colors[i + 1];
-
-      int values[6];
-      values[0] = caluclateBlueGrayscale(color1, brightness);
-      values[1] = caluclateGreenGrayscale(color1, brightness);
-      values[2] = caluclateRedGrayscale(color1, brightness);
-      values[3] = caluclateBlueGrayscale(color2, brightness);
-      values[4] = caluclateGreenGrayscale(color2, brightness);
-      values[5] = caluclateRedGrayscale(color2, brightness);
-
-      for (int k = 0; k < 6; k += 2) {
-        int value1 = values[k];
-        int value2 = values[k + 1];
-
-        buffer[j++] = static_cast<uint8_t>((value1 >> 4) & 0xff);
-        buffer[j++] = static_cast<uint8_t>((value1 << 4) | ((value2 >> 8) & 0xff));
-        buffer[j++] = static_cast<uint8_t>(value2 & 0xff);
-      }
-    }
-    this->spi->write(buffer, 36);
-
-    this->waitAnyEvent(ALL_EVENTS);
-  }
-
-  return true;
-}
-
-int TLC5947::caluclateRedGrayscale(Color color, int brightness) const {
-  return color.getRed() * brightness * 16 / 100;
-}
-
-int TLC5947::caluclateGreenGrayscale(Color color, int brightness) const {
-  return color.getGreen() * brightness * 16 / 100;
-}
-
-int TLC5947::caluclateBlueGrayscale(Color color, int brightness) const {
-  return color.getBlue() * brightness * (16 * 3) / (100 * 4);
-}
diff --git a/components/magneto/hmc5883l.cpp b/components/magneto/hmc5883l.cpp
deleted file mode 100644
index a032004..0000000
--- a/components/magneto/hmc5883l.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-#include <chdebug.h>
-
-#include <amiro/bus/i2c/I2CParams.hpp>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-#include <amiro/magneto/hmc5883l.hpp>
-#include <amiro/Constants.h>
-
-using namespace chibios_rt;
-
-namespace amiro {
-
-HMC5883L::~HMC5883L() {
-
-}
-
-HMC5883L::HMC5883L(I2CDriver *driver, const HMC5883LConfig *config)
-    : BaseStaticThread<256>(),
-      driver(driver),
-      config(config) {
-
-  this->txParams.addr = HMC5883L::SLA;
-}
-
-EvtSource*
-HMC5883L::
-getEventSource() {
-
-  return &this->eventSource;
-}
-
-msg_t
-HMC5883L::
-main(void) {
-
-  msg_t res;
-
-  this->setName("Hmc5883l");
-
-  /* exit if writing configuration fails */
-  res = this->writeConf();
-
-  if (res) {
-    return RDY_RESET;
-  }
-
-  while (!this->shouldTerminate()) {
-
-    this->updateSensorData();
-
-    this->eventSource.broadcastFlags(0);
-
-    this->waitAnyEventTimeout(ALL_EVENTS, CAN::UPDATE_PERIOD);
-  }
-
-  return RDY_OK;
-}
-
-int16_t
-HMC5883L::
-getMagnetization(const uint8_t axis) {
-  int16_t returnBuffer;
-  chSysLock();
-  returnBuffer = this->data[axis];
-  chSysUnlock();
-  return returnBuffer;
-
-}
-
-int32_t
-HMC5883L::
-getMagnetizationGauss(const uint8_t axis) {
-
-  int16_t magLsbBuffer = this->getMagnetization(axis);
-  int32_t returnBuffer = 0;
-
-  // The gains are taken from table 9 of the manual
-  switch (this->config->ctrlB & GN_7_GA) {
-    case HMC5883L::GN_0_GA:
-      returnBuffer = int32_t(0.73 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_1_GA:
-      returnBuffer = int32_t(0.92 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_2_GA:
-      returnBuffer = int32_t(1.22 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_3_GA:
-      returnBuffer = int32_t(1.52 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_4_GA:
-      returnBuffer = int32_t(2.27 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_5_GA:
-      returnBuffer = int32_t(2.56 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_6_GA:
-      returnBuffer = int32_t(3.03 * 1000) * int32_t(magLsbBuffer);
-      break;
-    case HMC5883L::GN_7_GA:
-      returnBuffer = int32_t(4.35 * 1000) * int32_t(magLsbBuffer);
-      break;
-  }
-
-  return returnBuffer;
-
-}
-
-void
-HMC5883L::
-updateSensorData() {
-
-  const uint8_t sizeOfRxData =  offsetof(HMC5883L::registers, yLsb)
-                              - offsetof(HMC5883L::registers, xMsb)
-                              + 1;
-
-  uint8_t rxBuffer[sizeOfRxData];
-
-  /*Address of data register*/
-  uint8_t txBuffer = offsetof(HMC5883L::registers, xMsb); /* Address of XMSB */
-
-  // Define the RXTX structure
-  this->txParams.txbuf = &txBuffer;
-  this->txParams.txbytes = sizeof(txBuffer);
-  this->txParams.rxbuf = rxBuffer;
-  this->txParams.rxbytes = sizeof(rxBuffer);
-
-  this->driver->acquireBus();
-  this->driver->masterTransmit(&this->txParams);
-  this->driver->releaseBus();
-
-  // Copy the bytes in the right order
-  chSysLock(); // TODO: check if this is really necessary b/c it inserts a DMB!!
-  data[HMC5883L::AXIS_X] = (rxBuffer[0] << 8) + rxBuffer[1];
-  data[HMC5883L::AXIS_Z] = (rxBuffer[2] << 8) + rxBuffer[3];
-  data[HMC5883L::AXIS_Y] = (rxBuffer[4] << 8) + rxBuffer[5];
-  chSysUnlock();
-}
-
-uint8_t HMC5883L::getCheck() {
-
-  I2CTxParams txStructure;
-  msg_t res;
-  const uint8_t txBuffer = offsetof(HMC5883L::registers, idA);
-  const uint8_t sizeOfRxData = offsetof(HMC5883L::registers, idC) - offsetof(HMC5883L::registers, idA) + 1;
-  uint8_t rxBuffer[sizeOfRxData];
-
-  txStructure.addr = SLA;
-  txStructure.txbuf = &txBuffer;
-  txStructure.txbytes = sizeof(txBuffer);
-  txStructure.rxbuf = rxBuffer;
-  txStructure.rxbytes = sizeof(rxBuffer);
-
-  // get the identifier
-  this->driver->acquireBus();
-  res = this->driver->masterTransmit(&txStructure);
-  this->driver->releaseBus();
-  // Check
-  if (rxBuffer[0] == ID_IRA && rxBuffer[1] == ID_IRB && rxBuffer[2] == ID_IRC && res == RDY_OK) {
-    return HMC5883L::CHECK_OK;
-  } else {
-    return HMC5883L::CHECK_FAIL;
-  }
-
-}
-
-
-msg_t
-HMC5883L::
-writeConf() {
-
-  uint8_t txBuffer[4];
-  msg_t res;
-
-  // write control config
-  txBuffer[0] = offsetof(HMC5883L::registers, ctrlA);  /* Address of ctrlA */
-  txBuffer[1] = this->config->ctrlA;
-  txBuffer[2] = this->config->ctrlB;
-  txBuffer[3] = this->config->mode;
-
-  this->txParams.txbuf = txBuffer;
-  this->txParams.txbytes = sizeof(txBuffer);
-  this->txParams.rxbytes = 0;
-
-  this->driver->acquireBus();
-  res = this->driver->masterTransmit(&this->txParams);
-  this->driver->releaseBus();
-
-  return res;
-
-}
-
-} /* amiro */
diff --git a/components/power/adconverter.cpp b/components/power/adconverter.cpp
deleted file mode 100644
index 7b43812..0000000
--- a/components/power/adconverter.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-#include <amiro/power/adconverter.hpp>
-
-#include <global.hpp>
-#include <amiro/Constants.h>
-#include <amiro/power/ina219.hpp>
-#include <amiro/util/util.h>
-
-#include <chprintf.h>
-
-using namespace amiro;
-
-extern Global global;
-
-void adcVsysErrorCallback(ADCDriver *adcp, adcerror_t err)
-{
-  if (err == ADC_ERR_WATCHDOG) {
-    chSysLockFromIsr();
-    if (adcp->thread != NULL) {
-      chEvtSignalI(adcp->thread, EVENT_MASK(ADConverter::EVT_WATCHDOG));
-      adcp->thread = NULL;
-    }
-    chSysUnlockFromIsr();
-  }
-
-  return;
-}
-
-void adcTimerCallback(Thread *tp)
-{
-  if (tp != NULL) {
-    chEvtSignal(tp, EVENT_MASK(ADConverter::EVT_TIMER));
-  }
-  return;
-}
-
-uint16_t
-ADConverter::uV2Adc(const uint32_t uV)
-{
-  // NOTE: The factor 5.33 is an approximation of the voltage divider.
-  //       Its value should be 5.0, but due to too large resistors the factor is shifted.
-  // TODO: 5.33 should be replaced by a non linear function, which needs to be optained from the system.
-
-  // get the current VDD voltage
-  global.ina219[constants::PowerManagement::INA_VDD].update();
-  INA219::BusVoltage vdd = global.ina219[constants::PowerManagement::INA_VDD].getVoltage();
-  return float(uV)/1000000 / 5.33f / (float(vdd.voltage_uV)/1000000) * 4096;
-}
-
-uint32_t ADConverter::adc2uV(const uint16_t adc)
-{
-  // NOTE: The factor 5.33 is an approximation of the voltage divider.
-  //       Its value should be 5.0, but due to too large resistors the factor is shifted.
-  // TODO: 5.33 should be replaced by a non linear function, which needs to be optained from the system.
-
-  // get the current VDD voltage
-  global.ina219[constants::PowerManagement::INA_VDD].update();
-  INA219::BusVoltage vdd = global.ina219[constants::PowerManagement::INA_VDD].getVoltage();
-  return float(adc)/4096 * (float(vdd.voltage_uV)/1000000) * 5.33f * 1000000;
-}
-
-ADConverter::ADConverter(ADCDriver& adcdrv, ADCConversionGroup& adccgrp, const uint32_t threshold_uV) :
-  driver(adcdrv), conversion_group(adccgrp), watchdog_threshold_uV(threshold_uV)
-{
-}
-
-
-ADConverter::~ADConverter()
-{
-}
-
-msg_t
-ADConverter::main()
-{
-  // initialize a timer event for later use
-  evtInit(&this->evt_timer, MS2ST(1));
-  this->evt_source = reinterpret_cast<EvtSource*>(&this->evt_timer.et_es);
-  this->evt_source->registerOne(&this->evt_listener, EVT_TIMER);
-
-  // initialize the watchdog
-  this->enableWatchdog(true);
-  this->conversion_group.htr = ADC_HTR(uV2Adc(this->watchdog_threshold_uV));
-  this->conversion_group.ltr = 0;
-  this->driver.thread = this->thread_ref;
-
-  adcStartConversion(&this->driver, &this->conversion_group, global.adc1_buffer, ARRAY_SIZE(global.adc1_buffer));
-
-  while (!this->shouldTerminate())
-  {
-    eventmask_t event = this->waitOneEventTimeout(ALL_EVENTS, MS2ST(1000));
-
-    switch (event)
-    {
-      // watchdog event (fired by ADC interrupt)
-      case EVENT_MASK(EVT_WATCHDOG):
-      {
-        // disable the chargers
-        global.bq24103a[constants::PowerManagement::BAT_P7]->enable(false);
-        global.bq24103a[constants::PowerManagement::BAT_P8]->enable(false);
-
-        // to avoid multiple interrupts because of noise, wait 1ms before setting the chargers and ADC
-        this->enableWatchdog(false);
-        evtStart(&this->evt_timer);
-        break;
-      }
-
-      // timer event
-      case EVENT_MASK(EVT_TIMER):
-      {
-        evtStop(&this->evt_timer);
-
-        // read the current voltage
-        this->conversion_group.circular = FALSE;
-        adcConvert(&this->driver, &this->conversion_group, global.adc1_buffer, ARRAY_SIZE(global.adc1_buffer));
-        this->conversion_group.circular = TRUE;
-        this->enableWatchdog(true); // Watchdog was disabled in ISR
-
-        if (global.adc1_buffer[0] > uV2Adc(this->watchdog_threshold_uV))
-        {
-          chprintf((BaseSequentialStream*)&global.sercanmux1, "%f > 9V detected: now charging\n", ((float)adc2uV(global.adc1_buffer[0]))/1000000.0f);
-          global.robot.getPowerStatus().charging_flags.content.vsys_higher_than_9V = true;
-          global.bq24103a[constants::PowerManagement::BAT_P7]->enable(true);
-          global.bq24103a[constants::PowerManagement::BAT_P8]->enable(true);
-          this->conversion_group.htr = ADC_HTR_HT;
-          this->conversion_group.ltr = ADC_LTR(uV2Adc(this->watchdog_threshold_uV));
-        } else {
-          chprintf((BaseSequentialStream*)&global.sercanmux1, "%f < 9V detected: not charging\n", ((float)adc2uV(global.adc1_buffer[0]))/1000000.0f);
-          global.robot.getPowerStatus().charging_flags.content.vsys_higher_than_9V = false;
-          this->conversion_group.htr = ADC_HTR(uV2Adc(this->watchdog_threshold_uV));
-          this->conversion_group.ltr = 0;
-        }
-        this->driver.thread = this->thread_ref;
-        adcStartConversion(&this->driver, &this->conversion_group, global.adc1_buffer, ARRAY_SIZE(global.adc1_buffer));
-        break;
-      }
-
-      // timeout
-      case 0:
-
-      default:
-        break;
-    }
-  }
-
-  return RDY_RESET;
-}
-
-void
-ADConverter::enableWatchdog(const bool enable)
-{
-  if (enable) {
-    this->conversion_group.cr1 |= ADC_CR1_AWDEN | ADC_CR1_AWDIE;
-    this->conversion_group.error_cb = &adcVsysErrorCallback;
-  } else {
-    this->conversion_group.cr1 &= ~(ADC_CR1_AWDEN | ADC_CR1_AWDIE);
-    this->conversion_group.error_cb = NULL;
-  }
-}
-
-
diff --git a/components/power/bq27500.cpp b/components/power/bq27500.cpp
deleted file mode 100644
index 795f274..0000000
--- a/components/power/bq27500.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-#include <amiro/power/bq27500.hpp>
-
-#include <ch.hpp>
-#include <chprintf.h>
-#include <global.hpp>
-
-#include <cstring>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace BQ27500;
-
-extern Global global;
-
-Driver::Driver(I2CDriver &i2c_driver, const GPIO_TypeDef &batgd_pingrp, const uint8_t batgd_pin, const GPIO_TypeDef &batlow_pingrp, const uint8_t batlow_pin) :
-  BaseSensor<BQ27500::InitData,BQ27500::CalibData>(), i2c_driver(&i2c_driver), tx_params({I2C_ADDR, NULL, 0, NULL, 0}),
-  batgd_pingrp(&batgd_pingrp), batgd_pin(batgd_pin), batlow_pingrp(&batlow_pingrp), batlow_pin(batlow_pin)
-{}
-
-Driver::~Driver()
-{}
-
-chibios_rt::EvtSource*
-Driver::getEventSource()
-{
-  return &this->eventSource;
-}
-
-msg_t
-Driver::init(InitData* initialization_data)
-{
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): TODO\n", __FILE__, __LINE__);
-  return NOT_IMPLEMENTED;
-}
-
-msg_t
-Driver::update()
-{
-  msg_t res = SUCCESS;
-  res |= this->stdCommand(STD_CMD_TimeToEmpty, this->status.minutes_to_empty);
-  res |= this->stdCommand(STD_CMD_TimeToFull, this->status.minutes_to_full);
-  res |= this->stdCommand(STD_CMD_AveragePower, this->status.average_power_mW);
-  uint16_t tmp;
-  res |= this->stdCommand(STD_CMD_StateOfCharge, tmp);
-  this->status.state_of_charge = tmp;
-  return (res == SUCCESS)? SUCCESS : ERROR;
-}
-
-msg_t
-Driver::wakeup()
-{
-  const msg_t res = this->subCommand(SUB_CMD_CLEAR_HIBERNATE);
-  return (res? ERROR : SUCCESS);
-}
-
-msg_t
-Driver::hibernate()
-{
-  const msg_t res = this->subCommand(SUB_CMD_SET_HIBERNATE);
-  return (res? ERROR : SUCCESS);
-}
-
-#ifndef AMIRO_NCALIBRATION
-msg_t
-Driver::calibration(CalibData* calibration_data)
-{
-  DataFlashBlock block;
-  this->readDataFlashBlock(block, CONFIGURATION_Safety);
-
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d):\n", __FILE__, __LINE__);
-  for(uint8_t i = 0; i < 32; ++i) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%02X ", block.content.data[i]);
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "%02X\n", block.content.checksum);
-
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): TODO\n", __FILE__, __LINE__);
-  return NOT_IMPLEMENTED;
-}
-#endif
-
-#ifndef AMIRO_NSELFTEST
-msg_t
-Driver::selftest()
-{
-  uint16_t val = 0;
-  Version version;
-
-  // read hardware version
-  version.value = 0;
-  if (this->subCommand(SUB_CMD_HW_VERSION, &version.value))
-  {
-    return ST_FAIL_READ_HW_VERSION;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "hardware version: %X%X-%X%X (0x%04X)\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low, version.value);
-
-  // read firmware version
-  version.value = 0;
-  if (this->subCommand(SUB_CMD_FW_VERSION, &version.value))
-  {
-    return ST_FAIL_READ_FW_VERSION;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "firmware version: %X%X-%X%X (0x%04X)\n", version.content.major_high, version.content.major_low, version.content.minor_high, version.content.minor_low, version.value);
-
-  // read device name
-  uint8_t name_length = 0;
-  if (this->extCommand(EXT_CMD_DNAMELEN, EXT_CMD_READ, &name_length))
-  {
-    return ST_FAIL_READ_DEVICENAMELENGTH;
-  }
-  char name_buffer[9]; // maximum name length is 8
-  if (this->extCommand(EXT_CMD_DNAME, EXT_CMD_READ, (uint8_t*)name_buffer, name_length))
-  {
-    return ST_FAIL_READ_DEVICENAME;
-  }
-  name_buffer[name_length] = '\0';
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "device name: %s (%u characters)\n", name_buffer, name_length);
-
-  // read the current flags
-  Flags flags;
-  if (this->stdCommand(STD_CMD_FLAGS, flags.value))
-  {
-    return ST_FAIL_READ_FLAGS;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "flags: 0x%04X\n", flags.value);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  OTC     : %u\n", flags.content.otc);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  OTD     : %u\n", flags.content.otd);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  CHG_INH : %u\n", flags.content.chg_inh);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  XCHG    : %u\n", flags.content.xchg);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  FC      : %u\n", flags.content.fc);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  CHG     : %u\n", flags.content.chg);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  OCV_GD  : %u\n", flags.content.ocv_gd);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  WAIT_ID : %u\n", flags.content.wait_id);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  BAT_DET : %u\n", flags.content.bat_det);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  SOC1    : %u\n", flags.content.soc1);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  SOCF    : %u\n", flags.content.socf);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  DSG     : %u\n", flags.content.dsg);
-
-  // read the current controller status
-  ControlStatus ctrl_status;
-  if (this->subCommand(SUB_CMD_CONTROL_STATUS, &ctrl_status.value))
-  {
-    return ST_FAIL_READ_STATUS;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "control status: 0x%04X\n", ctrl_status.value);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  FAS       : %u\n", ctrl_status.content.fas);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  SS        : %u\n", ctrl_status.content.ss);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  CSV       : %u\n", ctrl_status.content.csv);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  CSA       : %u\n", ctrl_status.content.cca);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  BCA       : %u\n", ctrl_status.content.bca);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  HIBERNATE : %u\n", ctrl_status.content.hibernate);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  SNOOZE    : %u\n", ctrl_status.content.snooze);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  SLEEP     : %u\n", ctrl_status.content.sleep);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  LDMD      : %u\n", ctrl_status.content.ldmd);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  RUP_DIS   : %u\n", ctrl_status.content.rup_dis);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  VOK       : %u\n", ctrl_status.content.vok);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "  QEN       : %u\n", ctrl_status.content.qen);
-
-  // if no battery was detected, abort
-  if (!flags.content.bat_det)
-  {
-    return ST_ABORT_NO_BAT;
-  }
-
-  // read the BATGD_N pin
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "battery good: %s\n", (this->isBatteryGood()? "yes" : "no"));
-
-  // read temperature
-  if (this->stdCommand(STD_CMD_TEMP, val))
-  {
-    return ST_FAIL_READ_TEMP;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "temperature: %fK (%fC)\n", float(val)/10.0f, float(val)/10.0f - 273.15f);
-
-  // read the full available capacity
-  if (this->stdCommand(STD_CMD_FAC, val))
-  {
-    return ST_FAIL_READ_FAC;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "full available capacity: %umAh\n", val);
-
-  // read the full charge capacity
-  if (this->stdCommand(STD_CMD_FCC, val))
-  {
-    return ST_FAIL_READ_FCC;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "full charge capacity: %umAh\n", val);
-
-  // read the remaining capacity
-  if (this->stdCommand(STD_CMD_RM, val))
-  {
-    return ST_FAIL_READ_RM;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "remaining capacity capacity: %umAh\n", val);
-
-  // read the state of charge
-  if (this->stdCommand(STD_CMD_SOC, val))
-  {
-    return ST_FAIL_READ_SOC;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "state of charge: %3u%%\n", val);
-
-  // read voltage
-  if (this->stdCommand(STD_CMD_VOLT, val))
-  {
-    return ST_FAIL_READ_VOLT;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "voltage: %umV\n", val);
-
-  // read average current
-  if (this->stdCommand(STD_CMD_AI, val))
-  {
-    return ST_FAIL_READ_AI;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "average current: %dmA\n", *reinterpret_cast<int8_t*>(&val));
-
-  // read average power
-  if (this->stdCommand(STD_CMD_AP, val))
-  {
-    return ST_FAIL_READ_AP;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "average power: %dmW\n", *reinterpret_cast<int8_t*>(&val));
-
-  // read the BATLOW pin
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "battery low: %s\n", (this->isBatteryLow()? "yes" : "no"));
-
-  // read the time to empty
-  if (this->stdCommand(STD_CMD_TTE, val))
-  {
-    return ST_FAIL_READ_TTE;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "time to empty: ");
-  if (uint16_t(~val)) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%u minutes", val);
-  } else {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "(not discharging)");
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-
-  // read the time to full
-  if (this->stdCommand(STD_CMD_TTF, val))
-  {
-    return ST_FAIL_READ_TTF;
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "time to full: ");
-  if (uint16_t(~val)) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%u minutes", val);
-  } else {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "(not charging)");
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "\n");
-
-  return ST_OK;
-}
-#endif
-
-bool
-Driver::isBatteryGood() const
-{
-  return (palReadPad(this->batgd_pingrp, this->batgd_pin) == PAL_LOW);
-}
-
-bool
-Driver::isBatteryLow() const
-{
-  return (palReadPad(this->batlow_pingrp, this->batlow_pin) == PAL_HIGH);
-}
-
-const Driver::UpdateData&
-Driver::getStatus() const
-{
-  return this->status;
-}
-
-msg_t
-Driver::main(void)
-{
-  while (!this->shouldTerminate())
-  {
-    this->update();
-    this->eventSource.broadcastFlags(0);
-
-    this->waitAnyEventTimeout(ALL_EVENTS, MS2ST(1000));
-  }
-
-  return RDY_OK;
-}
-
-msg_t
-Driver::stdCommand(const StandardCommand cmd, uint16_t &dst)
-{
-  uint8_t buffer[2];
-  this->tx_params.txbuf = reinterpret_cast<const uint8_t*>(&cmd);
-  this->tx_params.txbytes = 1;
-  this->tx_params.rxbuf = buffer;
-  this->tx_params.rxbytes = 2;
-
-  this->i2c_driver->acquireBus();
-  const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params);
-  this->i2c_driver->releaseBus();
-
-  if (!res) {
-    dst = uint16_t((buffer[1] << 8) | buffer[0]);
-#ifndef NDEBUG
-  } else {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d)\n", __FILE__ , __LINE__ , res);
-#endif
-  }
-
-  return res;
-}
-
-msg_t
-Driver::readName()
-{
-  uint8_t buffer[9];
-  uint8_t reg = 0x62u;
-  this->tx_params.txbuf = &reg;
-  this->tx_params.txbytes = 1;
-  this->tx_params.rxbuf = &buffer[0];
-  this->tx_params.rxbytes = 8;
-
-  this->i2c_driver->acquireBus();
-  const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params);
-  this->i2c_driver->releaseBus();
-
-  buffer[buffer[0] + 1] = '\0';
-
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "name: %u - %s\n", buffer[0], (char*)&buffer[1]);
-
-  return res;
-}
-
-msg_t
-Driver::subCommand(const ControlSubcommand cmd, uint16_t *dst)
-{
-  uint8_t buffer[3] = {STD_CMD_CNTL, uint8_t(cmd & 0x00FFu), uint8_t((cmd & 0xFF00u) >> 8)};
-  this->tx_params.txbuf = buffer;
-  this->tx_params.txbytes = 3;
-  this->tx_params.rxbytes = 0;
-
-  this->i2c_driver->acquireBus();
-  msg_t res = this->i2c_driver->masterTransmit(&this->tx_params);
-  this->i2c_driver->releaseBus();
-  if (dst) {
-    this->tx_params.txbytes = 1;
-
-    this->tx_params.rxbuf = &buffer[1];
-    this->tx_params.rxbytes = 2;
-
-    BaseThread::sleep(US2ST(2));
-    this->i2c_driver->acquireBus();
-    res |= this->i2c_driver->masterTransmit(&this->tx_params);
-    this->i2c_driver->releaseBus();
-  }
-
-#ifndef NDEBUG
-  if (res) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d)\n", __FILE__ , __LINE__ , res);
-  }
-#endif
-
-  if (dst && !res) {
-    *dst = uint16_t((buffer[2] << 8) | buffer[1]);
-  }
-
-  return res;
-}
-
-msg_t
-Driver::extCommand(const ExtendedCommand cmd, const ExtendedCommandAccess rw, uint8_t* buf, const uint8_t length, const uint8_t offset)
-{
-  if (!buf) {
-#ifndef NDEBUG
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: received NULL-pointer as buffer\n", __FILE__ , __LINE__);
-#endif
-    return ~RDY_OK;
-  }
-  if (rw != EXT_CMD_WRITE && rw != EXT_CMD_READ) {
-#ifndef NDEBUG
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: invalid access mode selected\n", __FILE__ , __LINE__);
-#endif
-    return ~RDY_OK;
-  }
-  if (length > 33) {
-#ifndef NDEBUG
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: length exceeds maximum of 33 bytes\n", __FILE__ , __LINE__);
-#endif
-    return ~RDY_OK;
-  }
-
-  uint8_t in_buffer[34];
-  in_buffer[0] = cmd + offset;
-  if (rw == EXT_CMD_WRITE) {
-    strncpy((char*)&in_buffer[1], (char*)buf, length);
-  }
-  this->tx_params.txbuf = in_buffer;
-  this->tx_params.txbytes = 1 + ((rw == EXT_CMD_WRITE)? length : 0);
-  this->tx_params.rxbuf = (rw == EXT_CMD_READ)? buf : NULL;
-  this->tx_params.rxbytes = (rw == EXT_CMD_READ)? length : 0;
-
-  this->i2c_driver->acquireBus();
-  const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params);
-  this->i2c_driver->releaseBus();
-
-#ifndef NDEBUG
-  if (res) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d)\n", __FILE__ , __LINE__ , res);
-  }
-#endif
-
-  return res;
-}
-
-msg_t
-Driver::readDataFlashBlock(DataFlashBlock &block, const DataFlashSubClassID sub_id, const uint8_t sub_block)
-{
-  block.raw[0] = sub_id;
-  block.raw[1] = sub_block;
-  msg_t res = this->extCommand(EXT_CMD_DFCLS, EXT_CMD_WRITE, &block.raw[0]);
-  res |= this->extCommand(EXT_CMD_DFBLK, EXT_CMD_WRITE, &block.raw[1]);
-
-  BaseThread::sleep(US2ST(1)); // Without this delay the whole block is shifted and the first byte is lost. TODO: investigate
-  res |= this->extCommand(EXT_CMD_DFD, EXT_CMD_READ, block.raw, 33);
-
-  return res;
-}
diff --git a/components/power/ina219.cpp b/components/power/ina219.cpp
deleted file mode 100644
index 6341f1e..0000000
--- a/components/power/ina219.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-#include <amiro/power/ina219.hpp>
-
-#include <ch.hpp>
-#include <chprintf.h>
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace INA219;
-
-extern Global global;
-
-Driver::Driver(I2CDriver &i2c_driver, const uint8_t i2c_address) :
-  BaseSensor<InitData,CalibData>(), i2c_driver(&i2c_driver), tx_params({i2c_address, NULL, 0, NULL, 0}), current_lsb_uA(0)
-{
-  this->config.content.brng = Configuration::BRNG_DEFAULT;
-  this->config.content.pg = Configuration::PGA_DEFAULT;
-  this->config.content.badc = Configuration::ADC_DEFAULT;
-  this->config.content.sadc = Configuration::ADC_DEFAULT;
-  this->config.content.mode = Configuration::MODE_DEFAULT;
-
-  return;
-}
-
-Driver::~Driver()
-{}
-
-msg_t
-Driver::init(InitData* initialization_data)
-{
-  if(!initialization_data)
-  {
-    return ERROR;
-  }
-
-  // write configuration
-  if (this->writeRegister(REG_CONFIGURATION, initialization_data->configuration.value & MASK_CONFIGURATION)) {
-    return ERROR;
-  }
-  this->config.value = initialization_data->configuration.value & MASK_CONFIGURATION;
-
-  if (this->writeRegister(REG_CALIBRATION, initialization_data->calibration & MASK_CALIBRATION)) {
-    return ERROR;
-  }
-
-  this->current_lsb_uA = initialization_data->current_lsb_uA;
-
-  return this->update();
-}
-
-msg_t
-Driver::update()
-{
-  this->status.power = 0;
-  msg_t res = this->readRegister(REG_BUS_VOLTAGE, this->status.bus_voltage.value);
-  res |= this->readRegister(REG_POWER, this->status.power);
-
-  // if the power register was not updated yet, try again
-  while (!this->status.bus_voltage.content.conversion_ready || this->status.power == 0 || res != 0)
-  {
-    BaseThread::sleep(MS2ST(10));
-    res |= this->readRegister(REG_BUS_VOLTAGE, this->status.bus_voltage.value);
-    res |= this->readRegister(REG_POWER, this->status.power);
-  }
-
-  return res ? ERROR : SUCCESS;
-}
-
-msg_t
-Driver::wakeup()
-{
-  if (this->writeRegister(REG_CONFIGURATION, this->config.value)) {
-    return ERROR;
-  } else {
-    return this->update();
-  }
-}
-
-msg_t
-Driver::hibernate()
-{
-  Configuration::Register tmp_config = this->config;
-  tmp_config.content.mode = Configuration::MODE_PowerDown;
-  if (this->writeRegister(REG_CONFIGURATION, tmp_config.value)) {
-    return ERROR;
-  } else {
-    return SUCCESS;
-  }
-
-}
-
-#ifndef AMIRO_NCALIBRATION
-msg_t
-Driver::calibration(CalibData* calibration_data)
-{
-  if (!calibration_data) {
-    return ERROR;
-  }
-
-  uint16_t current_lsb_uA = calibration_data->input.current_lsb_uA;
-  if (current_lsb_uA < calibration_data->input.max_expected_current_A / 0.032767f) {
-    current_lsb_uA = calibration_data->input.max_expected_current_A / 0.032767f;
-  } else if (current_lsb_uA > calibration_data->input.max_expected_current_A / 0.004096f) {
-    current_lsb_uA = calibration_data->input.max_expected_current_A / 0.004096f;
-  }
-
-  const uint16_t calibration_value = uint16_t(40960 / (current_lsb_uA * calibration_data->input.shunt_resistance_O));
-
-  float V_shunt_max;
-  switch (calibration_data->input.configuration.content.pg)
-  {
-    case Configuration::PGA_40mV:
-      V_shunt_max = 0.04f;
-      break;
-    case Configuration::PGA_80mV:
-      V_shunt_max = 0.08f;
-      break;
-    case Configuration::PGA_160mV:
-      V_shunt_max = 0.16f;
-      break;
-    case Configuration::PGA_320mV:
-      V_shunt_max = 0.32f;
-      break;
-  }
-
-  const float max_current_before_overflow = ( (current_lsb_uA * 0.032767f >= V_shunt_max) / (calibration_data->input.shunt_resistance_O) )?
-                                            V_shunt_max / calibration_data->input.shunt_resistance_O :
-                                            current_lsb_uA * 0.032767f;
-
-  const float max_shuntvoltage_before_overflow = ( (max_current_before_overflow * calibration_data->input.shunt_resistance_O) >= V_shunt_max )?
-                                                 V_shunt_max :
-                                                 max_current_before_overflow * calibration_data->input.shunt_resistance_O;
-
-  calibration_data->output.max_current_before_overflow_A = max_current_before_overflow;
-  calibration_data->output.max_shuntvoltage_before_overflow_V = max_shuntvoltage_before_overflow;
-  calibration_data->output.current_lsb_uA = current_lsb_uA;
-  calibration_data->output.calibration_value = calibration_value;
-
-  return SUCCESS;
-}
-#endif
-
-#ifndef AMIRO_NSELFTEST
-msg_t
-Driver::selftest()
-{
-  struct RegisterContent {
-    Configuration::Register configuration;
-    uint16_t shunt_voltage = 0;
-    BusVoltage bus_voltage;
-    uint16_t power = 0;
-    uint16_t current = 0;
-    uint16_t calibration = 0;
-  };
-
-  // backup the current status
-  RegisterContent backup;
-  msg_t res = this->readRegister(REG_CONFIGURATION, backup.configuration.value);
-  res |= this->readRegister(REG_SHUNT_VOLTAGE, backup.shunt_voltage);
-  res |= this->readRegister(REG_BUS_VOLTAGE, backup.bus_voltage.value);
-  res |= this->readRegister(REG_POWER, backup.power);
-  res |= this->readRegister(REG_CURRENT, backup.current);
-  res |= this->readRegister(REG_CALIBRATION, backup.calibration);
-  if (res ||
-      !(backup.configuration.value ||
-        backup.shunt_voltage ||
-        backup.bus_voltage.value ||
-        backup.power ||
-        backup.current ||
-        backup.calibration))
-  {
-    return ST_FAIL_BACKUP;
-  }
-
-  // reset the INA219
-  if (this->reset())
-  {
-    return ST_FAIL_RESET;
-  }
-
-  // read the configuration
-  Configuration::Register config = this->readConfiguration();
-
-  // check for the default configuration
-  Configuration::Register config_default;
-  config_default.content.brng = Configuration::BRNG_DEFAULT;
-  config_default.content.pg = Configuration::PGA_DEFAULT;
-  config_default.content.badc = Configuration::ADC_DEFAULT;
-  config_default.content.sadc = Configuration::ADC_DEFAULT;
-  config_default.content.mode = Configuration::MODE_DEFAULT;
-  if (config.value != config_default.value)
-  {
-    return ST_FAIL_IS_DEFAULT;
-  }
-
-  // revert to the previous configuration
-  if (this->writeRegister(REG_CONFIGURATION, backup.configuration.value))
-  {
-    return ST_FAIL_WRITE_CONFIG;
-  }
-
-  // revert to the previous calibration
-  if (this->writeRegister(REG_CALIBRATION, backup.calibration))
-  {
-    return ST_FAIL_WRITE_CALIB;
-  }
-
-  // read the current configuration
-  if (this->readConfiguration().value != backup.configuration.value)
-  {
-    return ST_FAIL_CHECK_CONFIG;
-  }
-
-  // read the current calibration
-  if (this->readCalibration() != backup.calibration)
-  {
-    return ST_FAIL_CHECK_CALIB;
-  }
-
-  // read and print the current status
-  INA219::BusVoltage bus_voltage = this->readBusVoltage();
-  uint16_t power;
-  this->readRegister(REG_POWER, power);
-  // wait until the bus voltage and the power register are valid
-  while (!bus_voltage.conversion_ready || power == 0)
-  {
-    BaseThread::sleep(MS2ST(10));
-    bus_voltage = this->readBusVoltage();
-    this->readRegister(REG_POWER, power);
-  }
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "shunt voltage : %fV\n", this->readShuntVoltage_uV() / 1000000.f);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "bus voltage   : %fV\n", bus_voltage.voltage_uV / 1000000.f);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "power         : %fW\n", this->readPower_uW() / 1000000.f);
-  chprintf((BaseSequentialStream*) &global.sercanmux1, "current       : %fA\n", this->readCurrent_uA() / 1000000.f);
-
-  return ST_OK;
-}
-#endif
-
-Configuration::Register
-Driver::readConfiguration()
-{
-  Configuration::Register reg;
-  this->readRegister(REG_CONFIGURATION, reg.value);
-  return reg;
-}
-
-int32_t
-Driver::readShuntVoltage_uV()
-{
-  uint16_t val = 0;
-  this->readRegister(REG_SHUNT_VOLTAGE, val);
-  /*
-   * Depending on the configuration either one, two, three or four most significant bits are used for coding the sign (no two's complement!)
-   * -> Masking bits in order to separate sign bits and value bits.
-   * Furthermore, the least significant bit represents 10uV.
-   * -> Multiplication by 10 or -10 respectively.
-   */
-  switch (this->config.content.pg)
-  {
-    case Configuration::PGA_320mV:
-      return ( uint32_t(val & 0x7FFFu) * ((val & 0x8000u)? -10 : 10) );
-    case Configuration::PGA_160mV:
-      return ( uint32_t(val & 0x3FFFu) * ((val & 0xC000u)? -10 : 10) );
-    case Configuration::PGA_80mV:
-      return ( uint32_t(val & 0x1FFFu) * ((val & 0xE000u)? -10 : 10) );
-    case Configuration::PGA_40mV:
-      return ( uint32_t(val & 0x0FFFu) * ((val & 0xF000u)? -10 : 10) );
-  }
-}
-
-INA219::BusVoltage
-Driver::readBusVoltage()
-{
-  Driver::BusVoltage reg;
-  this->readRegister(REG_BUS_VOLTAGE, reg.value);
-  return this->busVoltageReg2uV(reg);
-}
-
-uint32_t
-Driver::readPower_uW()
-{
-  uint16_t val = 0;
-  this->readRegister(REG_POWER, val);
-  return this->powerReg2uW(val);
-}
-
-int32_t
-Driver::readCurrent_uA()
-{
-  uint16_t val = 0;
-  this->readRegister(REG_CURRENT, val);
-
-  /*
-   * Reinterpret register value as a signed integer (two's complement).
-   * Multiply with the value of the least significant bit.
-   */
-  return int32_t(*reinterpret_cast<int16_t*>(&val)) * this->current_lsb_uA;
-}
-
-uint16_t
-Driver::readCalibration()
-{
-  uint16_t val = 0;
-  this->readRegister(REG_CALIBRATION, val);
-  return (val & MASK_CALIBRATION);
-}
-
-uint8_t
-Driver::reset()
-{
-  const msg_t res = this->writeRegister(REG_CONFIGURATION, MASK_RESET);
-  return (res? ERROR : SUCCESS);
-}
-
-msg_t
-Driver::main(void)
-{
-  while (!this->shouldTerminate())
-  {
-    this->update();
-    //this->eventSource.broadcastFlags(0);
-    this->sleep(MS2ST(1000));
-    //this->waitAnyEventTimeout(ALL_EVENTS, MS2ST(1000));
-  }
-
-  return RDY_OK;
-}
-
-msg_t
-Driver::readRegister(const RegisterAddress reg, uint16_t& dst)
-{
-  uint8_t buffer[2];
-  this->tx_params.txbuf = reinterpret_cast<const uint8_t*>(&reg);
-  this->tx_params.txbytes = 1;
-  this->tx_params.rxbuf = buffer;
-  this->tx_params.rxbytes = 2;
-
-  this->i2c_driver->acquireBus();
-  const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params);
-  this->i2c_driver->releaseBus();
-
-  if (!res) {
-    dst = (buffer[0] << 8) | buffer[1];
-    if (reg == REG_CALIBRATION)
-      dst &= MASK_CALIBRATION;
-#ifndef NDEBUG
-  } else {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d | 0x%08X)\n", __FILE__ , __LINE__ , res, this->i2c_driver->getErrors());
-#endif
-  }
-
-  return res;
-}
-
-msg_t
-Driver::writeRegister(const RegisterAddress reg, const uint16_t& val)
-{
-  const uint8_t buffer[3] = {reg,
-                             static_cast<uint8_t>((val & 0xFF00u) >> 8),
-                             static_cast<uint8_t>(val & 0x00FFu)};
-  this->tx_params.txbuf = buffer;
-  this->tx_params.txbytes = 3;
-  this->tx_params.rxbytes = 0;
-
-  this->i2c_driver->acquireBus();
-  const msg_t res = this->i2c_driver->masterTransmit(&this->tx_params);
-  this->i2c_driver->releaseBus();
-
-#ifndef NDEBUG
-  if (res) {
-    chprintf((BaseSequentialStream*) &global.sercanmux1, "%s(%d): ERROR: i2c transmit failed (%d | 0x%08X)\n", __FILE__ , __LINE__ , res, this->i2c_driver->getErrors());
-  }
-#endif
-
-  return res;
-}
-
diff --git a/components/proximity/vcnl4020.cpp b/components/proximity/vcnl4020.cpp
deleted file mode 100644
index 5e98351..0000000
--- a/components/proximity/vcnl4020.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-#include <chdebug.h>
-#include <chprintf.h>
-
-#include <amiro/bus/i2c/I2CParams.hpp>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-#include <amiro/proximity/vcnl4020.hpp>
-#include <amiro/Constants.h>
-
-using namespace chibios_rt;
-
-namespace amiro {
-
-VCNL4020::
-~VCNL4020() {
-
-}
-
-VCNL4020::
-VCNL4020(I2CDriver *driver, const VCNL4020Config *config) :
-  BaseStaticThread<256>(),
-  driver(driver),
-  config(config),
-  ambient(0x0000u),
-  proximity(0x0000u),
-  proximityOffset(0x0000u) {
-
-  this->tx_params.addr = VCNL4020::SLA;
-
-}
-
-uint16_t
-VCNL4020::
-getAmbientLight() {
-
-  return this->ambient;
-}
-
-void
-VCNL4020::
-setProximityOffset(uint16_t offset) {
-
-  this->proximityOffset = offset;
-}
-
-uint16_t
-VCNL4020::
-getProximityOffset() {
-
-  return this->proximityOffset;
-}
-
-EvtSource*
-VCNL4020::
-getEventSource() {
-
-  return &this->eventSource;
-}
-
-uint16_t
-VCNL4020::
-getProximity() {
-
-  return this->proximity;
-}
-
-uint16_t
-VCNL4020::
-getProximityScaledWoOffset() {
-
-  if (this->proximity <= this->proximityOffset)
-    return 0;
-
-  // Scale factor for the offset-less proximity value, so that we can reach full-scale
-  const float scaleFactor = float(0xFFFFu) / float((0xFFFFu - this->proximityOffset));
-
-  return uint16_t(float(this->proximity - this->proximityOffset) * scaleFactor);
-}
-
-msg_t
-VCNL4020::
-main(void) {
-
-  I2CDriver *drv = this->driver;
-  msg_t res;
-
-  this->setName("Vcnl4020");
-
-  drv->acquireBus();
-
-  /* exit if writing configuration fails */
-  res = this->writeIRConf();
-
-  drv->releaseBus();
-
-  if (res)
-    return RDY_RESET;
-
-  //TODO Read calibration from eeprom
-
-  while (!this->shouldTerminate()) {
-
-    drv->acquireBus();
-
-    this->readIntensities();
-    drv->releaseBus();
-
-    this->eventSource.broadcastFlags(0);
-
-    this->waitAnyEventTimeout(ALL_EVENTS, CAN::UPDATE_PERIOD);
-  }
-
-  return RDY_OK;
-}
-
-msg_t
-VCNL4020::
-writeIRConf() {
-
-  msg_t res;
-  const VCNL4020Config *cfg = this->config;
-
-  uint8_t buffer[4];
-  this->tx_params.txbuf = buffer;
-  this->tx_params.txbytes = 4;
-  this->tx_params.rxbytes = 0;
-
-  buffer[0] = offsetof(VCNL4020::registers, proximity_rate);
-  buffer[1] = cfg->proximity_rate;
-  buffer[2] = cfg->ir_led_current_mA > 200 ? 20u : cfg->ir_led_current_mA / 10u;
-  buffer[3] = cfg->ambient_parameter;
-
-  res = this->driver->masterTransmit(&this->tx_params);
-
-  buffer[0] = offsetof(VCNL4020::registers, command);
-  buffer[1] = cfg->command;
-
-  this->tx_params.txbytes = 2;
-
-  if (!res)
-    res = this->driver->masterTransmit(&this->tx_params);
-
-  return res;
-}
-
-msg_t
-VCNL4020::
-readIntensities() {
-
-  msg_t res;
-  uint8_t buffer[4];
-  uint8_t reg = offsetof(VCNL4020::registers, ambient_result);
-  this->tx_params.txbuf = &reg;
-  this->tx_params.txbytes = 1;
-  this->tx_params.rxbuf = buffer;
-  this->tx_params.rxbytes = 4;
-
-  res = this->driver->masterTransmit(&this->tx_params);
-
-  if (!res) {
-
-    /* update internal values */
-    this->ambient = (buffer[0] << 8) | buffer[1];
-    this->proximity = (buffer[2] << 8) | buffer[3];
-
-  }
-
-  return res;
-
-}
-
-uint8_t
-VCNL4020::
-getCheck(void) {
-
-  int8_t resTx;
-  uint8_t rxBuffer[2]; /** This is a bug workaround: 1 byte is impossible to read on STM32F1*/
-  const uint8_t txBuffer = uint8_t(offsetof(VCNL4020::registers, revision));
-
-  // Use own datastructure, so that there is now faulty
-  // behaviour with the other threads using it
-  I2CTxParams tx_params = this->tx_params;
-  tx_params.txbuf = &txBuffer;
-  tx_params.txbytes = 1;
-  tx_params.rxbytes = 2; /** This is a bug workaround: 1 byte is impossible to read on STM32F1*/
-  tx_params.rxbuf = rxBuffer;
-
-  // Read the data
-  resTx = this->driver->masterTransmit(&tx_params);
-  // Failed to transmit
-  if (resTx != RDY_OK || VCNL4020::PRODUCT_ID_REVISION != rxBuffer[0]) {
-    return VCNL4020::CHECK_FAIL;
-  } else {
-    return VCNL4020::CHECK_OK;
-  }
-
-}
-
-uint8_t
-VCNL4020::
-calibrate() {
-
-  uint16_t proximityFloorMeanValue;
-
-  // Get the offset
-  msg_t res = calibrateOffset(proximityFloorMeanValue);
-  if (res == CALIB_OK) {
-    this->proximityOffset = proximityFloorMeanValue;
-    //TODO Write value to eeprom
-    return res;
-  } else {
-    return res;
-  }
-
-}
-
-uint8_t
-VCNL4020::
-calibrateOffset(uint16_t &proximityFloorMeanValue) {
-
-  uint32_t tmpProximityFloorMeanValue;
-
-  // Register an event listener, to receive updates
-  chibios_rt::EvtListener eventTimerEvtListener;
-  chibios_rt::EvtSource *vcnlEvtSource;
-  vcnlEvtSource = reinterpret_cast<EvtSource *>(this->getEventSource());
-  vcnlEvtSource->registerOne(&eventTimerEvtListener,0);
-
-  // Get the first values
-  tmpProximityFloorMeanValue = this->getProximity();
-
-  // Get the others with a floating mean
-  const uint32_t maxValues = 20;
-  for (uint32_t idxMean = 2; idxMean <= maxValues; ++idxMean) {
-    this->waitOneEvent(ALL_EVENTS); /* Wait for a new update */
-    tmpProximityFloorMeanValue = (((idxMean-1) * tmpProximityFloorMeanValue) + uint32_t(this->getProximity())) / idxMean;
-  }
-
-  vcnlEvtSource->unregister(&eventTimerEvtListener);
-
-  // Cast the calculated offset to the temporary member variable
-  proximityFloorMeanValue = uint16_t(tmpProximityFloorMeanValue);
-
-  return CALIB_OK;
-}
-
-} /* amiro */
diff --git a/components/radio/a2500r24a.cpp b/components/radio/a2500r24a.cpp
deleted file mode 100644
index 5167b77..0000000
--- a/components/radio/a2500r24a.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <string.h>
-
-#include <amiro/util/util.h>
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/radio/a2500r24a.hpp>
-
-namespace amiro {
-
-A2500R24A::A2500R24A(HWSPIDriver *driver)
-    : driver(driver) {
-
-}
-
-A2500R24A::~A2500R24A() {
-
-}
-
-chibios_rt::EvtSource*
-A2500R24A::getEventSource() {
-  return &this->eventSource;
-}
-
-msg_t A2500R24A::main() {
-
-  while (!this->shouldTerminate()) {
-
-    updateSensorData();
-
-    this->eventSource.broadcastFlags(0);
-
-    this->waitAnyEventTimeout(ALL_EVENTS, MS2ST(200));
-
-  }
-  return RDY_OK;
-}
-
-void A2500R24A::updateSensorData() {
-
-}
-
-msg_t A2500R24A::configure(A2500R24AConfig *config) {
-
-  return RDY_OK;
-
-}
-
-uint8_t A2500R24A::getCheck() {
-
-  const size_t buffer_size = 1 /* addressing */
-                              + 1; /* who am i */
-  uint8_t buffer[buffer_size];
-
-  // Exchange the data with the A2500R24A radio chip
-  // Specify the adress and the mode
-  buffer[0] =  offsetof(A2500R24A::registerStatus, PARTNUM) | A2500R24A::SPI_READ | A2500R24A::SPI_STATUS_ACCESS;
-  this->driver->exchange(buffer, buffer, buffer_size);
-  // Check
-  if (buffer[1] == A2500R24A::A2500R24A_PARTNUM) {
-          return A2500R24A::CHECK_OK;
-  } else {
-          return A2500R24A::CHECK_FAIL;
-  }
-
-}
-
-} /* amiro */
diff --git a/components/serial_reset/iwrap_can_mux.cpp b/components/serial_reset/iwrap_can_mux.cpp
deleted file mode 100644
index f8d7318..0000000
--- a/components/serial_reset/iwrap_can_mux.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-#include <ch.h>
-#include <hal.h>
-#include <string.h>  // memcpy
-#include <chprintf.h>
-#include <amiro/Constants.h>
-
-#include <amiro/serial_reset/iwrap_can_mux.hpp>
-
-using namespace amiro;
-using namespace chibios_rt;
-
-IwrapCanMux::IwrapCanMux(SerialDriver *_sd_, CANDriver *can, const uint8_t boardId)
-  : BaseSequentialStreamInterface(),
-    sd_(_sd_),
-    canDriver(can)
-{
-    myID = boardId;
-    queryShellID = boardId;
-    replyShellID = boardId;
-
-    resetStatus = 0;
-    resetAddBytes = 0;
-
-    txmsg.IDE = CAN_IDE_STD;
-    txmsg.RTR = CAN_RTR_DATA;
-    txmsg.DLC = 0;
-
-    bluetoothStatus = BLUETOOTH_STATUS_START;
-}
-
-IwrapCanMux::~IwrapCanMux() {
-
-};
-
-
-/* Check bluetooth status
-void IwrapCanMux::checkBluetoothStatus(void) {
-
-      BluetoothUartReceiveByte(&byteData);
-      switch (bluetoothStatus) {
-
-        case BLUETOOTH_STATUS_START:
-          if (byteData == BLUETOOTH_START_FRAME) {
-            bluetoothStatus++;
-          }
-          break;
-
-        case BLUETOOTH_STATUS_LINK:
-            bluetoothLinkID = byteData;
-            bluetoothStatus++;
-          break;
-
-        case BLUETOOTH_STATUS_FLAGS:
-          if (byteData == BLUETOOTH_FLAGS) {
-            bluetoothStatus++;
-          } else {
-            bluetoothStatus = BLUETOOTH_STATUS_START;
-          }
-          break;
-
-        case BLUETOOTH_STATUS_LENGTH:
-          bluetoothStatus++;
-          bluetoothDataLength = byteData;
-          break;
-
-        case BLUETOOTH_STATUS_DATA:
-          if (--bluetoothDataLength == 0) {
-            bluetoothStatus++;
-          }
-          if (bluetoothLinkID == 0xFF) {
-          } else {
-            // read data
-          }
-          break;
-
-        default:
-          bluetoothStatus = BLUETOOTH_STATUS_START;
-          if (byteData == ~bluetoothLinkID) {
-            // iWRAP check
-          }
-          break;
-      }
-}
-*/
-
-
-/*
- * resets system for entering in bootloader.
- */
-void IwrapCanMux::restartSystem(void) {
-  //TODO Set reset SYS_PD_N
-  NVIC_SystemReset();
-}
-
-/*
- * checks bytes for reset command sequence.
- * if the last byte and the following identification number of the device have been sent,
- * the microcontroller will be reset
- */
-bool IwrapCanMux::checkByteForBLReset(uint8_t *inputs, size_t size) {
-  /* Run throug all given bytes */
-  for (size_t idx=0; idx < size; idx++) {
-    uint8_t input = *(inputs+idx);
-
-    /*
-     * if the last byte of reset command sequence has not been sent yet,
-     * check new byte and handle reset status
-     */
-    if (resetStatus < INPUT_BL_RESET_LENGTH) {
-      if (input == inputBLReset[resetStatus]) {
-        resetStatus++;
-        if (resetStatus == INPUT_BL_RESET_LENGTH) {
-          chprintf((BaseSequentialStream*)sd_, "\n\nDo reset ...\n\n");
-          uint8_t ledCount;
-          for (ledCount=0; ledCount<20; ledCount++) {
-//            boardWriteLed(1);
-            chThdSleepMilliseconds(100);
-//            boardWriteLed(0);
-            chThdSleepMilliseconds(100);
-          }
-          restartSystem();
-        }
-      } else {
-        resetStatus = 0;
-        resetAddBytes = 0;
-      }
-
-    /*
-     * if the last byte of reset command sequence has been sent,
-     * save new byte as identification number of the device which shall be flashed and
-     * reset microcontroller
-     */
-    } else {
-      inputAddBytes[resetAddBytes] = input;
-      resetAddBytes++;
-      if (resetAddBytes >= INPUT_BL_RESET_ADDITIONAL_BYTES) {
-        chprintf((BaseSequentialStream*)sd_, "\n\nAt device %x: Do reset ...\n\n", input);
-        chThdSleepMilliseconds(OFFSET_TIME_RESET_MS);
-        restartSystem();
-      }
-    }
-  }
-
-  return (resetStatus > 0);
-}
-
-msg_t IwrapCanMux::sendViaCan(uint32_t id, uint8_t *inputs, size_t size) {
-  msg_t status;
-  txmsg.SID = (id << CAN::DEVICE_ID_SHIFT) | myID;
-  for (size_t i=0; i<size; i+=8) {
-    txmsg.DLC = (size < (i + 8)) ? size-i : 8;
-    memcpy(txmsg.data8, &inputs[i], txmsg.DLC);
-    status = canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, TIME_INFINITE);
-    if (status!= RDY_OK)
-      return status;
-  }
-
-  return RDY_OK;
-}
-
-/*
- * Interface implementation.
- */
-
-size_t IwrapCanMux::write(const uint8_t *bp, size_t n) {
-  size_t size;
-
-  if (myID != replyShellID) {
-     msg_t status = sendViaCan(CAN::SHELL_REPLY_ID(replyShellID), (uint8_t *)bp, n);
-     BaseThread::sleep(US2ST(500));
-     size = (status == RDY_OK) ? n : 0;
-  } else {
-    size = sdWrite(sd_, bp, n);
-  }
-
-  return size;
-}
-
-size_t IwrapCanMux::read(uint8_t *bp, size_t n) {
-  size_t size = sdRead(sd_, inputChar, n);
-
-  checkByteForBLReset(inputChar, size);
-
-  if (myID != queryShellID)
-    sendViaCan(CAN::SHELL_QUERY_ID(queryShellID),inputChar, size);
-  else
-    memcpy(bp, inputChar, size);
-
-  return size;
-}
-
-msg_t IwrapCanMux::put(uint8_t b) {
-  msg_t byte;
-
-  if (myID != replyShellID) {
-    byte = sendViaCan(CAN::SHELL_REPLY_ID(replyShellID), &b, 1);
-    BaseThread::sleep(US2ST(200));
-  } else {
-    byte = sdPut(sd_, b);
-  }
-
-  return byte;
-}
-
-msg_t IwrapCanMux::get(void) {
-  msg_t byte = sdGet(sd_);
-  uint8_t b = (uint8_t) byte;
-
-  checkByteForBLReset(&b, 1);
-
-  if (myID != queryShellID)
-    sendViaCan(CAN::SHELL_QUERY_ID(queryShellID), &b, 1);
-
-  return byte;
-}
-
-//----------------------------------------------------------------
-
-/*
- * Converse data from CAN bus into input queue of serial driver.
- */
-
-void IwrapCanMux::convCan2Serial(uint8_t *data_can, size_t n) {
-  chSysLock();
-  for (size_t i=0; i < n; i++)
-     sdIncomingDataI(sd_, data_can[i]);
-  chSysUnlock();
-}
-
-void IwrapCanMux::sendSwitchCmd(uint8_t setid) {
-
-  if (myID == setid)
-    chprintf((BaseSequentialStream*)sd_, "Stay at the same shell\n");
-  else if (replyShellID == setid)
-    chprintf((BaseSequentialStream*)sd_, "Switch to the own shell\n");
-  else
-    chprintf((BaseSequentialStream*)sd_, "Switch to the shell on board %d\n", setid);
-
-  if (myID != setid) {
-
-    if (replyShellID != setid)  {
-      // To set the new remote shell via CAN bus.
-      txmsg.SID = ((CAN::SHELL_QUERY_ID(setid)) << CAN::DEVICE_ID_SHIFT) | replyShellID;
-      txmsg.DLC = 0;
-      canTransmit(canDriver, CAN_ANY_MAILBOX, &txmsg, US2ST(545));
-    }
-
-    if (replyShellID == myID) {
-      queryShellID = setid;
-    } else {
-      if (replyShellID == setid)
-        // To return the own shell via CAN bus.
-        txmsg.SID = ((CAN::SHELL_QUERY_ID(replyShellID)) << CAN::DEVICE_ID_SHIFT) | replyShellID;
-      else
-        // To set the serial board to the new remote shell.
-        txmsg.SID = ((CAN::SHELL_QUERY_ID(replyShellID)) << CAN::DEVICE_ID_SHIFT) | setid;
-
-      txmsg.DLC = 0;
-      canTransmit(canDriver, CAN_ANY_MAILBOX, &txmsg, US2ST(545));
-
-      replyShellID = myID;
-    }
-  }
-}
-
-void IwrapCanMux::rcvSwitchCmd(uint8_t setid) {
-
-  if (myID == setid) {
-    chprintf((BaseSequentialStream*)sd_, "\nReturn own shell\n\n");
-    queryShellID = setid;
-  } else if (myID != queryShellID) {
-    chprintf((BaseSequentialStream*)sd_, "\nSwitch to the shell on board %d\n", setid);
-    queryShellID = setid;
-  } else {
-    chprintf((BaseSequentialStream*)sd_, "\nShell shown in board %d\n\n", setid);
-    replyShellID = setid;
-  }
-}
diff --git a/components/serial_reset/serial_can_mux.cpp b/components/serial_reset/serial_can_mux.cpp
deleted file mode 100644
index 52425f0..0000000
--- a/components/serial_reset/serial_can_mux.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-#include <ch.h>
-#include <hal.h>
-#include <string.h>  // memcpy
-#include <chprintf.h>
-#include <amiro/Constants.h>
-
-#include <amiro/serial_reset/serial_can_mux.hpp>
-
-using namespace amiro;
-using namespace chibios_rt;
-
-SerialCanMux::SerialCanMux(SerialDriver *_sd_, CANDriver *can, const uint8_t boardId)
-  : BaseSequentialStreamInterface(),
-    sd_(_sd_),
-    canDriver(can)
-{
-//    oqueue(ob, 500, NULL, NULL);
-    myID = boardId;
-    queryShellID = boardId;
-    replyShellID = boardId;
-
-    resetStatus = 0;
-    resetAddBytes = 0;
-
-    txmsg.IDE = CAN_IDE_STD;
-    txmsg.RTR = CAN_RTR_DATA;
-    txmsg.DLC = 0;
-}
-
-SerialCanMux::~SerialCanMux() {
-
-};
-
-/*
- * resets system for entering in bootloader.
- */
-void SerialCanMux::restartSystem(void) {
-  //TODO Set reset SYS_PD_N
-  NVIC_SystemReset();
-}
-
-/*
- * checks bytes for reset command sequence.
- * if the last byte and the following identification number of the device have been sent,
- * the microcontroller will be reset
- */
-bool SerialCanMux::checkByteForBLReset(uint8_t *inputs, size_t size) {
-  /* Run throug all given bytes */
-  for (size_t idx=0; idx < size; idx++) {
-    uint8_t input = *(inputs+idx);
-
-    /*
-     * if the last byte of reset command sequence has not been sent yet,
-     * check new byte and handle reset status
-     */
-    if (resetStatus < INPUT_BL_RESET_LENGTH) {
-      if (input == inputBLReset[resetStatus]) {
-        resetStatus++;
-        if (resetStatus == INPUT_BL_RESET_LENGTH) {
-          chprintf((BaseSequentialStream*)sd_, "\n\nDo reset ...\n\n");
-          uint8_t ledCount;
-          for (ledCount=0; ledCount<20; ledCount++) {
-//            boardWriteLed(1);
-            chThdSleepMilliseconds(100);
-//            boardWriteLed(0);
-            chThdSleepMilliseconds(100);
-          }
-          restartSystem();
-        }
-      } else {
-        resetStatus = 0;
-        resetAddBytes = 0;
-      }
-
-    /*
-     * if the last byte of reset command sequence has been sent,
-     * save new byte as identification number of the device which shall be flashed and
-     * reset microcontroller
-     */
-    } else {
-      inputAddBytes[resetAddBytes] = input;
-      resetAddBytes++;
-      if (resetAddBytes >= INPUT_BL_RESET_ADDITIONAL_BYTES) {
-        chprintf((BaseSequentialStream*)sd_, "\n\nAt device %x: Do reset ...\n\n", input);
-        chThdSleepMilliseconds(OFFSET_TIME_RESET_MS);
-        restartSystem();
-      }
-    }
-  }
-
-  return (resetStatus > 0);
-}
-
-
-msg_t SerialCanMux::sendViaCan(uint32_t id, uint8_t *inputs, size_t size) {
-  msg_t status;
-  txmsg.SID = (id << CAN::DEVICE_ID_SHIFT) | myID;
-  for (size_t i=0; i<size; i+=8) {
-    txmsg.DLC = (size < (i + 8)) ? size-i : 8;
-    memcpy(txmsg.data8, &inputs[i], txmsg.DLC);
-    status = canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, TIME_INFINITE);
-    if (status!= RDY_OK)
-      return status;
-  }
-
-  return RDY_OK;
-}
-
-//----------------------------------------------------------------
-
-/*
- * Interface implementation.
- */
-
-size_t SerialCanMux::write(const uint8_t *bp, size_t n) {
-  size_t size;
-
-  if (myID != replyShellID) {
-     msg_t status = sendViaCan(CAN::SHELL_REPLY_ID(replyShellID), (uint8_t *)bp, n);
-     BaseThread::sleep(US2ST(500));
-     size = (status == RDY_OK) ? n : 0;
-  } else {
-    size = sdWrite(sd_, bp, n);
-  }
-
-  return size;
-}
-
-size_t SerialCanMux::read(uint8_t *bp, size_t n) {
-  size_t size = sdRead(sd_, inputChar, n);
-
-  checkByteForBLReset(inputChar, size);
-
-  if (myID != queryShellID)
-    sendViaCan(CAN::SHELL_QUERY_ID(queryShellID),inputChar, size);
-  else
-    memcpy(bp, inputChar, size);
-
-  return size;
-}
-
-msg_t SerialCanMux::put(uint8_t b) {
-  msg_t byte;
-
-  if (myID != replyShellID) {
-    byte = sendViaCan(CAN::SHELL_REPLY_ID(replyShellID), &b, 1);
-    BaseThread::sleep(US2ST(200));
-  } else {
-    byte = sdPut(sd_, b);
-  }
-
-  return byte;
-}
-
-msg_t SerialCanMux::get(void) {
-  msg_t byte = sdGet(sd_);
-  uint8_t b = (uint8_t) byte;
-
-  checkByteForBLReset(&b, 1);
-
-  if (myID != queryShellID)
-    sendViaCan(CAN::SHELL_QUERY_ID(queryShellID), &b, 1);
-
-  return byte;
-}
-
-//----------------------------------------------------------------
-
-/*
- * Converse data from CAN bus into input queue of serial driver.
- */
-
-void SerialCanMux::convCan2Serial(uint8_t *data_can, size_t n) {
-  chSysLock();
-  for (size_t i=0; i < n; i++)
-     sdIncomingDataI(sd_, data_can[i]);
-  chSysUnlock();
-}
-
-void SerialCanMux::sendSwitchCmd(uint8_t setid) {
-
-  if (myID == setid)
-    chprintf((BaseSequentialStream*)sd_, "Stay at the same shell\n");
-  else if (replyShellID == setid)
-    chprintf((BaseSequentialStream*)sd_, "Switch to the own shell\n");
-  else
-    chprintf((BaseSequentialStream*)sd_, "Switch to the shell on board %d\n", setid);
-
-  if (myID != setid) {
-
-    if (replyShellID != setid)  {
-      // To set the new remote shell via CAN bus.
-      txmsg.SID = ((CAN::SHELL_QUERY_ID(setid)) << CAN::DEVICE_ID_SHIFT) | replyShellID;
-      txmsg.DLC = 0;
-      canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, US2ST(545));
-    }
-
-    if (replyShellID == myID) {
-      queryShellID = setid;
-    } else {
-      if (replyShellID == setid)
-        // To return the own shell via CAN bus.
-        txmsg.SID = ((CAN::SHELL_QUERY_ID(replyShellID)) << CAN::DEVICE_ID_SHIFT) | replyShellID;
-      else
-        // To set the serial board to the new remote shell.
-        txmsg.SID = ((CAN::SHELL_QUERY_ID(replyShellID)) << CAN::DEVICE_ID_SHIFT) | setid;
-
-      txmsg.DLC = 0;
-      canTransmit(canDriver, CAN_TX_MAILBOXES, &txmsg, US2ST(545));
-
-      replyShellID = myID;
-    }
-  }
-}
-
-void SerialCanMux::rcvSwitchCmd(uint8_t setid) {
-
-  if (myID == setid) {
-    chprintf((BaseSequentialStream*)sd_, "\nReturn own shell\n\n");
-    queryShellID = setid;
-  } else if (myID != queryShellID) {
-    chprintf((BaseSequentialStream*)sd_, "\nSwitch to the shell on board %d\n", setid);
-    queryShellID = setid;
-  } else {
-    chprintf((BaseSequentialStream*)sd_, "\nShell shown in board %d\n\n", setid);
-    replyShellID = setid;
-  }
-}
diff --git a/devices/DiWheelDrive/DiWheelDrive.cpp b/devices/DiWheelDrive/DiWheelDrive.cpp
deleted file mode 100644
index e43991f..0000000
--- a/devices/DiWheelDrive/DiWheelDrive.cpp
+++ /dev/null
@@ -1,280 +0,0 @@
-#include "ch.hpp"
-#include "hal.h"
-#include "qei.h"
-#include "DiWheelDrive.h"
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace types;
-
-extern volatile uint32_t shutdown_now;
-extern Global global;
-
-DiWheelDrive::DiWheelDrive(CANDriver *can)
-    : ControllerAreaNetworkTx(can, CAN::DI_WHEEL_DRIVE_ID),
-      ControllerAreaNetworkRx(can, CAN::DI_WHEEL_DRIVE_ID),
-      bcCounter(0)
-{
-}
-
-msg_t DiWheelDrive::receiveMessage(CANRxFrame *frame) {
-  int deviceId = this->decodeDeviceId(frame);
-
-  switch (deviceId) {
-
-    case CAN::SHELL_REPLY_ID(CAN::DI_WHEEL_DRIVE_ID):
-      if (frame->DLC > 0) {
-        sdWrite(&SD1, frame->data8, frame->DLC);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::SHELL_QUERY_ID(CAN::DI_WHEEL_DRIVE_ID):
-      if (frame->DLC != 0) {
-        global.sercanmux1.convCan2Serial(frame->data8, frame->DLC);
-        return RDY_OK;
-      } else {
-        global.sercanmux1.rcvSwitchCmd(this->decodeBoardId(frame));
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::TARGET_SPEED_ID:
-      if (frame->DLC == 8) {
-        global.distcontrol.deactivateController();
-        kinematic targetVelocity;
-        targetVelocity.x = frame->data32[0];
-        targetVelocity.w_z = frame->data32[1];
-        global.motorcontrol.setTargetSpeed(targetVelocity);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::TARGET_RPM_ID:
-      if (frame->DLC == 8) {
-        global.distcontrol.deactivateController();
-        global.motorcontrol.setTargetRPM(frame->data32[0], frame->data32[1]);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::SET_ODOMETRY_ID:
-      if (frame->DLC == 8) {
-        int32_t robotPositionX = (frame->data8[0] << 8 | frame->data8[1] << 16 | frame->data8[2] << 24);
-        int32_t robotPositionY = (frame->data8[3] << 8 | frame->data8[4] << 16 | frame->data8[5] << 24);
-        int32_t robotPositionF_Z = (frame->data8[6] << 8 | frame->data8[7] << 16);
-        global.odometry.setPosition(float(robotPositionX)*1e-6,float(robotPositionY)*1e-6,float(robotPositionF_Z)*1e-6);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::BROADCAST_SHUTDOWN:
-      if (frame->DLC == 2 && frame->data16[0] == CAN::SHUTDOWN_MAGIC) {
-        shutdown_now = 0x4;
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::CALIBRATE_PROXIMITY_FLOOR:
-      // Dont care about the payload but start the calibration
-      // TODO Care about the payload. Differ between:
-      // 1: Do fresh calibration (Save values to memory and to temporary values)
-      // 2: Remove temporary Calibration and get uncalibrated values
-      // 3: Load calibration from memory
-      this->calibrate();
-      break;
-
-    case CAN::TARGET_POSITION_ID:
-      if (frame->DLC == 8) {
-        // Robot target position [x] = µm, [f_z] = µrad, [t] = ms
-        int32_t robotPositionX = (frame->data8[0] << 8 | frame->data8[1] << 16 | frame->data8[2] << 24);
-        int32_t robotPositionF_Z = (frame->data8[3] << 8 | frame->data8[4] << 16 | frame->data8[5] << 24);
-        uint16_t targetTimeMilliSeconds = (frame->data8[6] | frame->data8[7] << 8);
-        //chprintf((BaseSequentialStream*) &SD1, "\nx=%d\nf_z=%d\nt=%d", robotPositionX, robotPositionF_Z, targetTimeMilliSeconds);
-        global.distcontrol.setTargetPosition(robotPositionX, robotPositionF_Z, targetTimeMilliSeconds);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::SET_KINEMATIC_CONST_ID:
-      if (frame->DLC == 8) {
-/*        // Set (but do not store) Ed
-        global.motorcontrol.setWheelDiameterCorrectionFactor(static_cast<float>(frame->data32[0]), false);
-        // Set (but do not store) Eb
-        global.motorcontrol.setActualWheelBaseDistance(static_cast<float>(frame->data32[1]), false);
-        return RDY_OK;*/
-        // Set (but do not store) Ed
-        uint32_t ed_int = static_cast<uint32_t>(frame->data32[0]);
-        float ed_float = static_cast<float>(ed_int)/1000000.0;
-        global.motorcontrol.setWheelDiameterCorrectionFactor(ed_float, false);
-        // Set (but do not store) Eb
-        uint32_t eb_int = static_cast<uint32_t>(frame->data32[1]);
-        float eb_float = static_cast<float>(eb_int)/1000000.0;
-        global.motorcontrol.setActualWheelBaseDistance(eb_float, false);
-        //chprintf((BaseSequentialStream*) &SD1, "Edi=%i, Edf=%f, Ebi=%i, Ebf=%f\n", ed_int, ed_float, eb_int, eb_float);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::POWER_STATUS_ID:
-      if (frame->DLC == 6) {
-        // The power status is evaluated by inherited ControllerAreaNetworkRx object, but depending on the flags the power path controller needs to enabled or disabled.
-        types::power_status::ChargingState charging_flags;
-        charging_flags.value = frame->data8[0];
-        global.ltc4412.enable(charging_flags.content.diwheeldrive_enable_power_path);
-        // Do not return with RDY_OK, or the inherited ControllerAreaNetworkRx object would not evaluate the rest of this message.
-      }
-    break;
-
-    default:
-      break;
-  }
-  return -1;
-}
-
-msg_t DiWheelDrive::updateSensorVal() {
-
-  // Update robot velocity values
-  kinematic currentVelocity = global.motorcontrol.getCurrentVelocity();
-  this->actualSpeed[0] = currentVelocity.x;
-  this->actualSpeed[1] = currentVelocity.w_z;
-
-  // Update odometry values
-  this->robotPosition = global.odometry.getPosition();
-
-  // Update proximity values
-  for (int idx = 0; idx < 4; ++idx)
-    this->proximityFloorValue[idx] = global.vcnl4020[idx].getProximityScaledWoOffset();
-
-  // Update magnetometer values
-  for (uint8_t axis = 0; axis < 3; ++axis) {
-    this->magnetometerValue[axis] = global.hmc5883l.getMagnetizationGauss(axis);
-  }
-
-  // Update gyroscope values
-  for (uint8_t axis = 0; axis < 3; ++axis) {
-    this->gyroscopeValue[axis] = global.l3g4200d.getAngularRate(axis);
-  }
-
-  return 0;
-}
-
-void DiWheelDrive::periodicBroadcast() {
-  CANTxFrame frame;
-  frame.SID = 0;
-
-  // Send the velocites µm/s of the x axis and µrad/s around z axis: start
-  this->encodeDeviceId(&frame, CAN::ACTUAL_SPEED_ID);
-  frame.data32[0] = this->actualSpeed[0];
-  frame.data32[1] = this->actualSpeed[1];
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-
-  // Send the valocites µm/s of the x axis and µrad/s around z axis: end
-  // Send the odometry: start
-  BaseThread::sleep(US2ST(10)); // Use to sleep for 10 CAN cycle (@1Mbit), otherwise the cognition-board might not receive all messagee
-  // Set the frame id
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::ODOMETRY_ID);
-  // Cut of the first byte, which precission is not needed
-  int32_t x_mm = (this->robotPosition.x >> 8);
-  int32_t y_mm = (this->robotPosition.y >> 8);
-  int16_t f_z_mrad = int16_t(this->robotPosition.f_z >> 8 );
-  // Copy the data structure
-  memcpy((uint8_t *)&(frame.data8[0]), (uint8_t *)&x_mm, 3);
-  memcpy((uint8_t *)&(frame.data8[3]), (uint8_t *)&y_mm, 3);
-  memcpy((uint8_t *)&(frame.data8[6]), (uint8_t *)&f_z_mrad, 2);
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-
-  // Send the odometry: end
-  // Send the proximity values of the floor: start
-  BaseThread::sleep(US2ST(10)); // Use to sleep for 10 CAN cycle (@1Mbit), otherwise the cognition-board might not receive all messagee
-  // Set the frame id
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::PROXIMITY_FLOOR_ID);
-  frame.data16[0] = this->proximityFloorValue[0];
-  frame.data16[1] = this->proximityFloorValue[1];
-  frame.data16[2] = this->proximityFloorValue[2];
-  frame.data16[3] = this->proximityFloorValue[3];
-  frame.DLC = 8;
-  this->transmitMessage(&frame);
-
-  // Send the magnetometer data
-  for (uint8_t axis = 0; axis < 3; ++axis) {
-    frame.SID = 0;
-    this->encodeDeviceId(&frame, CAN::MAGNETOMETER_X_ID + axis); // Y- and Z-axis have according IDs
-    frame.data32[0] = this->magnetometerValue[axis];
-    frame.DLC = 4;
-    this->transmitMessage(&frame);
-  }
-
-  // Send gyroscope data
-  frame.SID = 0;
-  this->encodeDeviceId(&frame, CAN::GYROSCOPE_ID);
-  frame.data16[0] = this->gyroscopeValue[0];
-  frame.data16[1] = this->gyroscopeValue[1];
-  frame.data16[2] = this->gyroscopeValue[2];
-  frame.DLC = 6;
-  this->transmitMessage(&frame);
-
-  // Send the board ID (board ID of DiWheelDrive = Robot ID)
-  if (this->bcCounter % 10 == 0) {
-    frame.SID = 0;
-    this->encodeDeviceId(&frame, CAN::ROBOT_ID);
-    frame.data8[0] = this->robotId;
-    frame.DLC = 1;
-    this->transmitMessage(&frame);
-  }
-
-  ++this->bcCounter;
-}
-
-void DiWheelDrive::calibrate() {
-  // Stop sending and receiving of values to indicate the calibration phase
-//   eventTimerEvtSource->unregister(&this->eventTimerEvtListener);
-//   rxFullCanEvtSource->unregister(&this->rxFullCanEvtListener);
-
-  this->calibrateProximityFloorValues();
-
-  // Start sending and receving of values
-//   eventTimerEvtSource->registerOne(&this->eventTimerEvtListener, CAN::PERIODIC_TIMER_ID);
-//   rxFullCanEvtSource->registerOne(&this->rxFullCanEvtListener, CAN::RECEIVED_ID);
-
-}
-
-void DiWheelDrive::calibrateProximityFloorValues() {
-
-  uint16_t buffer;
-  for (uint8_t idx = 0; idx < 4; ++idx) {
-    global.vcnl4020[idx].calibrate();
-    buffer = global.vcnl4020[idx].getProximityOffset();
-    global.memory.setVcnl4020Offset(buffer,idx);
-  }
-
-}
-
-ThreadReference DiWheelDrive::start(tprio_t PRIO) {
-  // set the robot ID as the board ID, which is read from the memory
-  if (global.memory.getBoardId(&this->robotId) != fileSystemIo::FileSystemIoBase::OK) {
-    this->robotId = 0;
-  }
-
-  this->ControllerAreaNetworkRx::start(PRIO + 1);
-  this->ControllerAreaNetworkTx::start(PRIO);
-  return NULL;
-}
-
-msg_t
-DiWheelDrive::terminate(void) {
-  msg_t ret = RDY_OK;
-
-  this->ControllerAreaNetworkTx::requestTerminate();
-  ret |= this->ControllerAreaNetworkTx::wait();
-  this->ControllerAreaNetworkRx::requestTerminate();
-  ret |= this->ControllerAreaNetworkRx::wait();
-
-  return ret;
-}
diff --git a/devices/DiWheelDrive/DiWheelDrive.h b/devices/DiWheelDrive/DiWheelDrive.h
deleted file mode 100644
index 0ee13ed..0000000
--- a/devices/DiWheelDrive/DiWheelDrive.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef AMIRO_DI_WHEEL_DRIVE_H_
-#define AMIRO_DI_WHEEL_DRIVE_H_
-
-#include <amiro/ControllerAreaNetworkRx.h>
-#include <amiro/ControllerAreaNetworkTx.h>
-#include <amiro/MotorIncrements.h>
-#include <amiro/MotorControl.h>
-#include <amiro/Odometry.h>
-#include <amiro/proximity/vcnl4020.hpp>
-#include <Types.h> // kinematic
-#include <amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp>
-#include <amiro/power/ltc4412.hpp>
-#include <string.h>  // memcpy
-
-namespace amiro {
-
-  class DiWheelDrive : public ControllerAreaNetworkTx, public ControllerAreaNetworkRx {
-  public:
-    DiWheelDrive(CANDriver *can);//, MotorControl *motorcontrol, Odometry *odometry, VCNL4020 (*vcnl4020)[4], fileSystemIo::FSIODiWheelDrive *memory, BaseLTC4412wEN *ltc4412);
-    virtual void  calibrate();
-
-    /** \brief Handle the termination of ControllerAreaNetworkTx and ControllerAreaNetworkRx threads
-     *         This includes waiting until the threads have terminated, thus this function might block a relatively long time.
-     */
-    msg_t terminate(void);
-
-    /** \brief Handle the start of ControllerAreaNetworkTx and ControllerAreaNetworkRx threads */
-    ThreadReference start(tprio_t PRIO);
-
-  protected:
-    virtual msg_t receiveMessage(CANRxFrame *frame);
-    virtual msg_t updateSensorVal();
-    virtual void periodicBroadcast();
-
-    void  calibrateProximityFloorValues();
-
-  private:
-    uint32_t bcCounter;
-//    MotorControl *motorcontrol;
-//    Odometry *odometry;
-//    VCNL4020 (*vcnl4020)[4];
-//    fileSystemIo::FSIODiWheelDrive *memory;
-//    BaseLTC4412wEN *ltc4412;
-    int actualSpeed[2];
-    types::position robotPosition;
-
-  };
-
-}
-
-#endif /* AMIRO_DI_WHEEL_DRIVE_H_ */
diff --git a/devices/DiWheelDrive/Makefile b/devices/DiWheelDrive/Makefile
deleted file mode 100644
index 4b12897..0000000
--- a/devices/DiWheelDrive/Makefile
+++ /dev/null
@@ -1,259 +0,0 @@
-##############################################################################
-# Build global options
-# NOTE: Can be overridden externally.
-#
-
-# Compiler options here.
-ifeq ($(USE_OPT),)
-  USE_OPT = -O2 -fomit-frame-pointer -falign-functions=16 -DCHPRINTF_USE_FLOAT=1 -fstack-usage -DSERIAL_BUFFERS_SIZE=64
-endif
-
-# C specific options here (added to USE_OPT).
-ifeq ($(USE_COPT),)
-  USE_COPT =
-endif
-
-# C++ specific options here (added to USE_OPT).
-ifeq ($(USE_CPPOPT),)
-  USE_CPPOPT = -fno-rtti -fno-exceptions -std=c++11 -U__STRICT_ANSI__
-endif
-
-# Enable this if you want the linker to remove unused code and data
-ifeq ($(USE_LINK_GC),)
-  USE_LINK_GC = yes
-endif
-
-# Linker extra options here.
-ifeq ($(USE_LDOPT),)
-  USE_LDOPT =
-endif
-
-# Enable this if you want link time optimizations (LTO)
-ifeq ($(USE_LTO),)
-  USE_LTO = no
-endif
-
-# If enabled, this option allows to compile the application in THUMB mode.
-ifeq ($(USE_THUMB),)
-  USE_THUMB = yes
-endif
-
-# Enable this if you want to see the full log while compiling.
-ifeq ($(USE_VERBOSE_COMPILE),)
-  USE_VERBOSE_COMPILE = no
-endif
-
-#
-# Build global options
-##############################################################################
-
-##############################################################################
-# Architecture or project specific options
-#
-
-# Enable this if you really want to use the STM FWLib.
-ifeq ($(USE_FWLIB),)
-  USE_FWLIB = no
-endif
-
-#
-# Architecture or project specific options
-##############################################################################
-
-##############################################################################
-# Project, sources and paths
-#
-
-# Define project name here
-PROJECT = DiWheelDrive
-
-# Imported source files and paths
-CHIBIOS = ../../../ChibiOS
-AMIRO = ../..
-include $(AMIRO)/boards/DiWheelDrive/board.mk
-include $(CHIBIOS)/os/hal/platforms/STM32F1xx/platform.mk
-include $(CHIBIOS)/os/hal/hal.mk
-include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F1xx/port.mk
-include $(CHIBIOS)/os/kernel/kernel.mk
-include $(CHIBIOS)/os/various/cpp_wrappers/kernel.mk
-include $(AMIRO)/hal/platforms/STM32/platform.mk
-include $(AMIRO)/hal/hal.mk
-
-# Define linker script file here
-LDSCRIPT= $(BOARDLD)/STM32F103xE.ld
-
-# C sources that can be compiled in ARM or THUMB mode depending on the global
-# setting.
-CSRC = $(PORTSRC) \
-       $(KERNSRC) \
-       $(HALSRC) \
-       $(PLATFORMSRC) \
-       $(BOARDSRC) \
-       $(CHIBIOS)/os/various/evtimer.c \
-       $(CHIBIOS)/os/various/syscalls.c \
-       $(CHIBIOS)/os/various/chprintf.c \
-       $(CHIBIOS)/os/various/shell.c \
-       $(CHIBIOS)/os/various/memstreams.c \
-       $(AMIRO)/stubs.c \
-       $(AMIRO)/components/Debug.c \
-
-# C++ sources that can be compiled in ARM or THUMB mode depending on the global
-# setting.
-CPPSRC = $(CHCPPSRC) \
-         $(AMIRO)/components/bus/spi/HWSPIDriver.cpp \
-         $(AMIRO)/components/bus/i2c/HWI2CDriver.cpp \
-         $(AMIRO)/components/bus/i2c/I2CMultiplexer.cpp \
-         $(AMIRO)/components/bus/i2c/VI2CDriver.cpp \
-         $(AMIRO)/components/proximity/vcnl4020.cpp \
-         $(AMIRO)/components/magneto/hmc5883l.cpp \
-         $(AMIRO)/components/accel/lis331dlh.cpp \
-         $(AMIRO)/components/gyro/l3g4200d.cpp \
-         $(AMIRO)/components/power/ina219.cpp \
-         $(AMIRO)/components/eeprom/eeprom.cpp \
-         $(AMIRO)/components/eeprom/at24.cpp \
-         $(AMIRO)/components/FileSystemInputOutput/FileSystemInputOutputBase.cpp \
-         $(AMIRO)/components/FileSystemInputOutput/FSIODiWheelDrive.cpp \
-         $(AMIRO)/components/MotorIncrements.cpp \
-         $(AMIRO)/components/MotorControl.cpp \
-         $(AMIRO)/components/DistControl.cpp \
-         $(AMIRO)/components/Odometry.cpp \
-         $(AMIRO)/components/ControllerAreaNetworkRx.cpp \
-         $(AMIRO)/components/ControllerAreaNetworkTx.cpp \
-         $(AMIRO)/components/Color.cpp \
-         $(AMIRO)/components/serial_reset/serial_can_mux.cpp \
-         DiWheelDrive.cpp \
-         userthread.cpp \
-         main.cpp \
-         exti.cpp
-
-# C sources to be compiled in ARM mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-ACSRC =
-
-# C++ sources to be compiled in ARM mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-ACPPSRC =
-
-# C sources to be compiled in THUMB mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-TCSRC =
-
-# C sources to be compiled in THUMB mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-TCPPSRC =
-
-# List ASM source files here
-ASMSRC = $(PORTASM)
-
-INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
-         $(HALINC) $(PLATFORMINC) $(BOARDINC) \
-         $(CHCPPINC) \
-         $(CHIBIOS)/os/various \
-         $(AMIRO) \
-         $(AMIRO)/include
-
-#
-# Project, sources and paths
-##############################################################################
-
-##############################################################################
-# Compiler settings
-#
-
-MCU  = cortex-m3
-
-#TRGT = arm-elf-
-TRGT = arm-none-eabi-
-CC   = $(TRGT)gcc
-CPPC = $(TRGT)g++
-# Enable loading with g++ only if you need C++ runtime support.
-# NOTE: You can use C++ even without C++ support if you are careful. C++
-#       runtime support makes code size explode.
-#LD   = $(TRGT)gcc
-LD   = $(TRGT)g++
-CP   = $(TRGT)objcopy
-AS   = $(TRGT)gcc -x assembler-with-cpp
-OD   = $(TRGT)objdump
-SZ   = $(TRGT)size
-HEX  = $(CP) -O ihex
-BIN  = $(CP) -O binary
-SREC = $(CP) -O srec --srec-len=248
-
-# ARM-specific options here
-AOPT =
-
-# THUMB-specific options here
-TOPT = -mthumb -DTHUMB
-
-# Define C warning options here
-CWARN = -Wall -Wextra -Wstrict-prototypes
-
-# Define C++ warning options here
-CPPWARN = -Wall -Wextra
-
-#
-# Compiler settings
-##############################################################################
-
-##############################################################################
-# Start of default section
-#
-
-# List all default C defines here, like -D_DEBUG=1
-DDEFS =
-
-# List all default ASM defines here, like -D_DEBUG=1
-DADEFS =
-
-# List all default directories to look for include files here
-DINCDIR =
-
-# List the default directory to look for the libraries here
-DLIBDIR =
-
-# List all default libraries here
-DLIBS =
-
-#
-# End of default section
-##############################################################################
-
-##############################################################################
-# Start of user section
-#
-
-# List all user C define here, like -D_DEBUG=1
-UDEFS =
-
-# Define ASM defines here
-UADEFS =
-
-# List all user directories here
-UINCDIR =
-
-# List the user directory to look for the libraries here
-ULIBDIR =
-
-# List all user libraries here
-ULIBS =
-
-#
-# End of user defines
-##############################################################################
-
-ifeq ($(USE_FWLIB),yes)
-  include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
-  CSRC += $(STM32SRC)
-  INCDIR += $(STM32INC)
-  USE_OPT += -DUSE_STDPERIPH_DRIVER
-endif
-
-RULESPATH = $(CHIBIOS)/os/ports/GCC/ARMCMx
-include $(RULESPATH)/rules.mk
-
-include $(AMIRO)/ports/rules.mk
-include $(AMIRO)/devices/flash.mk
diff --git a/devices/DiWheelDrive/amiroosconf.h b/devices/DiWheelDrive/amiroosconf.h
deleted file mode 100644
index 4bb1b27..0000000
--- a/devices/DiWheelDrive/amiroosconf.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef AMIRO_AMIROOSCONF_H_
-#define AMIRO_AMIROOSCONF_H_
-
-/**
- * @brief Stack size of the user thread object
- */
-#if !defined(USER_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
-#define USER_THREAD_STACK_SIZE         1024
-#endif
-
-/**
- * @brief Flag to enable/disable als amiroDbgXXX macros
- */
-#if !defined(AMIRO_DBG) || defined(__DOXYGEN__)
-#define AMIRO_DBG                      TRUE
-#endif
-
-#endif // AMIRO_AMIROOSCONF_H_
-
diff --git a/devices/DiWheelDrive/chconf.h b/devices/DiWheelDrive/chconf.h
deleted file mode 100644
index 18634e4..0000000
--- a/devices/DiWheelDrive/chconf.h
+++ /dev/null
@@ -1,518 +0,0 @@
-/**
- * @file    devices/DiWheelDrive/chconf.h
- * @brief   Configuration file.
- *
- * @addtogroup config
- * @details Kernel related settings and hooks.
- * @{
- */
-
-#ifndef _CHCONF_H_
-#define _CHCONF_H_
-
-/*===========================================================================*/
-/**
- * @name Kernel parameters and options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   System tick frequency.
- * @details Frequency of the system timer that drives the system ticks. This
- *          setting also defines the system tick time unit.
- */
-#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__)
-#define CH_FREQUENCY                    1000
-#endif
-
-/**
- * @brief   Round robin interval.
- * @details This constant is the number of system ticks allowed for the
- *          threads before preemption occurs. Setting this value to zero
- *          disables the preemption for threads with equal priority and the
- *          round robin becomes cooperative. Note that higher priority
- *          threads can still preempt, the kernel is always preemptive.
- *
- * @note    Disabling the round robin preemption makes the kernel more compact
- *          and generally faster.
- */
-#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__)
-#define CH_TIME_QUANTUM                 20
-#endif
-
-/**
- * @brief   Managed RAM size.
- * @details Size of the RAM area to be managed by the OS. If set to zero
- *          then the whole available RAM is used. The core memory is made
- *          available to the heap allocator and/or can be used directly through
- *          the simplified core memory allocator.
- *
- * @note    In order to let the OS manage the whole RAM the linker script must
- *          provide the @p __heap_base__ and @p __heap_end__ symbols.
- * @note    Requires @p CH_USE_MEMCORE.
- */
-#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__)
-#define CH_MEMCORE_SIZE                 0
-#endif
-
-/**
- * @brief   Idle thread automatic spawn suppression.
- * @details When this option is activated the function @p chSysInit()
- *          does not spawn the idle thread automatically. The application has
- *          then the responsibility to do one of the following:
- *          - Spawn a custom idle thread at priority @p IDLEPRIO.
- *          - Change the main() thread priority to @p IDLEPRIO then enter
- *            an endless loop. In this scenario the @p main() thread acts as
- *            the idle thread.
- *          .
- * @note    Unless an idle thread is spawned the @p main() thread must not
- *          enter a sleep state.
- */
-#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__)
-#define CH_NO_IDLE_THREAD               FALSE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Performance options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   OS optimization.
- * @details If enabled then time efficient rather than space efficient code
- *          is used when two possible implementations exist.
- *
- * @note    This is not related to the compiler optimization options.
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__)
-#define CH_OPTIMIZE_SPEED               TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Subsystem options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Threads registry APIs.
- * @details If enabled then the registry APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__)
-#define CH_USE_REGISTRY                 TRUE
-#endif
-
-/**
- * @brief   Threads synchronization APIs.
- * @details If enabled then the @p chThdWait() function is included in
- *          the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__)
-#define CH_USE_WAITEXIT                 TRUE
-#endif
-
-/**
- * @brief   Semaphores APIs.
- * @details If enabled then the Semaphores APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__)
-#define CH_USE_SEMAPHORES               TRUE
-#endif
-
-/**
- * @brief   Semaphores queuing mode.
- * @details If enabled then the threads are enqueued on semaphores by
- *          priority rather than in FIFO order.
- *
- * @note    The default is @p FALSE. Enable this if you have special requirements.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__)
-#define CH_USE_SEMAPHORES_PRIORITY      FALSE
-#endif
-
-/**
- * @brief   Atomic semaphore API.
- * @details If enabled then the semaphores the @p chSemSignalWait() API
- *          is included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__)
-#define CH_USE_SEMSW                    TRUE
-#endif
-
-/**
- * @brief   Mutexes APIs.
- * @details If enabled then the mutexes APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__)
-#define CH_USE_MUTEXES                  TRUE
-#endif
-
-/**
- * @brief   Conditional Variables APIs.
- * @details If enabled then the conditional variables APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_MUTEXES.
- */
-#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__)
-#define CH_USE_CONDVARS                 TRUE
-#endif
-
-/**
- * @brief   Conditional Variables APIs with timeout.
- * @details If enabled then the conditional variables APIs with timeout
- *          specification are included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_CONDVARS.
- */
-#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__)
-#define CH_USE_CONDVARS_TIMEOUT         TRUE
-#endif
-
-/**
- * @brief   Events Flags APIs.
- * @details If enabled then the event flags APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__)
-#define CH_USE_EVENTS                   TRUE
-#endif
-
-/**
- * @brief   Events Flags APIs with timeout.
- * @details If enabled then the events APIs with timeout specification
- *          are included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_EVENTS.
- */
-#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
-#define CH_USE_EVENTS_TIMEOUT           TRUE
-#endif
-
-/**
- * @brief   Synchronous Messages APIs.
- * @details If enabled then the synchronous messages APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__)
-#define CH_USE_MESSAGES                 TRUE
-#endif
-
-/**
- * @brief   Synchronous Messages queuing mode.
- * @details If enabled then messages are served by priority rather than in
- *          FIFO order.
- *
- * @note    The default is @p FALSE. Enable this if you have special requirements.
- * @note    Requires @p CH_USE_MESSAGES.
- */
-#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__)
-#define CH_USE_MESSAGES_PRIORITY        FALSE
-#endif
-
-/**
- * @brief   Mailboxes APIs.
- * @details If enabled then the asynchronous messages (mailboxes) APIs are
- *          included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__)
-#define CH_USE_MAILBOXES                TRUE
-#endif
-
-/**
- * @brief   I/O Queues APIs.
- * @details If enabled then the I/O queues APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__)
-#define CH_USE_QUEUES                   TRUE
-#endif
-
-/**
- * @brief   Core Memory Manager APIs.
- * @details If enabled then the core memory manager APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__)
-#define CH_USE_MEMCORE                  TRUE
-#endif
-
-/**
- * @brief   Heap Allocator APIs.
- * @details If enabled then the memory heap allocator APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or
- *          @p CH_USE_SEMAPHORES.
- * @note    Mutexes are recommended.
- */
-#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__)
-#define CH_USE_HEAP                     TRUE
-#endif
-
-/**
- * @brief   C-runtime allocator.
- * @details If enabled the the heap allocator APIs just wrap the C-runtime
- *          @p malloc() and @p free() functions.
- *
- * @note    The default is @p FALSE.
- * @note    Requires @p CH_USE_HEAP.
- * @note    The C-runtime may or may not require @p CH_USE_MEMCORE, see the
- *          appropriate documentation.
- */
-#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
-#define CH_USE_MALLOC_HEAP              FALSE
-#endif
-
-/**
- * @brief   Memory Pools Allocator APIs.
- * @details If enabled then the memory pools allocator APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__)
-#define CH_USE_MEMPOOLS                 TRUE
-#endif
-
-/**
- * @brief   Dynamic Threads APIs.
- * @details If enabled then the dynamic threads creation APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_WAITEXIT.
- * @note    Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS.
- */
-#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__)
-#define CH_USE_DYNAMIC                  TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Debug options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Debug option, system state check.
- * @details If enabled the correct call protocol for system APIs is checked
- *          at runtime.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
-#define CH_DBG_SYSTEM_STATE_CHECK       TRUE
-#endif
-
-/**
- * @brief   Debug option, parameters checks.
- * @details If enabled then the checks on the API functions input
- *          parameters are activated.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_CHECKS            TRUE
-#endif
-
-/**
- * @brief   Debug option, consistency checks.
- * @details If enabled then all the assertions in the kernel code are
- *          activated. This includes consistency checks inside the kernel,
- *          runtime anomalies and port-defined checks.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_ASSERTS           TRUE
-#endif
-
-/**
- * @brief   Debug option, trace buffer.
- * @details If enabled then the context switch circular trace buffer is
- *          activated.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_TRACE             TRUE
-#endif
-
-/**
- * @brief   Debug option, stack checks.
- * @details If enabled then a runtime stack check is performed.
- *
- * @note    The default is @p FALSE.
- * @note    The stack check is performed in a architecture/port dependent way.
- *          It may not be implemented or some ports.
- * @note    The default failure mode is to halt the system with the global
- *          @p panic_msg variable set to @p NULL.
- */
-#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_STACK_CHECK       TRUE
-#endif
-
-/**
- * @brief   Debug option, stacks initialization.
- * @details If enabled then the threads working area is filled with a byte
- *          value when a thread is created. This can be useful for the
- *          runtime measurement of the used stack.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
-#define CH_DBG_FILL_THREADS             FALSE
-#endif
-
-/**
- * @brief   Debug option, threads profiling.
- * @details If enabled then a field is added to the @p Thread structure that
- *          counts the system ticks occurred while executing the thread.
- *
- * @note    The default is @p TRUE.
- * @note    This debug option is defaulted to TRUE because it is required by
- *          some test cases into the test suite.
- */
-#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
-#define CH_DBG_THREADS_PROFILING        TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Kernel hooks
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Threads descriptor structure extension.
- * @details User fields added to the end of the @p Thread structure.
- */
-#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
-#define THREAD_EXT_FIELDS                                                   \
-  /* Add threads custom fields here.*/
-#endif
-
-/**
- * @brief   Threads initialization hook.
- * @details User initialization code added to the @p chThdInit() API.
- *
- * @note    It is invoked from within @p chThdInit() and implicitly from all
- *          the threads creation APIs.
- */
-#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
-#define THREAD_EXT_INIT_HOOK(tp) {                                          \
-  /* Add threads initialization code here.*/                                \
-}
-#endif
-
-/**
- * @brief   Threads finalization hook.
- * @details User finalization code added to the @p chThdExit() API.
- *
- * @note    It is inserted into lock zone.
- * @note    It is also invoked when the threads simply return in order to
- *          terminate.
- */
-#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__)
-#define THREAD_EXT_EXIT_HOOK(tp) {                                          \
-  /* Add threads finalization code here.*/                                  \
-}
-#endif
-
-/**
- * @brief   Context switch hook.
- * @details This hook is invoked just before switching between threads.
- */
-#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
-#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
-  /* Context switch code here.*/                                            \
-}
-#endif
-
-/**
- * @brief   Idle Loop hook.
- * @details This hook is continuously invoked by the idle thread loop.
- */
-#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__)
-#define IDLE_LOOP_HOOK() {                                                  \
-  /* Idle loop code here.*/                                                 \
-}
-#endif
-
-/**
- * @brief   System tick event hook.
- * @details This hook is invoked in the system tick handler immediately
- *          after processing the virtual timers queue.
- */
-#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
-#define SYSTEM_TICK_EVENT_HOOK() {                                          \
-  /* System tick event code here.*/                                         \
-}
-#endif
-
-/**
- * @brief   System halt hook.
- * @details This hook is invoked in case to a system halting error before
- *          the system is halted.
- */
-#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
-void haltErrorCode(void);
-#define SYSTEM_HALT_HOOK() {                                                \
-  /* System halt code here.*/                                               \
-  haltErrorCode();                                                          \
-}
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/* Port-specific settings (override port settings defaulted in chcore.h).    */
-/*===========================================================================*/
-
-/* NVIC VTOR initialization (only offset!) */
-#define CORTEX_VTOR_INIT 0x00006000
-
-#endif  /* _CHCONF_H_ */
-
-/** @} */
diff --git a/devices/DiWheelDrive/exti.cpp b/devices/DiWheelDrive/exti.cpp
deleted file mode 100644
index 2a95029..0000000
--- a/devices/DiWheelDrive/exti.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <board.h>
-
-#include "exti.hpp"
-
-volatile uint32_t shutdown_now = 0x00000000u; // = BL_SHUTDOWN_NONE in main.cpp
-
-EXTConfig extcfg = {
-
-  {
-    /* channel 0 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 1 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 2 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 3 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 4 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 5 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 6 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 7 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 8 */
-    {
-      /* mode */ EXT_MODE_GPIOC | EXT_CH_MODE_AUTOSTART | EXT_CH_MODE_FALLING_EDGE,
-      /* cb   */ power_down_cb,
-    },
-    /* channel 9 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 10 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 11 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 12 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 13 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 14 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 15 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 16 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 17 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 18 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-  }
-};
-
-void power_down_cb(EXTDriver *extp, expchannel_t channel) {
-
-  (void) extp;
-  (void) channel;
-  // make sure we don't accidentally power down when somebody tries to wake us
-  if (!palReadPad(GPIOC, GPIOC_SYS_PD_N))
-    palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_LOW); // indicate that the module needs some time to shut down
-    shutdown_now = 5; // = SHUTDOWN_HANDLE_REQUEST in main.cpp
-}
diff --git a/devices/DiWheelDrive/exti.hpp b/devices/DiWheelDrive/exti.hpp
deleted file mode 100644
index 97b8683..0000000
--- a/devices/DiWheelDrive/exti.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef EXT_HPP_
-#define EXT_HPP_
-
-extern volatile uint32_t shutdown_now;
-
-extern EXTConfig extcfg;
-
-void power_down_cb(EXTDriver *extp, expchannel_t channel);
-
-#endif /* EXT_HPP_ */
diff --git a/devices/DiWheelDrive/global.hpp b/devices/DiWheelDrive/global.hpp
deleted file mode 100644
index 2561989..0000000
--- a/devices/DiWheelDrive/global.hpp
+++ /dev/null
@@ -1,207 +0,0 @@
-#ifndef AMIRO_GLOBAL_HPP_
-#define AMIRO_GLOBAL_HPP_
-
-#include <hal.h>
-#include <qei.h>
-
-#include <stdlib.h>
-#include <array>
-
-#include <board.h>
-#include <amiro/proximity/vcnl4020.hpp>
-#include <amiro/bus/i2c/HWI2CDriver.hpp>
-#include <amiro/bus/i2c/mux/pca9544.hpp>
-#include <amiro/bus/i2c/VI2CDriver.hpp>
-#include <amiro/magneto/hmc5883l.hpp>
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/accel/lis331dlh.hpp>
-#include <amiro/gyro/l3g4200d.hpp>
-#include <amiro/power/ina219.hpp>
-#include <amiro/power/ltc4412.hpp>
-#include <amiro/eeprom/at24.hpp>
-#include <amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp>
-#include <amiro/serial_reset/serial_can_mux.hpp>
-#include <amiro/MotorIncrements.h>
-#include <amiro/MotorControl.h>
-#include <amiro/DistControl.h>
-#include <amiro/Odometry.h>
-#include <DiWheelDrive.h>
-#include <userthread.hpp>
-
-using namespace amiro;
-
-class Global final
-{
-public:
-  SerialConfig sd1_config{
-    /* speed        */ 115200,
-    /* CR1 register */ 0,
-    /* CR2 register */ 0,
-    /* CR3 register */ 0
-  };
-
-  I2CConfig i2c1_config{
-    /* I2C mode                 */ OPMODE_I2C,
-    /* frequency                */ 400000,
-    /* I2C fast mode duty cycle */ FAST_DUTY_CYCLE_2
-  };
-  I2CConfig i2c2_config{
-    /* I2C mode                 */ OPMODE_I2C,
-    /* frequency                */ 400000,
-    /* I2C fast mode duty cycle */ FAST_DUTY_CYCLE_2
-  };
-
-  VCNL4020::VCNL4020Config vcnl4020_config{
-    /* command             */ VCNL4020::ALS_EN | VCNL4020::PROX_EN | VCNL4020::SELFTIMED_EN,
-    /* ambient parameter   */ VCNL4020::AMBIENT_RATE_2 | VCNL4020::AMBIENT_AUTO_OFFSET | VCNL4020::AMBIENT_AVG_32,
-    /* IR LED current [mA] */ 200u,
-    /* proximity rate      */ VCNL4020::PROX_RATE_125
-  };
-
-  /**
-   * @brief I2C Bus 1
-   * Conected devices:
-   *   HMC5883L
-   */
-  HWI2CDriver HW_I2C1;
-  /**
-   * @brief I2C Bus 2
-   * Connected devices:
-   *   PCA9544
-   *   VCNL4020
-   *   INA219
-   *   AT24Cxx
-   */
-  HWI2CDriver HW_I2C2;
-
-  PCA9544<true> HW_PCA9544;
-
-  std::array<VI2CDriver, 4> V_I2C2;
-
-  std::array<VCNL4020, 4> vcnl4020;
-
-  HMC5883L::HMC5883LConfig hmc5883l_config{
-    /* ctrlA */ HMC5883L::DO_20_HZ | HMC5883L::MS_NORMAL | HMC5883L::MA_AVG8,
-    /* ctrlB */ HMC5883L::GN_5_GA,
-    /* mode  */ HMC5883L::MD_CONTCV | HMC5883L::HS_DISABLE
-  };
-  HMC5883L hmc5883l;
-
-  SPIConfig accel_spi1_config{
-    /* callback function pointer   */ NULL,
-    /* chip select line port       */ GPIOC,
-    /* chip select line pad number */ GPIOC_ACCEL_SS_N,
-    /* initialzation data          */ SPI_CR1_BR_0
-  };
-
-  SPIConfig gyro_spi1_config{
-    /* callback function pointer   */ NULL,
-    /* chip select line port       */ GPIOC,
-    /* chip select line pad number */ GPIOC_GYRO_SS_N,
-    /* initialzation data          */ SPI_CR1_BR_0
-  };
-
-  HWSPIDriver HW_SPI1_ACCEL;
-  HWSPIDriver HW_SPI1_GYRO;
-
-  LIS331DLH::LIS331DLHConfig accel_run_config{
-    /* ctrl1                     */ LIS331DLH::PM_ODR | LIS331DLH::DR_50HZ_37LP | LIS331DLH::ZEN | LIS331DLH::YEN | LIS331DLH::XEN,
-    /* ctrl2                     */ 0x00u,
-    /* ctrl3                     */ LIS331DLH::INT_LOW | LIS331DLH::I1_CFG_DRY,
-    /* ctrl4                     */ LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE | LIS331DLH::FS_4G | LIS331DLH::SIM_4WI,
-    /* ctrl5                     */ LIS331DLH::SLEEP_TO_WAKE_OFF,
-    /* interrupt 1 configuration */ {/* configuration */ LIS331DLH::AOI_OR_INT,
-                                     /* ths           */ 0x00u,
-                                     /* duration      */ 0x00u},
-    /* interrupt 2 configuration */ {/* configuration */ LIS331DLH::AOI_OR_INT,
-                                     /* ths           */ 0x00u,
-                                     /* duration      */ 0x00u}
-  };
-  LIS331DLH::LIS331DLHConfig accel_sleep_config{
-    /* ctrl1                     */ LIS331DLH::PM_0_5_HZ | LIS331DLH::DR_50HZ_37LP | LIS331DLH::XEN,
-    /* ctrl2                     */ 0x00u,
-    /* ctrl3                     */ LIS331DLH::INT_LOW | LIS331DLH::I1_CFG_I1,
-    /* ctrl4                     */ LIS331DLH::BDU_CONT | LIS331DLH::BLE_LE | LIS331DLH::FS_4G | LIS331DLH::SIM_4WI,
-    /* ctrl5                     */ LIS331DLH::SLEEP_TO_WAKE_ON,
-    /* interrupt 1 configuration */ {/* configuration */ LIS331DLH::AOI_OR_INT | LIS331DLH::XHIE,
-                                     /* ths           */ 0x10u,
-                                     /* duration      */ 0x02u},
-    /* interrupt 2 configuration */ {/* configuration */ LIS331DLH::AOI_OR_INT,
-                                     /* ths           */ 0x00u,
-                                     /* duration      */ 0x00u}
-  };
-  LIS331DLH lis331dlh;
-
-  L3G4200D::L3G4200DConfig gyro_run_config{
-    /* ctrl reg 1 */ L3G4200D::DR_100_HZ | L3G4200D::BW_25 | L3G4200D::PD | L3G4200D::ZEN | L3G4200D::YEN | L3G4200D::XEN,
-    /* ctrl reg 2 */ 0,
-    /* ctrl reg 3 */ L3G4200D::I2_DRDY,
-    /* ctrl reg 4 */ L3G4200D::FS_500_DPS | L3G4200D::SIM_4W,
-    /* ctrl reg 5 */ 0
-  };
-  L3G4200D::L3G4200DConfig gyro_sleep_config{
-    /* ctrl reg 1 */ L3G4200D::DR_100_HZ | L3G4200D::BW_25 | L3G4200D::PD,
-    /* ctrl reg 2 */ gyro_run_config.ctrl2,
-    /* ctrl reg 3 */ gyro_run_config.ctrl3,
-    /* ctrl reg 4 */ gyro_run_config.ctrl4,
-    /* ctrl reg 5 */ gyro_run_config.ctrl5
-  };
-  L3G4200D l3g4200d;
-
-  INA219::Driver ina219;
-
-  LTC4412wEN<(uintptr_t)GPIOC, GPIOC_PATH_DCSTAT, (uintptr_t)GPIOC, GPIOC_PATH_DCEN> ltc4412;
-
-  AT24 at24c01;
-  fileSystemIo::FSIODiWheelDrive memory;
-
-  MotorIncrements increments;
-  MotorControl motorcontrol;
-  DistControl distcontrol;
-  Odometry odometry;
-  SerialCanMux sercanmux1;
-
-  DiWheelDrive robot;
-
-  UserThread userThread;
-
-public:
-  Global() :
-    HW_I2C1(&I2CD1), HW_I2C2(&I2CD2),
-    HW_PCA9544(&HW_I2C2, 0x07u),
-    V_I2C2{{VI2CDriver(&HW_PCA9544, 0),
-            VI2CDriver(&HW_PCA9544, 1),
-            VI2CDriver(&HW_PCA9544, 2),
-            VI2CDriver(&HW_PCA9544, 3)}
-          },
-    vcnl4020{{/* front left  */ VCNL4020(&V_I2C2[0], &vcnl4020_config),
-              /* left wheel  */ VCNL4020(&V_I2C2[1], &vcnl4020_config),
-              /* right wheel */ VCNL4020(&V_I2C2[2], &vcnl4020_config),
-              /* front right */ VCNL4020(&V_I2C2[3], &vcnl4020_config)}
-            },
-    hmc5883l(&HW_I2C1, &hmc5883l_config),
-    HW_SPI1_ACCEL(&SPID1, &accel_spi1_config), HW_SPI1_GYRO(&SPID1, &gyro_spi1_config),
-    lis331dlh(&HW_SPI1_ACCEL),
-    l3g4200d(&HW_SPI1_GYRO),
-    ina219(HW_I2C2, 0x40u),
-    ltc4412(),
-    at24c01(0x400u / 0x08u, 0x08u, 500u, &HW_I2C2),
-    memory(at24c01, /*BMSV*/ 1, /*bmsv*/ 3, /*HMV*/ 1, /*hmv*/ 0), // bmsv changed von 2 auf 3
-    increments(&QEID3, &QEID4),
-    motorcontrol(&PWMD2, &increments, GPIOB, GPIOB_POWER_EN, &memory),
-    distcontrol(&motorcontrol, &increments),
-    odometry(&increments, &l3g4200d),
-    sercanmux1(&SD1, &CAND1, CAN::DI_WHEEL_DRIVE_ID),
-    robot(&CAND1),
-    userThread()
-  {
-    return;
-  }
-
-  ~Global()
-  {
-    return;
-  }
-};
-
-#endif /* AMIRO_GLOBAL_HPP_ */
diff --git a/devices/DiWheelDrive/halconf.h b/devices/DiWheelDrive/halconf.h
deleted file mode 100644
index 1fb3501..0000000
--- a/devices/DiWheelDrive/halconf.h
+++ /dev/null
@@ -1,303 +0,0 @@
-/**
- * @file    devices/DiWheelDrive/halconf.h
- * @brief   HAL configuration header.
- * @details HAL configuration file, this file allows to enable or disable the
- *          various device drivers from your application. You may also use
- *          this file in order to override the device drivers default settings.
- *
- * @addtogroup HAL_CONF
- * @{
- */
-
-#ifndef _HALCONF_H_
-#define _HALCONF_H_
-
-#include "mcuconf.h"
-
-/**
- * @brief   Enables the TM subsystem.
- */
-#if !defined(HAL_USE_TM) || defined(__DOXYGEN__)
-#define HAL_USE_TM                  TRUE
-#endif
-
-/**
- * @brief   Enables the PAL subsystem.
- */
-#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
-#define HAL_USE_PAL                 TRUE
-#endif
-
-/**
- * @brief   Enables the ADC subsystem.
- */
-#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
-#define HAL_USE_ADC                 FALSE
-#endif
-
-/**
- * @brief   Enables the CAN subsystem.
- */
-#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
-#define HAL_USE_CAN                 TRUE
-#endif
-
-/**
- * @brief   Enables the EXT subsystem.
- */
-#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
-#define HAL_USE_EXT                 TRUE
-#endif
-
-/**
- * @brief   Enables the GPT subsystem.
- */
-#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
-#define HAL_USE_GPT                 FALSE
-#endif
-
-/**
- * @brief   Enables the I2C subsystem.
- */
-#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
-#define HAL_USE_I2C                 TRUE
-#endif
-
-/**
- * @brief   Enables the ICU subsystem.
- */
-#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
-#define HAL_USE_ICU                 FALSE
-#endif
-
-/**
- * @brief   Enables the MAC subsystem.
- */
-#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
-#define HAL_USE_MAC                 FALSE
-#endif
-
-/**
- * @brief   Enables the MMC_SPI subsystem.
- */
-#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_MMC_SPI             FALSE
-#endif
-
-/**
- * @brief   Enables the PWM subsystem.
- */
-#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
-#define HAL_USE_PWM                 TRUE
-#endif
-
-/**
- * @brief   Enables the RTC subsystem.
- */
-#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
-#define HAL_USE_RTC                 FALSE
-#endif
-
-/**
- * @brief   Enables the SDC subsystem.
- */
-#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
-#define HAL_USE_SDC                 FALSE
-#endif
-
-/**
- * @brief   Enables the SERIAL subsystem.
- */
-#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL              TRUE
-#endif
-
-/**
- * @brief   Enables the SERIAL over USB subsystem.
- */
-#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL_USB          FALSE
-#endif
-
-/**
- * @brief   Enables the SPI subsystem.
- */
-#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_SPI                 TRUE
-#endif
-
-/**
- * @brief   Enables the UART subsystem.
- */
-#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
-#define HAL_USE_UART                FALSE
-#endif
-
-/**
- * @brief   Enables the USB subsystem.
- */
-#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
-#define HAL_USE_USB                 FALSE
-#endif
-
-/**
- * @brief   Enables the QEI subsystem.
- */
-#if !defined(HAL_USE_QEI) || defined(__DOXYGEN__)
-#define HAL_USE_QEI                 TRUE
-#endif
-
-/*===========================================================================*/
-/* ADC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables synchronous APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
-#define ADC_USE_WAIT                TRUE
-#endif
-
-/**
- * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define ADC_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-/*===========================================================================*/
-/* CAN driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Sleep mode related APIs inclusion switch.
- */
-#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
-#define CAN_USE_SLEEP_MODE          TRUE
-#endif
-
-/*===========================================================================*/
-/* I2C driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables the mutual exclusion APIs on the I2C bus.
- */
-#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define I2C_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-/*===========================================================================*/
-/* MAC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
-#define MAC_USE_ZERO_COPY           FALSE
-#endif
-
-/**
- * @brief   Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
-#define MAC_USE_EVENTS              TRUE
-#endif
-
-/*===========================================================================*/
-/* MMC_SPI driver related settings.                                          */
-/*===========================================================================*/
-
-/**
- * @brief   Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- *          routines releasing some extra CPU time for the threads with
- *          lower priority, this may slow down the driver a bit however.
- *          This option is recommended also if the SPI driver does not
- *          use a DMA channel and heavily loads the CPU.
- */
-#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
-#define MMC_NICE_WAITING            TRUE
-#endif
-
-/*===========================================================================*/
-/* SDC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Number of initialization attempts before rejecting the card.
- * @note    Attempts are performed at 10mS intervals.
- */
-#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
-#define SDC_INIT_RETRY              100
-#endif
-
-/**
- * @brief   Include support for MMC cards.
- * @note    MMC support is not yet implemented so this option must be kept
- *          at @p FALSE.
- */
-#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
-#define SDC_MMC_SUPPORT             FALSE
-#endif
-
-/**
- * @brief   Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- *          routines releasing some extra CPU time for the threads with
- *          lower priority, this may slow down the driver a bit however.
- */
-#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
-#define SDC_NICE_WAITING            TRUE
-#endif
-
-/*===========================================================================*/
-/* SERIAL driver related settings.                                           */
-/*===========================================================================*/
-
-/**
- * @brief   Default bit rate.
- * @details Configuration parameter, this is the baud rate selected for the
- *          default configuration.
- */
-#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
-#define SERIAL_DEFAULT_BITRATE      38400
-#endif
-
-/**
- * @brief   Serial buffers size.
- * @details Configuration parameter, you can change the depth of the queue
- *          buffers depending on the requirements of your application.
- * @note    The default is 64 bytes for both the transmission and receive
- *          buffers.
- */
-#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
-#define SERIAL_BUFFERS_SIZE         16
-#endif
-
-/*===========================================================================*/
-/* SPI driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables synchronous APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
-#define SPI_USE_WAIT                TRUE
-#endif
-
-/**
- * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define SPI_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-#endif /* _HALCONF_H_ */
-
-/** @} */
diff --git a/devices/DiWheelDrive/main.cpp b/devices/DiWheelDrive/main.cpp
deleted file mode 100644
index ee7dad3..0000000
--- a/devices/DiWheelDrive/main.cpp
+++ /dev/null
@@ -1,1016 +0,0 @@
-#define BL_CALLBACK_TABLE_ADDR  (0x08000000 + 0x01C0)
-#define BL_MAGIC_NUMBER         ((uint32_t)0xFF669900u)
-
-#define SHUTDOWN_NONE             0
-#define SHUTDOWN_TRANSPORTATION   1
-#define SHUTDOWN_DEEPSLEEP        2
-#define SHUTDOWN_HIBERNATE        3
-#define SHUTDOWN_RESTART          4
-#define SHUTDOWN_HANDLE_REQUEST   5
-
-#include <ch.hpp>
-
-#include <amiro/util/util.h>
-#include <global.hpp>
-#include <exti.hpp>
-
-#include <chprintf.h>
-#include <shell.h>
-
-using namespace chibios_rt;
-
-Global global;
-
-struct blVersion_t {
-  const uint8_t identifier;
-  const uint8_t major;
-  const uint8_t minor;
-  const uint8_t patch;
-} __attribute__((packed));
-
-void systemShutdown() {
-  types::kinematic k;
-  uint8_t i;
-
-//  // make sure we assert SYS_PD_N to delay shutdown until we're done.
-//  boardRequestShutdown();
-
-    // stop the user thread
-  global.userThread.requestTerminate();
-  global.userThread.wait();
-
-  k.x = 0x00u;
-  k.w_z = 0x00u;
-
-  // stop wheels
-  global.robot.setTargetSpeed(k);
-  global.robot.terminate();
-
-  for (i = 0x00; i < global.vcnl4020.size(); i++) {
-    global.vcnl4020[i].requestTerminate();
-    global.vcnl4020[i].wait();
-  }
-
-  global.ina219.requestTerminate();
-  global.ina219.wait();
-  global.hmc5883l.requestTerminate();
-  global.hmc5883l.wait();
-  global.l3g4200d.requestTerminate();
-  global.l3g4200d.wait();
-
-  global.motorcontrol.requestTerminate();
-  global.motorcontrol.wait();
-  global.odometry.requestTerminate();
-  global.odometry.wait();
-
-  // stop I²C
-  for (i = 0; i < global.V_I2C2.size(); ++i)
-    global.V_I2C2[i].stop();
-  global.HW_I2C2.stop();
-
-  global.lis331dlh.requestTerminate();
-  global.lis331dlh.wait();
-
-  global.lis331dlh.configure(&global.accel_sleep_config);
-//  global.lis331dlh.start(NORMALPRIO +4);
-
-//  boardWriteIoPower(0);
-//  boardStandby();
-
-  return;
-}
-
-
-//void (*shellcmd_t)(BaseSequentialStream *chp, int argc, char *argv[]);
-
-void shellRequestShutdown(BaseSequentialStream *chp, int argc, char *argv[]) {
-
-  chprintf(chp, "shellRequestShutdown\n");
-
-  /* if nor argument was given, print some help text */
-  if (argc == 0 || strcmp(argv[0], "help") == 0) {
-    chprintf(chp, "\tUSAGE:\n");
-    chprintf(chp, "> shutdown <type>\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\ttype\n");
-    chprintf(chp, "The type of shutdown to perform.\n");
-    chprintf(chp, "Choose one of the following types:\n");
-    chprintf(chp, "  transportation - Ultra low-power mode with all wakeups disabled.\n");
-    chprintf(chp, "                   The robot can not be charged.\n");
-    chprintf(chp, "  deepsleep      - Ultra low-power mode with several wakeups enabled.\n");
-    chprintf(chp, "                   The robot can only be charged via the power plug.\n");
-    chprintf(chp, "  hibernate      - Medium low-power mode, but with full charging capabilities.\n");
-    chprintf(chp, "  restart        - Performs a system restart.\n");
-    chprintf(chp, "Alternatively, you can use the shortcuts 't', 'd', 'h', and 'r' respectively.");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  if (strcmp(argv[0],"transportation") == 0 || strcmp(argv[0],"t") == 0) {
-    shutdown_now = SHUTDOWN_TRANSPORTATION;
-    chprintf(chp, "shutdown to transportation mode initialized\n");
-  } else if (strcmp(argv[0],"deepsleep") == 0 || strcmp(argv[0],"d") == 0) {
-    shutdown_now = SHUTDOWN_DEEPSLEEP;
-    chprintf(chp, "shutdown to deepsleep mode initialized\n");
-  } else if (strcmp(argv[0],"hibernate") == 0 || strcmp(argv[0],"h") == 0) {
-    shutdown_now = SHUTDOWN_HIBERNATE;
-    chprintf(chp, "shutdown to hibernate mode initialized\n");
-  } else if (strcmp(argv[0],"restart") == 0 || strcmp(argv[0],"r") == 0) {
-    chprintf(chp, "restart initialized\n");
-    shutdown_now = SHUTDOWN_RESTART;
-  } else {
-    chprintf(chp, "ERROR: unknown argument!\n");
-    shutdown_now = SHUTDOWN_NONE;
-  }
-
-  return;
-}
-
-void shellRequestWakeup(BaseSequentialStream *chp, int argc, char *argv[]) {
-  int i;
-  chprintf(chp, "shellRequestWakeup\n");
-
-  for (i = 0x00u; i < argc; i++)
-    chprintf(chp, "%s\n", argv[i]);
-
-  boardWakeup();
-}
-
-void shellRequestGetMemoryData(BaseSequentialStream *chp, int argc, char *argv[]) {
-  enum Type {HEX, U8, U16, U32, S8, S16, S32};
-
-  chprintf(chp, "shellRequestReadData\n");
-
-  if (argc < 2 || strcmp(argv[0],"help") == 0)
-  {
-    chprintf(chp, "Usage: %s\n","get_memory_data <type> <start> [<count>]");
-    chprintf(chp, "\n");
-    chprintf(chp, "\ttype\n");
-    chprintf(chp, "The data type as which to interpret the data.\n");
-    chprintf(chp, "Choose one of the following types:\n");
-    chprintf(chp, "  hex - one byte as hexadecimal value\n");
-    chprintf(chp, "  u8  - unsigned integer (8 bit)\n");
-    chprintf(chp, "  u16 - unsigned integer (16 bit)\n");
-    chprintf(chp, "  u32 - unsigned integer (32 bit)\n");
-    chprintf(chp, "  s8  - signed integer (8 bit)\n");
-    chprintf(chp, "  s16 - signed integer (16 bit)\n");
-    chprintf(chp, "  s32 - signed integer (32 bit)\n");
-    chprintf(chp, "\tstart\n");
-    chprintf(chp, "The first byte to read from the memory.\n");
-    chprintf(chp, "\tcount [default = 1]\n");
-    chprintf(chp, "The number of elements to read.\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tNOTE\n");
-    chprintf(chp, "Type conversions of this function might fail.\n");
-    chprintf(chp, "If so, use type=hex and convert by hand.\n");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  uint8_t type_size = 0;
-  Type type = HEX;
-  if (strcmp(argv[0],"hex") == 0) {
-    type_size = sizeof(unsigned char);
-    type = HEX;
-  } else if(strcmp(argv[0],"u8") == 0) {
-    type_size = sizeof(uint8_t);
-    type = U8;
-  } else if(strcmp(argv[0],"u16") == 0) {
-    type_size = sizeof(uint16_t);
-    type = U16;
-  } else if(strcmp(argv[0],"u32") == 0) {
-    type_size = sizeof(uint32_t);
-    type = U32;
-  } else if(strcmp(argv[0],"s8") == 0) {
-    type_size = sizeof(int8_t);
-    type = S8;
-  } else if(strcmp(argv[0],"s16") == 0) {
-    type_size = sizeof(int16_t);
-    type = S16;
-  } else if(strcmp(argv[0],"s32") == 0) {
-    type_size = sizeof(int32_t);
-    type = S32;
-  } else {
-    chprintf(chp, "First argument invalid. Use 'get_memory_data help' for help.\n");
-    return;
-  }
-
-  unsigned int start_byte = atoi(argv[1]);
-
-  unsigned int num_elements = 1;
-  if (argc >= 3)
-    num_elements = atoi(argv[2]);
-
-  const size_t eeprom_size = EEPROM::getsize(&global.at24c01);
-  uint8_t buffer[eeprom_size];
-  if (start_byte + (type_size * num_elements) > eeprom_size) {
-    num_elements = (eeprom_size - start_byte) / type_size;
-    chprintf(chp, "Warning: request exceeds eeprom size -> limiting to %u values.\n", num_elements);
-  }
-
-  chFileStreamSeek((BaseFileStream*)&global.at24c01, start_byte);
-
-  // Work around, because stm32f1 cannot read a single byte
-  if (type_size*num_elements < 2)
-    type_size = 2;
-
-  uint32_t bytes_read = chSequentialStreamRead((BaseFileStream*)&global.at24c01, buffer, type_size*num_elements);
-
-  if (bytes_read != type_size*num_elements)
-    chprintf(chp, "Warning: %u of %u requested bytes were read.\n", bytes_read, type_size*num_elements);
-
-  for (unsigned int i = 0; i < num_elements; ++i) {
-    switch (type) {
-      case HEX:
-        chprintf(chp, "%02X ", buffer[i]);
-        break;
-      case U8:
-        chprintf(chp, "%03u ", ((uint8_t*)buffer)[i]);
-        break;
-      case U16:
-        chprintf(chp, "%05u ", ((uint16_t*)buffer)[i]);
-        break;
-      case U32:
-        chprintf(chp, "%010u ", ((uint32_t*)buffer)[i]);
-        break;
-      case S8:
-        chprintf(chp, "%+03d ", ((int8_t*)buffer)[i]);
-        break;
-      case S16:
-        chprintf(chp, "%+05d ", ((int16_t*)buffer)[i]);
-        break;
-      case S32:
-        chprintf(chp, "%+010d ", ((int32_t*)buffer)[i]);
-        break;
-      default:
-        break;
-    }
-  }
-  chprintf(chp, "\n");
-
-  return;
-}
-
-void shellRequestSetLights(BaseSequentialStream *chp, int argc, char *argv[]) {
-
-  if (argc < 2 || argc == 3 ||strcmp(argv[0],"help") == 0) {
-    chprintf(chp, "\tUSAGE:\n");
-    chprintf(chp, "> set_lights <led mask> <white/red> [<green> <blue>]\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tled mask\n");
-    chprintf(chp, "The LEDs to be set.\n");
-    chprintf(chp, "You can set multiple LEDs at once by adding the following values:\n");
-    chprintf(chp, "  0x01 - rear left LED (SSW)\n");
-    chprintf(chp, "  0x02 - left rear LED (WSW)\n");
-    chprintf(chp, "  0x04 - left front LED (WNW)\n");
-    chprintf(chp, "  0x08 - front left LED (NNW)\n");
-    chprintf(chp, "  0x10 - front right LED (NNE)\n");
-    chprintf(chp, "  0x20 - right front LED (ENE)\n");
-    chprintf(chp, "  0x40 - right rear LED (ESE)\n");
-    chprintf(chp, "  0x80 - rear right LED (SSE)\n");
-    chprintf(chp, "\twhite/red\n");
-    chprintf(chp, "If no optional argument is given, this arguments sets the white value of the selected LEDs.\n");
-    chprintf(chp, "Otherwise this arguments sets the red color channel value.\n");
-    chprintf(chp, "\tgreen\n");
-    chprintf(chp, "Sets the green color channel value.\n");
-    chprintf(chp, "\tblue\n");
-    chprintf(chp, "Sets the blue color channel value.\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tExample:\n");
-    chprintf(chp, "This line will set the two most left and two most right LEDs to bright cyan.\n");
-    chprintf(chp, "> set_lights 0x66 0 255 255\n");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  int arg_mask = strtol(argv[0], NULL, 0);
-  int red = strtol(argv[1], NULL, 0);
-  int green = red;
-  int blue = red;
-  if (argc >= 4) {
-    green = strtol(argv[2], NULL, 0);
-    blue = strtol(argv[3], NULL, 0);
-  }
-  Color color(red, green, blue);
-
-  if (arg_mask & 0x01) {
-    global.robot.setLightColor(constants::LightRing::LED_SSW, color);
-  }
-  if (arg_mask & 0x02) {
-    global.robot.setLightColor(constants::LightRing::LED_WSW, color);
-  }
-  if (arg_mask & 0x04) {
-    global.robot.setLightColor(constants::LightRing::LED_WNW, color);
-  }
-  if (arg_mask & 0x08) {
-    global.robot.setLightColor(constants::LightRing::LED_NNW, color);
-  }
-  if (arg_mask & 0x10) {
-    global.robot.setLightColor(constants::LightRing::LED_NNE, color);
-  }
-  if (arg_mask & 0x20) {
-    global.robot.setLightColor(constants::LightRing::LED_ENE, color);
-  }
-  if (arg_mask & 0x40) {
-    global.robot.setLightColor(constants::LightRing::LED_ESE, color);
-  }
-  if (arg_mask & 0x80) {
-    global.robot.setLightColor(constants::LightRing::LED_SSE, color);
-  }
-
-  return;
-}
-
-void boardPeripheryCheck(BaseSequentialStream *chp) {
-  msg_t result;
-  chprintf(chp, "\nCHECK: START\n");
-  // Check the accelerometer
-  result = global.lis331dlh.getCheck();
-  if (result == global.lis331dlh.CHECK_OK)
-    chprintf(chp, "LIS331DLH: OK\n");
-  else
-    chprintf(chp, "LIS331DLH: FAIL\n");
-
-  // Self-test accelerometer
-//  lis331dlh.printSelfTest(NULL);
-
-  // Check the eeprom
-  result = global.memory.getCheck();
-  if ( result != global.memory.OK)
-    chprintf(chp, "Memory Structure: FAIL\n");
-  else
-    chprintf(chp, "Memory Structure: OK\n");
-
-  // Check the gyroscope
-  result = global.l3g4200d.getCheck();
-  if (result == global.l3g4200d.CHECK_OK)
-    chprintf(chp, "L3G4200D: OK\n");
-  else
-    chprintf(chp, "L3G4200D: FAIL\n");
-
-  // Check the magnetometer
-  result = global.hmc5883l.getCheck();
-  if (result == global.hmc5883l.CHECK_OK)
-    chprintf(chp, "HMC5883L: OK\n");
-  else
-    chprintf(chp, "HMC5883L: FAIL\n");
-
-  // Check the MUX
-  result = global.HW_PCA9544.getCheck();
-  if (result == global.HW_PCA9544.CHECK_OK)
-    chprintf(chp, "PCA9544: OK\n");
-  else
-    chprintf(chp, "PCA9544: FAIL\n");
-
-  // Check the power monitor
-  chprintf(chp, "INA219:\tVDD (3.3V):\n");
-  result = global.ina219.selftest();
-  if (result == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "->\tnot implemented\n");
-  else if (result != INA219::Driver::ST_OK)
-    chprintf(chp, "->\tFAIL (error code 0x%02X)\n", result);
-  else
-    chprintf(chp, "->\tOK\n");
-
-  // Check the proximitysensors
-  for (uint8_t i = 0x00; i < global.vcnl4020.size(); i++) {
-    result = global.vcnl4020[i].getCheck();
-    if (result == global.vcnl4020[i].CHECK_OK)
-      chprintf(chp, "VCNL4020: %d OK\n", i);
-    else
-      chprintf(chp, "VCNL4020: %d FAIL\n", i);
-  }
-  chprintf(chp, "CHECK: FINISH\n");
-}
-
-void shellRequestCheck(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestCheck\n");
-  boardPeripheryCheck(chp);
-}
-
-void shellRequestResetMemory(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestInitMemory\n");
-
-  msg_t res = global.memory.resetMemory();
-  if ( res != global.memory.OK)
-    chprintf(chp, "Memory Init: FAIL\n");
-  else
-    chprintf(chp, "Memory Init: OK\n");
-}
-
-void shellRequestGetBoardId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetBoardId\n");
-  uint8_t id = 0xFFu;
-
-  msg_t res = global.memory.getBoardId(&id);
-
-  if (res != global.memory.OK)
-    chprintf(chp, "Get Board ID: FAIL\n");
-  else
-    chprintf(chp, "Get Board ID: %u\n", id);
-}
-
-void shellRequestSetBoardId(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetBoardId\n");
-
-  if (argc == 0) {
-    chprintf(chp, "Usage: %s\n","set_board_id <idx>");
-  } else {
-    msg_t res = global.memory.setBoardId(atoi(argv[0]));
-    if (res != global.memory.OK)
-      chprintf(chp, "Set Board ID: FAIL\n");
-    else
-      chprintf(chp, "Set Board ID: OK\n");
-  }
-}
-
-void shellRequestResetCalibrationConstants(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestResetCalibrationConstants\n");
-  chprintf(chp, "Setting Ed=1.0f, Eb=1.0f\n");
-  msg_t res;
-
-  res = global.memory.setEd(1.0f);
-  if (res != global.memory.OK)
-    chprintf(chp, "Set Ed: FAIL\n");
-  else
-    chprintf(chp, "Set Ed: OK\n");
-
-  res = global.memory.setEb(1.0f);
-  if (res != global.memory.OK)
-    chprintf(chp, "Set Eb: FAIL\n");
-  else
-    chprintf(chp, "Set Eb: OK\n");
-}
-
-void shellRequestGetCalibrationConstants(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetCalibrationConstants\n");
-  msg_t res;
-  float Ed, Eb;
-
-  res = global.memory.getEd(&Ed);
-  if (res != global.memory.OK)
-    chprintf(chp, "Get Ed: FAIL\n");
-  else
-    chprintf(chp, "Get Ed: OK \t Ed=%f\n", Ed);
-
-  res = global.memory.getEb(&Eb);
-  if (res != global.memory.OK)
-    chprintf(chp, "Get Eb: FAIL\n");
-  else
-    chprintf(chp, "Get Eb: OK \t Eb=%f\n", Eb);
-}
-
-void shellRequestSetCalibrationConstants(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetCalibrationConstants\n");
-  msg_t res;
-
-  if (argc != 3) {
-    chprintf(chp, "Usage: %s\n","set_Ed_Eb <Ed> <Eb> <Write To Eeprom ? 1 : 0>");
-    chprintf(chp, "(Call with floating point values for Ed and Eb values and write condition):\n");
-    return;
-  }
-  // Get the write condition
-  const float Ed = atof(argv[0]);
-  const float Eb = atof(argv[1]);
-  bool_t writeToMemory = atoi(argv[2]) == 1 ? true : false;
-
-  res = global.motorcontrol.setWheelDiameterCorrectionFactor(Ed, writeToMemory);
-  if (res != global.memory.OK)
-    chprintf(chp, "Set Ed: FAIL\n");
-  else
-    chprintf(chp, "Set Ed: OK \t Ed=%f\n", Ed);
-
-  res = global.motorcontrol.setActualWheelBaseDistance(Eb, writeToMemory);
-  if (res != global.memory.OK)
-    chprintf(chp, "Set Eb: FAIL\n");
-  else
-    chprintf(chp, "Set Eb: OK \t Ed=%f\n", Eb);
-}
-
-void shellRequestGetVcnl(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetVcnl\n");
-  // Print the sensor information
-  if (argc != 1) {
-    chprintf(chp, "Usage: %s\n","get_vcnl <rep>");
-    return;
-  }
-  for (int32_t rep = 0x00; rep < atoi(argv[0]); ++rep) {
-    for (uint8_t idx = 0x00; idx < global.vcnl4020.size(); idx++) {
-     chprintf(chp, "%d: Ambi %d\tProx raw %d\tProx scaled %d\n", idx, global.vcnl4020[idx].getAmbientLight(), global.vcnl4020[idx].getProximity(), global.vcnl4020[idx].getProximityScaledWoOffset());
-    }
-    chprintf(chp, "\n\n");
-    BaseThread::sleep(MS2ST(250));
-  }
-}
-
-void shellRequestSetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetVcnlOffset\n");
-  if (argc != 2) {
-    chprintf(chp, "Usage: %s\n","set_vcnl <idx> <offset>");
-    return;
-  }
-
-  uint8_t vcnlIdx = static_cast<uint8_t>(atoi(argv[0]));
-  uint16_t vcnlOffset = static_cast<uint16_t>(atoi(argv[1]));
-
-  if (vcnlIdx >= global.vcnl4020.size()) {
-    chprintf(chp, "Wrong VCNL index: Choose [0 .. %d]\n", global.vcnl4020.size()-1);
-    return;
-  }
-
-  msg_t res = global.memory.setVcnl4020Offset(vcnlOffset, vcnlIdx);
-  if (res != global.memory.OK) {
-    chprintf(chp, "Set Offset: FAIL\n");
-  } else {
-    chprintf(chp, "Set Offset: OK\n");
-    global.vcnl4020[vcnlIdx].setProximityOffset(vcnlOffset);
-  }
-}
-
-void shellRequestResetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
-  msg_t res = global.memory.OK;
-  for (uint8_t idx = 0; idx < 4; ++idx) {
-    msg_t r = global.memory.setVcnl4020Offset(0, idx);
-    if (r == global.memory.OK) {
-      global.vcnl4020[idx].setProximityOffset(0);
-    } else {
-      chprintf(chp, "Reset Offset %u: FAIL\n", idx);
-      res = r;
-    }
-  }
-
-  if (res == global.memory.OK) {
-    chprintf(chp, "Reset Offset: DONE\n");
-  }
-
-  return;
-}
-
-void shellRequestGetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetVcnlOffset\n");
-  if (argc != 1) {
-    chprintf(chp, "Call with decimal numbers: get_vcnl <idx>\n");
-    return;
-  }
-
-  uint8_t vcnlIdx = static_cast<uint8_t>(atoi(argv[0]));
-
-  if (vcnlIdx >= global.vcnl4020.size()) {
-    chprintf(chp, "Wrong VCNL index: Choose [0 .. %d]\n", global.vcnl4020.size()-1);
-    return;
-  }
-
-  uint16_t vcnlOffset;
-  msg_t res = global.memory.getVcnl4020Offset(&vcnlOffset, vcnlIdx);
-  if (res != global.memory.OK) {
-    chprintf(chp, "Get Offset: FAIL\n");
-  } else {
-    chprintf(chp, "Get Offset: OK \t Offset=%d\n", vcnlOffset);
-  }
-}
-
-void shellRequestCalib(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestCalib\n");
-  global.robot.calibrate();
-}
-
-void shellRequestGetRobotId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetRobotId\n");
-  chprintf(chp, "Robot ID: %u\n", global.robot.getRobotID());
-  if (global.robot.getRobotID() == 0)
-    chprintf(chp, "Warning: The board ID seems to be uninitialized.\n");
-}
-
-void shellRequestGetSystemLoad(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetSystemLoad\n");
-  uint8_t seconds = 1;
-  if (argc >= 1) {
-    seconds = atoi(argv[0]);
-  }
-  chprintf(chp, "measuring CPU load for %u %s...\n", seconds, (seconds>1)? "seconds" : "second");
-
-  const systime_t before = chThdGetTicks(chSysGetIdleThread());
-  BaseThread::sleep(S2ST(seconds));
-  const systime_t after = chThdGetTicks(chSysGetIdleThread());
-  const float usage = 1.0f - (float(after - before) / float(seconds * CH_FREQUENCY));
-
-  chprintf(chp, "CPU load: %3.2f%%\n", usage * 100);
-  const uint32_t memory_total = 0x10000;
-  const uint32_t memory_load = memory_total - chCoreStatus();
-  chprintf(chp, "RAM load: %3.2f%% (%u / %u Byte)\n", float(memory_load)/float(memory_total) * 100, memory_load, memory_total);
-}
-
-void shellSwitchBoardCmd(BaseSequentialStream *chp, int argc, char *argv[]) {
-  if (argc != 1) {
-    chprintf(chp, "Call with decimal numbers: shell_board <idx>\n");
-    return;
-  }
-  uint8_t boardIdx = static_cast<uint8_t>(atoi(argv[0]));
-
-  chprintf(chp, "shellSwitchBoardCmd\n");
-  global.sercanmux1.sendSwitchCmd(boardIdx);
-}
-
-void shellRequestGetBootloaderInfo(BaseSequentialStream* chp, int argc, char *argv[]) {
-  // check the magic number
-  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
-    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
-      break;
-
-    case BL_MAGIC_NUMBER:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
-      break;
-
-    default:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
-      break;
-  }
-
-  return;
-}
-
-void shellRequestMotorDrive(BaseSequentialStream *chp, int argc, char *argv[]) {
-  types::kinematic tmp;
-  tmp.w_z = 0;
-  tmp.x = 0;
-  if (argc == 1){
-    chprintf(chp, "Set speed to %i um/s \n", atoi(argv[0]));
-    tmp.x = atoi(argv[0]);
-  } else {
-    if(argc == 2){
-      chprintf(chp, "Set speed to %i \n um/s", atoi(argv[0]));
-      chprintf(chp, "Set angular speed to %i \n urad/s", atoi(argv[1]));
-      tmp.x = atoi(argv[0]);
-      tmp.w_z= atoi(argv[1]);
-    } else {
-      chprintf(chp, "Wrong number of parameters given (%i), stopping robot \n", argc);
-    }
-  }
-
-  global.motorcontrol.setTargetSpeed(tmp);
-  return;
-}
-
-void shellRequestMotorStop(BaseSequentialStream *chp, int argc, char *argv[]) {
-  types::kinematic tmp;
-  tmp.x = 0;
-  tmp.w_z = 0;
-
-  global.motorcontrol.setTargetSpeed(tmp);
-
-  chprintf(chp, "stop");
-return;
-}
-
-void shellRequestMotorCalibrate(BaseSequentialStream *chp, int argc, char *argv[]) {
-  global.motorcontrol.resetGains();
-  chprintf((BaseSequentialStream*)&global.sercanmux1, "motor calibration starts in five seconds...\n");
-  BaseThread::sleep(MS2ST(5000));
-  global.motorcontrol.isCalibrating = true;
-
-  return;
-}
-
-void shellRequestMotorGetGains(BaseSequentialStream *chp, int argc, char *argv[]){
-  global.motorcontrol.printGains();
-
-  return;
-}
-
-void shellRequestMotorResetGains(BaseSequentialStream *chp, int argc, char *argv[]) {
-  global.motorcontrol.resetGains();;
-
-  return;
-}
-
-static const ShellCommand commands[] = {
-  {"shutdown", shellRequestShutdown},
-  {"wakeup", shellRequestWakeup},
-  {"check", shellRequestCheck},
-  {"reset_memory", shellRequestResetMemory},
-  {"get_board_id", shellRequestGetBoardId},
-  {"set_board_id", shellRequestSetBoardId},
-  {"get_memory_data", shellRequestGetMemoryData},
-  {"get_vcnl", shellRequestGetVcnl},
-  {"calib_vcnl_offset", shellRequestCalib},
-  {"set_vcnl_offset", shellRequestSetVcnlOffset},
-  {"reset_vcnl_offset", shellRequestResetVcnlOffset},
-  {"get_vcnl_offset", shellRequestGetVcnlOffset},
-  {"reset_Ed_Eb", shellRequestResetCalibrationConstants},
-  {"get_Ed_Eb", shellRequestGetCalibrationConstants},
-  {"set_Ed_Eb", shellRequestSetCalibrationConstants},
-  {"get_robot_id", shellRequestGetRobotId},
-  {"get_system_load", shellRequestGetSystemLoad},
-  {"set_lights", shellRequestSetLights},
-  {"shell_board", shellSwitchBoardCmd},
-  {"get_bootloader_info", shellRequestGetBootloaderInfo},
-  {"motor_drive", shellRequestMotorDrive},
-  {"motor_stop", shellRequestMotorStop},
-  {"motor_calibrate", shellRequestMotorCalibrate},
-  {"motor_getGains", shellRequestMotorGetGains},
-  {"motor_resetGains", shellRequestMotorResetGains},
-  {NULL, NULL}
-};
-
-static const ShellConfig shell_cfg1 = {
-  (BaseSequentialStream *) &global.sercanmux1,
-  commands
-};
-
-void initPowermonitor(INA219::Driver &ina219, const float shuntResistance_O, const float maxExpectedCurrent_A, const uint16_t currentLsb_uA)
-{
-  INA219::CalibData calibData;
-  INA219::InitData initData;
-
-  calibData.input.configuration.content.brng = INA219::Configuration::BRNG_16V;
-  calibData.input.configuration.content.pg = INA219::Configuration::PGA_40mV;
-  calibData.input.configuration.content.badc = INA219::Configuration::ADC_68100us;
-  calibData.input.configuration.content.sadc = INA219::Configuration::ADC_68100us;
-  calibData.input.configuration.content.mode = INA219::Configuration::MODE_ShuntBus_Continuous;
-  calibData.input.shunt_resistance_O = shuntResistance_O;
-  calibData.input.max_expected_current_A = maxExpectedCurrent_A;
-  calibData.input.current_lsb_uA = currentLsb_uA;
-  if (ina219.calibration(&calibData) != BaseSensor<>::SUCCESS)
-  {
-    chprintf((BaseSequentialStream*)&SD1, "WARNING: calibration of INA219 failed.\n");
-  }
-
-  initData.configuration.value = calibData.input.configuration.value;
-  initData.calibration = calibData.output.calibration_value;
-  initData.current_lsb_uA = calibData.output.current_lsb_uA;
-  if (ina219.init(&initData) != BaseSensor<>::SUCCESS)
-  {
-    chprintf((BaseSequentialStream*)&SD1, "WARNING: initialization of INA219 failed.\n");
-  }
-
-  if (calibData.input.current_lsb_uA != initData.current_lsb_uA)
-  {
-    chprintf((BaseSequentialStream*)&SD1, "NOTE: LSB for current measurement was limited when initializing INA219 (%u -> %u)", calibData.input.current_lsb_uA, initData.current_lsb_uA);
-  }
-
-  return;
-}
-
-/*
- * Application entry point.
- */
-int main(void) {
-
-//  int16_t accel;
-  Thread *shelltp = NULL;
-
-  /*
-   * System initializations.
-   * - HAL initialization, this also initializes the configured device drivers
-   *   and performs the board-specific initializations.
-   * - Kernel initialization, the main() function becomes a thread and the
-   *   RTOS is active.
-   */
-  halInit();
-  qeiInit();
-  System::init();
-
-//  boardWakeup();
-//  boardWriteIoPower(1);
-
-  /*
-   * Activates the serial driver 2 using the driver default configuration.
-   */
-  sdStart(&SD1, &global.sd1_config);
-
-  chprintf((BaseSequentialStream*) &SD1, "\n");
-  chprintf((BaseSequentialStream*) &SD1, BOARD_NAME " " BOARD_VERSION "\n");
-  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
-    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
-      break;
-
-    case BL_MAGIC_NUMBER:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
-      break;
-
-    default:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
-      break;
-  }
-  chprintf((BaseSequentialStream*) &SD1, "ChibiOS " CH_KERNEL_VERSION "\n");
-  // make sure that the info text is completetly printed
-  BaseThread::sleep(10);
-
-  extStart(&EXTD1, &extcfg);
-
-  /*
-   * Wait for a certain amount of time, so that the PowerBoard can activate
-   * the IO voltages for the I2C Bus
-   */
-  BaseThread::sleep(MS2ST(2000));
-
-  boardClearI2CBus(GPIOB_COMPASS_SCL, GPIOB_COMPASS_SDA);
-  boardClearI2CBus(GPIOB_IR_SCL, GPIOB_IR_SDA);
-
-  global.HW_I2C1.start(&global.i2c1_config);
-  global.HW_I2C2.start(&global.i2c2_config);
-
-  global.memory.init();
-
-  uint8_t i = 0;
-  if (global.memory.getBoardId(&i) == fileSystemIo::FileSystemIoBase::OK) {
-    chprintf((BaseSequentialStream*) &SD1, "Board ID: %u\n", i);
-  } else {
-    chprintf((BaseSequentialStream*) &SD1, "Error reading board ID\n");
-  }
-  chprintf((BaseSequentialStream*) &SD1, "\n");
-
-  initPowermonitor(global.ina219, 0.1f, 0.075f, 10);
-
-  for (i = 0x00u; i < global.vcnl4020.size(); i++) {
-    uint16_t buffer;
-    global.memory.getVcnl4020Offset(&buffer,i);
-    global.vcnl4020[i].setProximityOffset(buffer);
-    global.vcnl4020[i].start(NORMALPRIO);
-  }
-
-  global.ina219.start(NORMALPRIO);
-
-  global.hmc5883l.start(NORMALPRIO + 8);
-
-  global.increments.start();  // Start the qei driver
-
-  // Start the three axes gyroscope
-  global.l3g4200d.configure(&global.gyro_run_config);
-  global.l3g4200d.start(NORMALPRIO+5);
-
-  global.odometry.start(NORMALPRIO + 20);
-
-  global.robot.start(HIGHPRIO - 1);
-
-  global.motorcontrol.start(NORMALPRIO + 7);
-
-  global.distcontrol.start(NORMALPRIO + 9);
-
-  // Set target velocity
-  types::kinematic velocity;
-  velocity.x = 0; // E.g.  "100*1e3" equals "10 cm/s"
-  velocity.w_z = 0; // E.g. "2*1e6" equals "2 rad/s"
-  global.motorcontrol.setTargetSpeed(velocity);
-
-  // Start the three axes linear accelerometer
-  global.lis331dlh.configure(&global.accel_run_config);
-  global.lis331dlh.start(NORMALPRIO+4);
-
-  // Start the user thread
-  global.userThread.start(NORMALPRIO);
-
-  /* let the SYS_SYNC_N pin go, to signal that the initialization of the module is done */
-  palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_HIGH);
-
-  /* wait until all modules are done */
-  while (palReadPad(GPIOC, GPIOC_SYS_INT_N) == PAL_LOW) {
-    continue;
-  }
-
-  while (true) {
-
-    if (!shelltp)
-      shelltp = shellCreate(&shell_cfg1, THD_WA_SIZE(1024), NORMALPRIO);
-    else if (chThdTerminated(shelltp)) {
-      chThdRelease(shelltp);    /* Recovers memory of the previous shell. */
-      shelltp = NULL;           /* Triggers spawning of a new shell.      */
-    }
-
-    // Let the LED just blink as an alive signal
-    boardWriteLed(1);
-    BaseThread::sleep(MS2ST(250));
-    boardWriteLed(0);
-    BaseThread::sleep(MS2ST(250));
-
-    if (shutdown_now != SHUTDOWN_NONE) {
-      if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) && (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != BL_MAGIC_NUMBER)) {
-        chprintf((BaseSequentialStream*) &SD1, "ERROR: unable to shut down (bootloader deprecated).\n");
-        shutdown_now = SHUTDOWN_NONE;
-      } else {
-        uint32_t blCallbackPtrAddr = BL_CALLBACK_TABLE_ADDR;
-        // handle bootloader version 0.2.x
-        if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
-            (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 2)) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 10 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-        // handle bootloader version 0.3.x
-        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
-                 (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 3)) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 7 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-              blCallbackPtrAddr += 8 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-        // handle bootloader version 1.0.x
-        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) &&
-                 ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major == 1 && ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor == 0) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 7 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-              blCallbackPtrAddr += 8 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-
-        void (*blCallback)(void) = NULL;
-        if (blCallbackPtrAddr > BL_CALLBACK_TABLE_ADDR) {
-          blCallback = (void (*)(void))(*((uint32_t*)blCallbackPtrAddr));
-
-          if (!blCallback) {
-            chprintf((BaseSequentialStream*) &SD1, "ERROR: Requested shutdown not supported.\n");
-            shutdown_now = SHUTDOWN_NONE;
-          } else {
-            chprintf((BaseSequentialStream*)&SD1, "initiating shutdown sequence...\n");
-            palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_LOW);
-            palWritePad(GPIOC, GPIOC_SYS_PD_N, PAL_LOW);
-
-            chprintf((BaseSequentialStream*)&SD1, "stopping all threads and periphery...");
-            systemShutdown();
-            chprintf((BaseSequentialStream*)&SD1, "\tdone\n");
-            BaseThread::sleep(MS2ST(10)); // sleep to print everything
-
-            blCallback();
-          }
-
-        } else {
-          chprintf((BaseSequentialStream*) &SD1, "ERROR: invalid shutdown requested (%u).\n", shutdown_now);
-          shutdown_now = SHUTDOWN_NONE;
-        }
-      }
-
-//    for (uint8_t i = LIS331DLH::AXIS_X; i <= LIS331DLH::AXIS_Z; i++) {
-//        accel = lis331dlh.getAcceleration(i);
-//        chprintf((BaseSequentialStream*) &SD1, "%c%04X ", accel < 0 ? '-' : '+', accel < 0 ? -accel : accel);
-//    }
-//
-//    chprintf((BaseSequentialStream*) &SD1, "\n");
-//
-//    // Print out an alive signal
-//    chprintf((BaseSequentialStream*) &SD1, ".");
-    }
-  }
-
-  return 0;
-}
diff --git a/devices/DiWheelDrive/mcuconf.h b/devices/DiWheelDrive/mcuconf.h
deleted file mode 100644
index 19ec6e7..0000000
--- a/devices/DiWheelDrive/mcuconf.h
+++ /dev/null
@@ -1,193 +0,0 @@
-#define STM32F103_MCUCONF
-
-/*
- * STM32F103 drivers configuration.
- * The following settings override the default settings present in
- * the various device driver implementation headers.
- * Note that the settings for each driver only have effect if the whole
- * driver is enabled in halconf.h.
- *
- * IRQ priorities:
- * 15...0       Lowest...Highest.
- *
- * DMA priorities:
- * 0...3        Lowest...Highest.
- */
-
-/*
- * HAL driver system settings.
- */
-#define STM32_NO_INIT                       FALSE
-#define STM32_HSI_ENABLED                   TRUE
-#define STM32_LSI_ENABLED                   FALSE
-#define STM32_HSE_ENABLED                   TRUE
-#define STM32_LSE_ENABLED                   FALSE
-#define STM32_SW                            STM32_SW_PLL
-#define STM32_PLLSRC                        STM32_PLLSRC_HSE
-#define STM32_PLLXTPRE                      STM32_PLLXTPRE_DIV1
-#define STM32_PLLMUL_VALUE                  9
-#define STM32_HPRE                          STM32_HPRE_DIV1
-#define STM32_PPRE1                         STM32_PPRE1_DIV2
-#define STM32_PPRE2                         STM32_PPRE2_DIV2
-#define STM32_ADCPRE                        STM32_ADCPRE_DIV4
-#define STM32_USB_CLOCK_REQUIRED            TRUE
-#define STM32_USBPRE                        STM32_USBPRE_DIV1P5
-#define STM32_MCOSEL                        STM32_MCOSEL_NOCLOCK
-#define STM32_RTCSEL                        STM32_RTCSEL_HSEDIV
-#define STM32_PVD_ENABLE                    FALSE
-#define STM32_PLS                           STM32_PLS_LEV0
-
-/*
- * ADC driver system settings.
- */
-#define STM32_ADC_USE_ADC1                  FALSE
-#define STM32_ADC_ADC1_DMA_PRIORITY         2
-#define STM32_ADC_ADC1_IRQ_PRIORITY         6
-
-/*
- * CAN driver system settings.
- */
-#define STM32_CAN_USE_CAN1                  TRUE
-#define STM32_CAN_CAN1_IRQ_PRIORITY         11
-
-/*
- * EXT driver system settings.
- */
-#define STM32_EXT_EXTI0_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI1_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI2_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI3_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI4_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI5_9_IRQ_PRIORITY      6
-#define STM32_EXT_EXTI10_15_IRQ_PRIORITY    6
-#define STM32_EXT_EXTI16_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI17_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI18_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI19_IRQ_PRIORITY       6
-
-/*
- * GPT driver system settings.
- */
-#define STM32_GPT_USE_TIM1                  FALSE
-#define STM32_GPT_USE_TIM2                  FALSE
-#define STM32_GPT_USE_TIM3                  FALSE
-#define STM32_GPT_USE_TIM4                  FALSE
-#define STM32_GPT_USE_TIM5                  FALSE
-#define STM32_GPT_USE_TIM8                  FALSE
-#define STM32_GPT_TIM1_IRQ_PRIORITY         7
-#define STM32_GPT_TIM2_IRQ_PRIORITY         7
-#define STM32_GPT_TIM3_IRQ_PRIORITY         7
-#define STM32_GPT_TIM4_IRQ_PRIORITY         7
-#define STM32_GPT_TIM5_IRQ_PRIORITY         7
-#define STM32_GPT_TIM8_IRQ_PRIORITY         7
-
-/*
- * I2C driver system settings.
- */
-#define STM32_I2C_USE_I2C1                  TRUE
-#define STM32_I2C_USE_I2C2                  TRUE
-#define STM32_I2C_I2C1_IRQ_PRIORITY         5
-#define STM32_I2C_I2C2_IRQ_PRIORITY         5
-#define STM32_I2C_I2C1_DMA_PRIORITY         3
-#define STM32_I2C_I2C2_DMA_PRIORITY         3
-#define STM32_I2C_I2C1_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_I2C2_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_USE_DMA                   FALSE
-
-/*
- * ICU driver system settings.
- */
-#define STM32_ICU_USE_TIM1                  FALSE
-#define STM32_ICU_USE_TIM2                  FALSE
-#define STM32_ICU_USE_TIM3                  FALSE
-#define STM32_ICU_USE_TIM4                  FALSE
-#define STM32_ICU_USE_TIM5                  FALSE
-#define STM32_ICU_USE_TIM8                  FALSE
-#define STM32_ICU_TIM1_IRQ_PRIORITY         7
-#define STM32_ICU_TIM2_IRQ_PRIORITY         7
-#define STM32_ICU_TIM3_IRQ_PRIORITY         7
-#define STM32_ICU_TIM4_IRQ_PRIORITY         7
-#define STM32_ICU_TIM5_IRQ_PRIORITY         7
-#define STM32_ICU_TIM8_IRQ_PRIORITY         7
-
-/*
- * PWM driver system settings.
- */
-#define STM32_PWM_USE_ADVANCED              FALSE
-#define STM32_PWM_USE_TIM1                  FALSE
-#define STM32_PWM_USE_TIM2                  TRUE
-#define STM32_PWM_USE_TIM3                  FALSE
-#define STM32_PWM_USE_TIM4                  FALSE
-#define STM32_PWM_USE_TIM5                  FALSE
-#define STM32_PWM_USE_TIM8                  FALSE
-#define STM32_PWM_TIM1_IRQ_PRIORITY         7
-#define STM32_PWM_TIM2_IRQ_PRIORITY         7
-#define STM32_PWM_TIM3_IRQ_PRIORITY         7
-#define STM32_PWM_TIM4_IRQ_PRIORITY         7
-#define STM32_PWM_TIM5_IRQ_PRIORITY         7
-#define STM32_PWM_TIM8_IRQ_PRIORITY         7
-
-/*
- * RTC driver system settings.
- */
-#define STM32_RTC_IRQ_PRIORITY              15
-
-/*
- * SERIAL driver system settings.
- */
-#define STM32_SERIAL_USE_USART1             TRUE
-#define STM32_SERIAL_USE_USART2             FALSE
-#define STM32_SERIAL_USE_USART3             FALSE
-#define STM32_SERIAL_USE_UART4              FALSE
-#define STM32_SERIAL_USE_UART5              FALSE
-#define STM32_SERIAL_USART1_PRIORITY        12
-#define STM32_SERIAL_USART2_PRIORITY        12
-#define STM32_SERIAL_USART3_PRIORITY        12
-#define STM32_SERIAL_UART4_PRIORITY         12
-#define STM32_SERIAL_UART5_PRIORITY         12
-
-/*
- * SPI driver system settings.
- */
-#define STM32_SPI_USE_SPI1                  TRUE
-#define STM32_SPI_USE_SPI2                  TRUE
-#define STM32_SPI_USE_SPI3                  FALSE
-#define STM32_SPI_SPI1_DMA_PRIORITY         1
-#define STM32_SPI_SPI2_DMA_PRIORITY         1
-#define STM32_SPI_SPI3_DMA_PRIORITY         1
-#define STM32_SPI_SPI1_IRQ_PRIORITY         10
-#define STM32_SPI_SPI2_IRQ_PRIORITY         10
-#define STM32_SPI_SPI3_IRQ_PRIORITY         10
-#define STM32_SPI_DMA_ERROR_HOOK(spip)      chSysHalt()
-
-/*
- * UART driver system settings.
- */
-#define STM32_UART_USE_USART1               FALSE
-#define STM32_UART_USE_USART2               FALSE
-#define STM32_UART_USE_USART3               FALSE
-#define STM32_UART_USART1_IRQ_PRIORITY      12
-#define STM32_UART_USART2_IRQ_PRIORITY      12
-#define STM32_UART_USART3_IRQ_PRIORITY      12
-#define STM32_UART_USART1_DMA_PRIORITY      0
-#define STM32_UART_USART2_DMA_PRIORITY      0
-#define STM32_UART_USART3_DMA_PRIORITY      0
-#define STM32_UART_DMA_ERROR_HOOK(uartp)    chSysHalt()
-
-/*
- * USB driver system settings.
- */
-#define STM32_USB_USE_USB1                  FALSE
-#define STM32_USB_LOW_POWER_ON_SUSPEND      FALSE
-#define STM32_USB_USB1_HP_IRQ_PRIORITY      13
-#define STM32_USB_USB1_LP_IRQ_PRIORITY      14
-
-/*
- * QEI driver system settings.
- */
-#define STM32_QEI_USE_TIM1                  FALSE
-#define STM32_QEI_USE_TIM2                  FALSE
-#define STM32_QEI_USE_TIM3                  TRUE
-#define STM32_QEI_USE_TIM4                  TRUE
-#define STM32_QEI_USE_TIM5                  FALSE
-#define STM32_QEI_USE_TIM8                  FALSE
diff --git a/devices/DiWheelDrive/userthread.cpp b/devices/DiWheelDrive/userthread.cpp
deleted file mode 100644
index dbf8517..0000000
--- a/devices/DiWheelDrive/userthread.cpp
+++ /dev/null
@@ -1,419 +0,0 @@
-#include "userthread.hpp"
-
-#include "global.hpp"
-
-using namespace amiro;
-
-extern Global global;
-
-// State machine states
-enum states : uint8_t {
-	IDLE,
-	GO_RIGHT,
-	GO_STRAIGHT,
-	PARKING,
-	PARKING_RIGHT,
-	PARKING_LEFT,
-	GO_LEFT,
-	SPINNING_PARKING,
-	SPINNING
-};
-
-// Policy
-states policy[] = {
-  GO_STRAIGHT,
-  GO_RIGHT,
-  GO_RIGHT,
-  GO_STRAIGHT,
-  GO_RIGHT,
-  GO_STRAIGHT,
-  GO_RIGHT,
-  GO_STRAIGHT,
-  GO_STRAIGHT,
-  GO_RIGHT,
-  GO_STRAIGHT,
-  GO_RIGHT,
-  GO_STRAIGHT
-};
-
-// The different classes (or members) of color discrimination
-// BLACK is the line itselfe
-// GREY is the boarder between the line and the surface
-// WHITE is the common surface
-enum colorMember : uint8_t {
-	BLACK=0,
-	GREY=1,
-	WHITE=2
-};
-
-// a buffer for the z-value of the accelerometer
-int16_t accel_z;
-bool running;
-
-// Get some information about the policy
-const int sizeOfPolicy = sizeof(policy) / sizeof(states);
-int policyCounter = 0; // Do not change this, it points to the beginning of the policy
-
-// Different speed settings (all values in "rounds per minute")
-const int rpmForward[2] = {25,25};
-const int rpmSoftLeft[2] = {15,25};
-const int rpmHardLeft[2] = {10,25};
-const int rpmSoftRight[2] = {rpmSoftLeft[1],rpmSoftLeft[0]};
-const int rpmHardRight[2] = {rpmHardLeft[1],rpmHardLeft[0]};
-const int rpmTurnLeft[2] = {-10, 10};
-const int rpmTurnRight[2] = {rpmTurnLeft[1],rpmTurnLeft[0]};
-const int rpmHalt[2] = {0, 0};
-
-// Definition of the fuzzyfication function
-//  | Membership
-// 1|_B__   G    __W__
-//  |    \  /\  /
-//  |     \/  \/
-//  |_____/\__/\______ Sensor values
-// SEE MATLAB SCRIPT "fuzzyRule.m" for adjusting the values
-// All values are "raw sensor values"
-/* Use these values for white ground surface (e.g. paper) */
-
-const int blackStartFalling = 0x1000; // Where the black curve starts falling
-const int blackOff = 0x1800; // Where no more black is detected
-const int whiteStartRising = 0x2800; // Where the white curve starts rising
-const int whiteOn = 0x6000; // Where the white curve has reached the maximum value
-const int greyMax = (whiteOn + blackStartFalling) / 2; // Where grey has its maximum
-const int greyStartRising = blackStartFalling; // Where grey starts rising
-const int greyOff = whiteOn; // Where grey is completely off again
-
-/* Use these values for gray ground surfaces */
-/*
-const int blackStartFalling = 0x1000; // Where the black curve starts falling
-const int blackOff = 0x2800; // Where no more black is detected
-const int whiteStartRising = 0x4000; // Where the white curve starts rising
-const int whiteOn = 0x5000; // Where the white curve starts rising
-const int greyMax = (whiteOn + blackStartFalling) / 2; // Where grey has its maximum
-const int greyStartRising = blackStartFalling; // Where grey starts rising
-const int greyOff = whiteOn; // Where grey is completely off again
-*/
-
-int vcnl4020AmbientLight[4] = {0};
-int vcnl4020Proximity[4] = {0};
-
-// Border for the discrimination between black and white
-const int discrBlackWhite = 16000; // border in "raw sensor values"
-// Discrimination between black and white (returns BLACK or WHITE)
-// The border was calculated by a MAP-decider
-colorMember discrimination(int value) {
-	if (value < discrBlackWhite)
-		return BLACK;
-	else
-		return WHITE;
-}
-
-// Copy the speed from the source to the target array
-void copyRpmSpeed(const int (&source)[2], int (&target)[2]) {
-	target[constants::DiWheelDrive::LEFT_WHEEL] = source[constants::DiWheelDrive::LEFT_WHEEL];
-	target[constants::DiWheelDrive::RIGHT_WHEEL] = source[constants::DiWheelDrive::RIGHT_WHEEL];
-}
-
-// Fuzzyfication of the sensor values
-void fuzzyfication(int sensorValue, float (&fuzziedValue)[3]) {
-	if (sensorValue < blackStartFalling ) {
-		// Only black value
-		fuzziedValue[BLACK] = 1.0f;
-		fuzziedValue[GREY] = 0.0f;
-		fuzziedValue[WHITE] = 0.0f;
-	} else if (sensorValue > whiteOn ) {
-		// Only white value
-		fuzziedValue[BLACK] = 0.0f;
-		fuzziedValue[GREY] = 0.0f;
-		fuzziedValue[WHITE] = 1.0f;
-	} else if ( sensorValue < greyMax) {
-		// Some greyisch value between black and grey
-
-		// Black is going down
-		if ( sensorValue > blackOff) {
-			fuzziedValue[BLACK] = 0.0f;
-		} else {
-			fuzziedValue[BLACK] = static_cast<float>(sensorValue-blackOff) / (blackStartFalling-blackOff);
-		}
-
-		// Grey is going up
-		if ( sensorValue < greyStartRising) {
-			fuzziedValue[GREY] = 0.0f;
-		} else {
-			fuzziedValue[GREY] = static_cast<float>(sensorValue-greyStartRising) / (greyMax-greyStartRising);
-		}
-
-		// White is absent
-		fuzziedValue[WHITE] = 0.0f;
-
-	} else if ( sensorValue >= greyMax) {
-		// Some greyisch value between grey white
-
-		// Black is absent
-		fuzziedValue[BLACK] = 0.0f;
-
-		// Grey is going down
-		if ( sensorValue < greyOff) {
-			fuzziedValue[GREY] = static_cast<float>(sensorValue-greyOff) / (greyMax-greyOff);
-		} else {
-			fuzziedValue[GREY] = 0.0f;
-		}
-
-		// White is going up
-		if ( sensorValue < whiteStartRising) {
-			fuzziedValue[WHITE] = 0.0f;
-		} else {
-			fuzziedValue[WHITE] = static_cast<float>(sensorValue-whiteStartRising) / (whiteOn-whiteStartRising);
-		}
-	}
-}
-
-// Return the color, which has the highest fuzzy value
-colorMember getMember(float (&fuzzyValue)[3]) {
-	colorMember member;
-
-	if (fuzzyValue[BLACK] > fuzzyValue[GREY])
-		if (fuzzyValue[BLACK] > fuzzyValue[WHITE])
-			member = BLACK;
-		else
-			member = WHITE;
-	else
-		if (fuzzyValue[GREY] > fuzzyValue[WHITE])
-			member = GREY;
-		else
-			member = WHITE;
-
-	return member;
-}
-
-// Get a crisp output for the steering commands
-void defuzzyfication(colorMember (&member)[4], int (&rpmFuzzyCtrl)[2]) {
-
-	// all sensors are equal
-	if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == member[constants::DiWheelDrive::PROX_FRONT_LEFT] &&
-	    member[constants::DiWheelDrive::PROX_FRONT_LEFT] == member[constants::DiWheelDrive::PROX_FRONT_RIGHT] &&
-	    member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == member[constants::DiWheelDrive::PROX_WHEEL_RIGHT]) {
-		// something is wrong -> stop
-		copyRpmSpeed(rpmHalt, rpmFuzzyCtrl);
-	// both front sensor detect a line
-	} else if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == BLACK &&
-	    member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == BLACK) {
-		// straight
-		copyRpmSpeed(rpmForward, rpmFuzzyCtrl);
-	// exact one front sensor detects a line
-	} else if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == BLACK ||
-	           member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == BLACK) {
-		// soft correction
-		if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == GREY) {
-			// soft right
-			copyRpmSpeed(rpmSoftRight, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == WHITE) {
-			// hard right
-			copyRpmSpeed(rpmHardRight, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == GREY) {
-			// soft left
-			copyRpmSpeed(rpmSoftLeft, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == WHITE) {
-			// hard left
-			copyRpmSpeed(rpmHardLeft, rpmFuzzyCtrl);
-		}
-	// both wheel sensors detect a line
-	} else if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == BLACK &&
-	           member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == BLACK) {
-		// something is wrong -> stop
-		copyRpmSpeed(rpmHalt, rpmFuzzyCtrl);
-	// exactly one wheel sensor detects a line
-	} else if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == BLACK ||
-	           member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == BLACK) {
-		if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == BLACK) {
-			// turn left
-			copyRpmSpeed(rpmTurnLeft, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == BLACK) {
-			// turn right
-			copyRpmSpeed(rpmTurnRight, rpmFuzzyCtrl);
-		}
-	// both front sensors may detect a line
-	} else if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == GREY &&
-	           member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == GREY) {
-		if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == GREY) {
-			// turn left
-			copyRpmSpeed(rpmTurnLeft, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == GREY) {
-			// turn right
-			copyRpmSpeed(rpmTurnRight, rpmFuzzyCtrl);
-		}
-	// exactly one front sensor may detect a line
-	} else if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == GREY ||
-	           member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == GREY) {
-		if (member[constants::DiWheelDrive::PROX_FRONT_LEFT] == GREY) {
-			// turn left
-			copyRpmSpeed(rpmTurnLeft, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_FRONT_RIGHT] == GREY) {
-			// turn right
-			copyRpmSpeed(rpmTurnRight, rpmFuzzyCtrl);
-		}
-	// both wheel sensors may detect a line
-	} else if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == GREY &&
-	           member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == GREY) {
-		// something is wrong -> stop
-		copyRpmSpeed(rpmHalt, rpmFuzzyCtrl);
-	// exactly one wheel sensor may detect a line
-	} else if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == GREY ||
-	           member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == GREY) {
-		if (member[constants::DiWheelDrive::PROX_WHEEL_LEFT] == GREY) {
-			// turn left
-			copyRpmSpeed(rpmTurnLeft, rpmFuzzyCtrl);
-		} else if (member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] == GREY) {
-			// turn right
-			copyRpmSpeed(rpmTurnRight, rpmFuzzyCtrl);
-		}
-	// no sensor detects anything 
-	} else {
-		// line is lost -> stop
-		copyRpmSpeed(rpmHalt, rpmFuzzyCtrl);
-	}
-
-	return;
-}
-
-Color memberToLed(colorMember member) {
-	switch (member) {
-		case BLACK:
-			return Color(Color::GREEN);
-		case GREY:
-			return Color(Color::YELLOW);
-		case WHITE:
-			return Color(Color::RED);
-		default:
-			return Color(Color::WHITE);
-	}
-}
-
-// Line following by a fuzzy controler
-void lineFollowing(int (&proximity)[4], int (&rpmFuzzyCtrl)[2]) {
-	// FUZZYFICATION
-	// First we need to get the fuzzy value for our 3 values {BLACK, GREY, WHITE}
-	float leftWheelFuzzyMemberValues[3], leftFrontFuzzyMemberValues[3], rightFrontFuzzyMemberValues[3], rightWheelFuzzyMemberValues[3];
-	fuzzyfication(proximity[constants::DiWheelDrive::PROX_WHEEL_LEFT], leftWheelFuzzyMemberValues);
-	fuzzyfication(proximity[constants::DiWheelDrive::PROX_FRONT_LEFT], leftFrontFuzzyMemberValues);
-	fuzzyfication(proximity[constants::DiWheelDrive::PROX_FRONT_RIGHT], rightFrontFuzzyMemberValues);
-	fuzzyfication(proximity[constants::DiWheelDrive::PROX_WHEEL_RIGHT], rightWheelFuzzyMemberValues);
-
-	// INFERENCE RULE DEFINITION
-	// Get the member for each sensor
-	colorMember member[4];
-	member[constants::DiWheelDrive::PROX_WHEEL_LEFT] = getMember(leftWheelFuzzyMemberValues);
-	member[constants::DiWheelDrive::PROX_FRONT_LEFT] = getMember(leftFrontFuzzyMemberValues);
-	member[constants::DiWheelDrive::PROX_FRONT_RIGHT] = getMember(rightFrontFuzzyMemberValues);
-	member[constants::DiWheelDrive::PROX_WHEEL_RIGHT] = getMember(rightWheelFuzzyMemberValues);
-
-	// visualize sensors via LEDs
-	global.robot.setLightColor(constants::LightRing::LED_WNW, memberToLed(member[constants::DiWheelDrive::PROX_WHEEL_LEFT]));
-	global.robot.setLightColor(constants::LightRing::LED_NNW, memberToLed(member[constants::DiWheelDrive::PROX_FRONT_LEFT]));
-	global.robot.setLightColor(constants::LightRing::LED_NNE, memberToLed(member[constants::DiWheelDrive::PROX_FRONT_RIGHT]));
-	global.robot.setLightColor(constants::LightRing::LED_ENE, memberToLed(member[constants::DiWheelDrive::PROX_WHEEL_RIGHT]));
-
-//	chprintf((BaseSequentialStream*) &SD1, "Left: BLACK: %f, GREY: %f, WHITE: %f\r\n", leftFuzzyMemberValues[BLACK], leftFuzzyMemberValues[GREY], leftFuzzyMemberValues[WHITE]);
-//	chprintf((BaseSequentialStream*) &SD1, "Right: BLACK: %f, GREY: %f, WHITE: %f\r\n", rightFuzzyMemberValues[BLACK], rightFuzzyMemberValues[GREY], rightFuzzyMemberValues[WHITE]);
-
-	// DEFUZZYFICATION
-	defuzzyfication(member, rpmFuzzyCtrl);
-}
-
-// Set the speed by the array
-void setRpmSpeed(const int (&rpmSpeed)[2]) {
-	global.motorcontrol.setTargetRPM(rpmSpeed[constants::DiWheelDrive::LEFT_WHEEL] * 1000000, rpmSpeed[constants::DiWheelDrive::RIGHT_WHEEL] * 1000000);
-}
-
-// Get the next policy rule
-states getNextPolicy() {
-	// If the policy is over, start again
-	if (policyCounter >= sizeOfPolicy)
-		policyCounter = 3;
-
-	return policy[policyCounter++];
-}
-
-
-
-UserThread::UserThread() :
-  chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>()
-{
-}
-
-UserThread::~UserThread()
-{
-}
-
-msg_t
-UserThread::main()
-{
-	/*
-	 * SETUP
-	 */
-	int rpmFuzzyCtrl[2] = {0};
-    for (uint8_t led = 0; led < 8; ++led) {
-		global.robot.setLightColor(led, Color(Color::BLACK));
-    }
-    running = false;
-
-	/*
-	 * LOOP
-	 */
-	while (!this->shouldTerminate())
-	{
-        /*
-         * read accelerometer z-value
-         */
-        accel_z = global.lis331dlh.getAccelerationForce(LIS331DLH::AXIS_Z);
-
-        /*
-         * evaluate the accelerometer
-         */
-        if (accel_z < -900 /*-0.9g*/) {
-            if (running) {
-                // stop the robot
-                running = false;
-                global.motorcontrol.setTargetRPM(0, 0);
-            } else {
-                // start the robot
-                running = true;
-            }
-            // set the front LEDs to blue for one second
-            global.robot.setLightColor(constants::LightRing::LED_SSW, Color(Color::BLACK));
-            global.robot.setLightColor(constants::LightRing::LED_WSW, Color(Color::BLACK));
-            global.robot.setLightColor(constants::LightRing::LED_WNW, Color(Color::WHITE));
-            global.robot.setLightColor(constants::LightRing::LED_NNW, Color(Color::WHITE));
-            global.robot.setLightColor(constants::LightRing::LED_NNE, Color(Color::WHITE));
-            global.robot.setLightColor(constants::LightRing::LED_ENE, Color(Color::WHITE));
-            global.robot.setLightColor(constants::LightRing::LED_ESE, Color(Color::BLACK));
-            global.robot.setLightColor(constants::LightRing::LED_SSE, Color(Color::BLACK));
-            this->sleep(MS2ST(1000));
-            global.robot.setLightColor(constants::LightRing::LED_WNW, Color(Color::BLACK));
-            global.robot.setLightColor(constants::LightRing::LED_NNW, Color(Color::BLACK));
-            global.robot.setLightColor(constants::LightRing::LED_NNE, Color(Color::BLACK));
-            global.robot.setLightColor(constants::LightRing::LED_ENE, Color(Color::BLACK));
-        }
-
-        if (running) {
-            // Read the proximity values
-            for (int i = 0; i < 4; i++) {
-                vcnl4020AmbientLight[i] = global.vcnl4020[i].getAmbientLight();
-                vcnl4020Proximity[i] = global.vcnl4020[i].getProximityScaledWoOffset();
-            }
-
-//            chprintf((BaseSequentialStream*) &SD1, "0x%04X 0x%04X 0x%04X 0x%04X\n",
-//                     vcnl4020Proximity[constants::DiWheelDrive::PROX_WHEEL_LEFT],
-//                     vcnl4020Proximity[constants::DiWheelDrive::PROX_FRONT_LEFT],
-//                     vcnl4020Proximity[constants::DiWheelDrive::PROX_FRONT_RIGHT],
-//                     vcnl4020Proximity[constants::DiWheelDrive::PROX_WHEEL_RIGHT]);
-
-            lineFollowing(vcnl4020Proximity, rpmFuzzyCtrl);
-            setRpmSpeed(rpmFuzzyCtrl);
-        }
-
-		this->sleep(CAN::UPDATE_PERIOD);
-	}
-
-  return RDY_OK;
-}
-
diff --git a/devices/DiWheelDrive/userthread.hpp b/devices/DiWheelDrive/userthread.hpp
deleted file mode 100644
index ac056b1..0000000
--- a/devices/DiWheelDrive/userthread.hpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef AMIRO_USERTHREAD_H_
-#define AMIRO_USERTHREAD_H_
-
-#include <ch.hpp>
-#include <amiroosconf.h>
-
-namespace amiro {
-
-class UserThread : public chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>
-{
-public:
-  explicit UserThread();
-
-  virtual ~UserThread();
-
-  virtual msg_t main();
-};
-
-} // end of namespace amiro
-
-#endif // AMIRO_USERTHREAD_H_
diff --git a/devices/LightRing/LightRing.cpp b/devices/LightRing/LightRing.cpp
deleted file mode 100644
index 98158fa..0000000
--- a/devices/LightRing/LightRing.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-#include "ch.hpp"
-#include "hal.h"
-
-#include "LightRing.h"
-
-#include <global.hpp>
-
-using namespace chibios_rt;
-using namespace amiro;
-using namespace types;
-
-extern volatile uint32_t shutdown_now;
-extern Global global;
-
-
-LightRing::LightRing(CANDriver *can, TLC5947 *tlc5947, fileSystemIo::FSIOLightRing *memory)
-    : ControllerAreaNetworkTx(can, CAN::LIGHT_RING_ID),
-      ControllerAreaNetworkRx(can, CAN::LIGHT_RING_ID),
-      tlc5947(tlc5947),
-      memory(memory) {
-  chDbgCheck(tlc5947 != NULL, "LightRing");
-}
-
-void LightRing::setLightBrightness(int brightness) {
-  this->tlc5947->setBrightness(brightness);
-  this->tlc5947->update();
-}
-
-void LightRing::setLightColor(int index, Color color) {
-  this->tlc5947->setColor(index, color);
-  this->tlc5947->update();
-}
-
-msg_t LightRing::receiveMessage(CANRxFrame *frame) {
-  int deviceId = this->decodeDeviceId(frame);
-
-  switch (deviceId) {
-
-    case CAN::SHELL_REPLY_ID(CAN::LIGHT_RING_ID):
-      if (frame->DLC > 0) {
-        sdWrite(&SD1, frame->data8, frame->DLC);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::SHELL_QUERY_ID(CAN::LIGHT_RING_ID):
-      if (frame->DLC != 0) {
-        global.sercanmux1.convCan2Serial(frame->data8, frame->DLC);
-        return RDY_OK;
-      } else {
-        global.sercanmux1.rcvSwitchCmd(this->decodeBoardId(frame));
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::COLOR_ID(0):
-    case CAN::COLOR_ID(1):
-    case CAN::COLOR_ID(2):
-    case CAN::COLOR_ID(3):
-    case CAN::COLOR_ID(4):
-    case CAN::COLOR_ID(5):
-    case CAN::COLOR_ID(6):
-    case CAN::COLOR_ID(7):
-      if (frame->DLC == 3) {
-        int index = deviceId & 0x7;
-        Color color(frame->data8[0], frame->data8[1], frame->data8[2]);
-        this->setLightColor(index, color);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::BRIGHTNESS_ID:
-      if (frame->DLC == 1) {
-        int brightness = frame->data8[0];
-        this->setLightBrightness(brightness);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::BROADCAST_SHUTDOWN:
-      if (frame->DLC == 2 && frame->data16[0] == CAN::SHUTDOWN_MAGIC) {
-        shutdown_now = 0x4;
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::ROBOT_ID:
-      if (frame->DLC == 1) {
-        this->robotId = frame->data8[0];
-        return RDY_OK;
-      }
-      break;
-
-    default:
-      break;
-  }
-  return -1;
-}
-
-ThreadReference LightRing::start(tprio_t PRIO) {
-  this->ControllerAreaNetworkRx::start(PRIO + 1);
-  this->ControllerAreaNetworkTx::start(PRIO);
-  return NULL;
-}
-
-msg_t
-LightRing::terminate(void) {
-  msg_t ret = RDY_OK;
-
-  this->ControllerAreaNetworkTx::requestTerminate();
-  ret |= this->ControllerAreaNetworkTx::wait();
-  this->ControllerAreaNetworkRx::requestTerminate();
-  ret |= this->ControllerAreaNetworkRx::wait();
-
-  return ret;
-}
-
-void LightRing::periodicBroadcast() {
-
-}
diff --git a/devices/LightRing/LightRing.h b/devices/LightRing/LightRing.h
deleted file mode 100644
index 0001c8a..0000000
--- a/devices/LightRing/LightRing.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _AMIRO_LIGTH_RING_H_
-#define _AMIRO_LIGTH_RING_H_
-
-#include <amiro/Constants.h>
-
-#include <amiro/ControllerAreaNetworkRx.h>
-#include <amiro/ControllerAreaNetworkTx.h>
-#include <amiro/leds/tlc5947.hpp>
-#include <amiro/FileSystemInputOutput/FSIOLightRing.hpp>
-
-using namespace chibios_rt;
-
-namespace amiro {
-
-  class LightRing : public ControllerAreaNetworkTx, public ControllerAreaNetworkRx {
-  public:
-    LightRing(CANDriver *can, TLC5947 *tlc5947, fileSystemIo::FSIOLightRing *memory);
-    void setLightBrightness(int brightness);
-    void setLightColor(int index, Color color);
-
-    /** \brief Handle the termination of ControllerAreaNetworkTx and ControllerAreaNetworkRx threads
-     *         This includes waiting until the threads have terminated, thus this function might block a relatively long time.
-     */
-    msg_t terminate(void);
-
-    /** \brief Handle the start of ControllerAreaNetworkTx and ControllerAreaNetworkRx threads */
-    ThreadReference start(tprio_t PRIO);
-
-  protected:
-    virtual msg_t receiveMessage(CANRxFrame *frame);
-    virtual void periodicBroadcast();
-
-  private:
-    TLC5947 *tlc5947;
-    fileSystemIo::FSIOLightRing *memory;
-  };
-
-}
-
-#endif /* _AMIRO_LIGTH_RING_H_ */
-
-/** @} */
diff --git a/devices/LightRing/Makefile b/devices/LightRing/Makefile
deleted file mode 100644
index c01caf6..0000000
--- a/devices/LightRing/Makefile
+++ /dev/null
@@ -1,249 +0,0 @@
-##############################################################################
-# Build global options
-# NOTE: Can be overridden externally.
-#
-
-# Compiler options here.
-ifeq ($(USE_OPT),)
-  USE_OPT = -O2 -fomit-frame-pointer -falign-functions=16 -DCHPRINTF_USE_FLOAT=1 -fstack-usage -DSERIAL_BUFFERS_SIZE=64
-endif
-
-# C specific options here (added to USE_OPT).
-ifeq ($(USE_COPT),)
-  USE_COPT =
-endif
-
-# C++ specific options here (added to USE_OPT).
-ifeq ($(USE_CPPOPT),)
-  USE_CPPOPT = -fno-rtti -fno-exceptions -std=c++11 -U__STRICT_ANSI__
-endif
-
-# Enable this if you want the linker to remove unused code and data
-ifeq ($(USE_LINK_GC),)
-  USE_LINK_GC = yes
-endif
-
-# Linker extra options here.
-ifeq ($(USE_LDOPT),)
-  USE_LDOPT =
-endif
-
-# Enable this if you want link time optimizations (LTO)
-ifeq ($(USE_LTO),)
-  USE_LTO = no
-endif
-
-# If enabled, this option allows to compile the application in THUMB mode.
-ifeq ($(USE_THUMB),)
-  USE_THUMB = yes
-endif
-
-# Enable this if you want to see the full log while compiling.
-ifeq ($(USE_VERBOSE_COMPILE),)
-  USE_VERBOSE_COMPILE = no
-endif
-
-#
-# Build global options
-##############################################################################
-
-##############################################################################
-# Architecture or project specific options
-#
-
-# Enable this if you really want to use the STM FWLib.
-ifeq ($(USE_FWLIB),)
-  USE_FWLIB = no
-endif
-
-#
-# Architecture or project specific options
-##############################################################################
-
-##############################################################################
-# Project, sources and paths
-#
-
-# Define project name here
-PROJECT = LightRing
-
-# Imported source files and paths
-CHIBIOS = ../../../ChibiOS
-AMIRO = ../..
-include $(AMIRO)/boards/LightRing/board.mk
-include $(CHIBIOS)/os/hal/platforms/STM32F1xx/platform.mk
-include $(CHIBIOS)/os/hal/hal.mk
-include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F1xx/port.mk
-include $(CHIBIOS)/os/kernel/kernel.mk
-include $(CHIBIOS)/os/various/cpp_wrappers/kernel.mk
-
-# Define linker script file here
-LDSCRIPT= $(BOARDLD)/STM32F103xE.ld
-
-# C sources that can be compiled in ARM or THUMB mode depending on the global
-# setting.
-CSRC = $(PORTSRC) \
-       $(KERNSRC) \
-       $(HALSRC) \
-       $(PLATFORMSRC) \
-       $(BOARDSRC) \
-       $(CHIBIOS)/os/various/evtimer.c \
-       $(CHIBIOS)/os/various/syscalls.c \
-       $(CHIBIOS)/os/various/chprintf.c \
-       $(CHIBIOS)/os/various/shell.c \
-       $(CHIBIOS)/os/various/memstreams.c \
-       $(AMIRO)/stubs.c \
-       $(AMIRO)/components/Debug.c
-
-# C++ sources that can be compiled in ARM or THUMB mode depending on the global
-# setting.
-CPPSRC = $(CHCPPSRC) \
-         $(AMIRO)/components/Color.cpp \
-         $(AMIRO)/components/bus/spi/HWSPIDriver.cpp \
-         $(AMIRO)/components/bus/i2c/HWI2CDriver.cpp \
-         $(AMIRO)/components/leds/tlc5947.cpp \
-         $(AMIRO)/components/radio/a2500r24a.cpp \
-         $(AMIRO)/components/eeprom/eeprom.cpp \
-         $(AMIRO)/components/eeprom/at24.cpp \
-         $(AMIRO)/components/FileSystemInputOutput/FileSystemInputOutputBase.cpp \
-         $(AMIRO)/components/FileSystemInputOutput/FSIOLightRing.cpp \
-         $(AMIRO)/components/ControllerAreaNetworkRx.cpp \
-         $(AMIRO)/components/ControllerAreaNetworkTx.cpp \
-         $(AMIRO)/components/Lidar.cpp \
-         $(AMIRO)/components/serial_reset/serial_can_mux.cpp \
-         LightRing.cpp \
-         userthread.cpp \
-         main.cpp \
-         exti.cpp
-
-# C sources to be compiled in ARM mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-ACSRC =
-
-# C++ sources to be compiled in ARM mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-ACPPSRC =
-
-# C sources to be compiled in THUMB mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-TCSRC =
-
-# C sources to be compiled in THUMB mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-TCPPSRC =
-
-# List ASM source files here
-ASMSRC = $(PORTASM)
-
-INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
-         $(HALINC) $(PLATFORMINC) $(BOARDINC) \
-         $(CHCPPINC) \
-         $(CHIBIOS)/os/various \
-         $(AMIRO) \
-         $(AMIRO)/include
-
-#
-# Project, sources and paths
-##############################################################################
-
-##############################################################################
-# Compiler settings
-#
-
-MCU  = cortex-m3
-
-#TRGT = arm-elf-
-TRGT = arm-none-eabi-
-CC   = $(TRGT)gcc
-CPPC = $(TRGT)g++
-# Enable loading with g++ only if you need C++ runtime support.
-# NOTE: You can use C++ even without C++ support if you are careful. C++
-#       runtime support makes code size explode.
-#LD   = $(TRGT)gcc
-LD   = $(TRGT)g++
-CP   = $(TRGT)objcopy
-AS   = $(TRGT)gcc -x assembler-with-cpp
-OD   = $(TRGT)objdump
-SZ   = $(TRGT)size
-HEX  = $(CP) -O ihex
-BIN  = $(CP) -O binary
-SREC = $(CP) -O srec --srec-len=248
-
-# ARM-specific options here
-AOPT =
-
-# THUMB-specific options here
-TOPT = -mthumb -DTHUMB
-
-# Define C warning options here
-CWARN = -Wall -Wextra -Wstrict-prototypes
-
-# Define C++ warning options here
-CPPWARN = -Wall -Wextra
-
-#
-# Compiler settings
-##############################################################################
-
-##############################################################################
-# Start of default section
-#
-
-# List all default C defines here, like -D_DEBUG=1
-DDEFS =
-
-# List all default ASM defines here, like -D_DEBUG=1
-DADEFS =
-
-# List all default directories to look for include files here
-DINCDIR =
-
-# List the default directory to look for the libraries here
-DLIBDIR =
-
-# List all default libraries here
-DLIBS =
-
-#
-# End of default section
-##############################################################################
-
-##############################################################################
-# Start of user section
-#
-
-# List all user C define here, like -D_DEBUG=1
-UDEFS =
-
-# Define ASM defines here
-UADEFS =
-
-# List all user directories here
-UINCDIR =
-
-# List the user directory to look for the libraries here
-ULIBDIR =
-
-# List all user libraries here
-ULIBS =
-
-#
-# End of user defines
-##############################################################################
-
-ifeq ($(USE_FWLIB),yes)
-  include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
-  CSRC += $(STM32SRC)
-  INCDIR += $(STM32INC)
-  USE_OPT += -DUSE_STDPERIPH_DRIVER
-endif
-
-RULESPATH = $(CHIBIOS)/os/ports/GCC/ARMCMx
-include $(RULESPATH)/rules.mk
-
-include $(AMIRO)/ports/rules.mk
-include $(AMIRO)/devices/flash.mk
diff --git a/devices/LightRing/amiroosconf.h b/devices/LightRing/amiroosconf.h
deleted file mode 100644
index 4bb1b27..0000000
--- a/devices/LightRing/amiroosconf.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef AMIRO_AMIROOSCONF_H_
-#define AMIRO_AMIROOSCONF_H_
-
-/**
- * @brief Stack size of the user thread object
- */
-#if !defined(USER_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
-#define USER_THREAD_STACK_SIZE         1024
-#endif
-
-/**
- * @brief Flag to enable/disable als amiroDbgXXX macros
- */
-#if !defined(AMIRO_DBG) || defined(__DOXYGEN__)
-#define AMIRO_DBG                      TRUE
-#endif
-
-#endif // AMIRO_AMIROOSCONF_H_
-
diff --git a/devices/LightRing/chconf.h b/devices/LightRing/chconf.h
deleted file mode 100644
index 963a543..0000000
--- a/devices/LightRing/chconf.h
+++ /dev/null
@@ -1,518 +0,0 @@
-/**
- * @file    devices/LightRing/chconf.h
- * @brief   Configuration file.
- *
- * @addtogroup config
- * @details Kernel related settings and hooks.
- * @{
- */
-
-#ifndef _CHCONF_H_
-#define _CHCONF_H_
-
-/*===========================================================================*/
-/**
- * @name Kernel parameters and options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   System tick frequency.
- * @details Frequency of the system timer that drives the system ticks. This
- *          setting also defines the system tick time unit.
- */
-#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__)
-#define CH_FREQUENCY                    1000
-#endif
-
-/**
- * @brief   Round robin interval.
- * @details This constant is the number of system ticks allowed for the
- *          threads before preemption occurs. Setting this value to zero
- *          disables the preemption for threads with equal priority and the
- *          round robin becomes cooperative. Note that higher priority
- *          threads can still preempt, the kernel is always preemptive.
- *
- * @note    Disabling the round robin preemption makes the kernel more compact
- *          and generally faster.
- */
-#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__)
-#define CH_TIME_QUANTUM                 20
-#endif
-
-/**
- * @brief   Managed RAM size.
- * @details Size of the RAM area to be managed by the OS. If set to zero
- *          then the whole available RAM is used. The core memory is made
- *          available to the heap allocator and/or can be used directly through
- *          the simplified core memory allocator.
- *
- * @note    In order to let the OS manage the whole RAM the linker script must
- *          provide the @p __heap_base__ and @p __heap_end__ symbols.
- * @note    Requires @p CH_USE_MEMCORE.
- */
-#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__)
-#define CH_MEMCORE_SIZE                 0
-#endif
-
-/**
- * @brief   Idle thread automatic spawn suppression.
- * @details When this option is activated the function @p chSysInit()
- *          does not spawn the idle thread automatically. The application has
- *          then the responsibility to do one of the following:
- *          - Spawn a custom idle thread at priority @p IDLEPRIO.
- *          - Change the main() thread priority to @p IDLEPRIO then enter
- *            an endless loop. In this scenario the @p main() thread acts as
- *            the idle thread.
- *          .
- * @note    Unless an idle thread is spawned the @p main() thread must not
- *          enter a sleep state.
- */
-#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__)
-#define CH_NO_IDLE_THREAD               FALSE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Performance options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   OS optimization.
- * @details If enabled then time efficient rather than space efficient code
- *          is used when two possible implementations exist.
- *
- * @note    This is not related to the compiler optimization options.
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__)
-#define CH_OPTIMIZE_SPEED               TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Subsystem options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Threads registry APIs.
- * @details If enabled then the registry APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__)
-#define CH_USE_REGISTRY                 TRUE
-#endif
-
-/**
- * @brief   Threads synchronization APIs.
- * @details If enabled then the @p chThdWait() function is included in
- *          the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__)
-#define CH_USE_WAITEXIT                 TRUE
-#endif
-
-/**
- * @brief   Semaphores APIs.
- * @details If enabled then the Semaphores APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__)
-#define CH_USE_SEMAPHORES               TRUE
-#endif
-
-/**
- * @brief   Semaphores queuing mode.
- * @details If enabled then the threads are enqueued on semaphores by
- *          priority rather than in FIFO order.
- *
- * @note    The default is @p FALSE. Enable this if you have special requirements.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__)
-#define CH_USE_SEMAPHORES_PRIORITY      FALSE
-#endif
-
-/**
- * @brief   Atomic semaphore API.
- * @details If enabled then the semaphores the @p chSemSignalWait() API
- *          is included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__)
-#define CH_USE_SEMSW                    TRUE
-#endif
-
-/**
- * @brief   Mutexes APIs.
- * @details If enabled then the mutexes APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__)
-#define CH_USE_MUTEXES                  TRUE
-#endif
-
-/**
- * @brief   Conditional Variables APIs.
- * @details If enabled then the conditional variables APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_MUTEXES.
- */
-#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__)
-#define CH_USE_CONDVARS                 TRUE
-#endif
-
-/**
- * @brief   Conditional Variables APIs with timeout.
- * @details If enabled then the conditional variables APIs with timeout
- *          specification are included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_CONDVARS.
- */
-#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__)
-#define CH_USE_CONDVARS_TIMEOUT         TRUE
-#endif
-
-/**
- * @brief   Events Flags APIs.
- * @details If enabled then the event flags APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__)
-#define CH_USE_EVENTS                   TRUE
-#endif
-
-/**
- * @brief   Events Flags APIs with timeout.
- * @details If enabled then the events APIs with timeout specification
- *          are included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_EVENTS.
- */
-#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
-#define CH_USE_EVENTS_TIMEOUT           TRUE
-#endif
-
-/**
- * @brief   Synchronous Messages APIs.
- * @details If enabled then the synchronous messages APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__)
-#define CH_USE_MESSAGES                 TRUE
-#endif
-
-/**
- * @brief   Synchronous Messages queuing mode.
- * @details If enabled then messages are served by priority rather than in
- *          FIFO order.
- *
- * @note    The default is @p FALSE. Enable this if you have special requirements.
- * @note    Requires @p CH_USE_MESSAGES.
- */
-#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__)
-#define CH_USE_MESSAGES_PRIORITY        FALSE
-#endif
-
-/**
- * @brief   Mailboxes APIs.
- * @details If enabled then the asynchronous messages (mailboxes) APIs are
- *          included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__)
-#define CH_USE_MAILBOXES                TRUE
-#endif
-
-/**
- * @brief   I/O Queues APIs.
- * @details If enabled then the I/O queues APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__)
-#define CH_USE_QUEUES                   TRUE
-#endif
-
-/**
- * @brief   Core Memory Manager APIs.
- * @details If enabled then the core memory manager APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__)
-#define CH_USE_MEMCORE                  TRUE
-#endif
-
-/**
- * @brief   Heap Allocator APIs.
- * @details If enabled then the memory heap allocator APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or
- *          @p CH_USE_SEMAPHORES.
- * @note    Mutexes are recommended.
- */
-#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__)
-#define CH_USE_HEAP                     TRUE
-#endif
-
-/**
- * @brief   C-runtime allocator.
- * @details If enabled the the heap allocator APIs just wrap the C-runtime
- *          @p malloc() and @p free() functions.
- *
- * @note    The default is @p FALSE.
- * @note    Requires @p CH_USE_HEAP.
- * @note    The C-runtime may or may not require @p CH_USE_MEMCORE, see the
- *          appropriate documentation.
- */
-#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
-#define CH_USE_MALLOC_HEAP              FALSE
-#endif
-
-/**
- * @brief   Memory Pools Allocator APIs.
- * @details If enabled then the memory pools allocator APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__)
-#define CH_USE_MEMPOOLS                 TRUE
-#endif
-
-/**
- * @brief   Dynamic Threads APIs.
- * @details If enabled then the dynamic threads creation APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_WAITEXIT.
- * @note    Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS.
- */
-#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__)
-#define CH_USE_DYNAMIC                  TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Debug options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Debug option, system state check.
- * @details If enabled the correct call protocol for system APIs is checked
- *          at runtime.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
-#define CH_DBG_SYSTEM_STATE_CHECK       TRUE
-#endif
-
-/**
- * @brief   Debug option, parameters checks.
- * @details If enabled then the checks on the API functions input
- *          parameters are activated.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_CHECKS            TRUE
-#endif
-
-/**
- * @brief   Debug option, consistency checks.
- * @details If enabled then all the assertions in the kernel code are
- *          activated. This includes consistency checks inside the kernel,
- *          runtime anomalies and port-defined checks.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_ASSERTS           TRUE
-#endif
-
-/**
- * @brief   Debug option, trace buffer.
- * @details If enabled then the context switch circular trace buffer is
- *          activated.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_TRACE             TRUE
-#endif
-
-/**
- * @brief   Debug option, stack checks.
- * @details If enabled then a runtime stack check is performed.
- *
- * @note    The default is @p FALSE.
- * @note    The stack check is performed in a architecture/port dependent way.
- *          It may not be implemented or some ports.
- * @note    The default failure mode is to halt the system with the global
- *          @p panic_msg variable set to @p NULL.
- */
-#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_STACK_CHECK       TRUE
-#endif
-
-/**
- * @brief   Debug option, stacks initialization.
- * @details If enabled then the threads working area is filled with a byte
- *          value when a thread is created. This can be useful for the
- *          runtime measurement of the used stack.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
-#define CH_DBG_FILL_THREADS             FALSE
-#endif
-
-/**
- * @brief   Debug option, threads profiling.
- * @details If enabled then a field is added to the @p Thread structure that
- *          counts the system ticks occurred while executing the thread.
- *
- * @note    The default is @p TRUE.
- * @note    This debug option is defaulted to TRUE because it is required by
- *          some test cases into the test suite.
- */
-#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
-#define CH_DBG_THREADS_PROFILING        TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Kernel hooks
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Threads descriptor structure extension.
- * @details User fields added to the end of the @p Thread structure.
- */
-#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
-#define THREAD_EXT_FIELDS                                                   \
-  /* Add threads custom fields here.*/
-#endif
-
-/**
- * @brief   Threads initialization hook.
- * @details User initialization code added to the @p chThdInit() API.
- *
- * @note    It is invoked from within @p chThdInit() and implicitly from all
- *          the threads creation APIs.
- */
-#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
-#define THREAD_EXT_INIT_HOOK(tp) {                                          \
-  /* Add threads initialization code here.*/                                \
-}
-#endif
-
-/**
- * @brief   Threads finalization hook.
- * @details User finalization code added to the @p chThdExit() API.
- *
- * @note    It is inserted into lock zone.
- * @note    It is also invoked when the threads simply return in order to
- *          terminate.
- */
-#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__)
-#define THREAD_EXT_EXIT_HOOK(tp) {                                          \
-  /* Add threads finalization code here.*/                                  \
-}
-#endif
-
-/**
- * @brief   Context switch hook.
- * @details This hook is invoked just before switching between threads.
- */
-#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
-#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
-  /* Context switch code here.*/                                            \
-}
-#endif
-
-/**
- * @brief   Idle Loop hook.
- * @details This hook is continuously invoked by the idle thread loop.
- */
-#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__)
-#define IDLE_LOOP_HOOK() {                                                  \
-  /* Idle loop code here.*/                                                 \
-}
-#endif
-
-/**
- * @brief   System tick event hook.
- * @details This hook is invoked in the system tick handler immediately
- *          after processing the virtual timers queue.
- */
-#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
-#define SYSTEM_TICK_EVENT_HOOK() {                                          \
-  /* System tick event code here.*/                                         \
-}
-#endif
-
-/**
- * @brief   System halt hook.
- * @details This hook is invoked in case to a system halting error before
- *          the system is halted.
- */
-#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
-void haltErrorCode(void);
-#define SYSTEM_HALT_HOOK() {                                                \
-  /* System halt code here.*/                                               \
-  haltErrorCode();                                                          \
-}
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/* Port-specific settings (override port settings defaulted in chcore.h).    */
-/*===========================================================================*/
-
-/* NVIC VTOR initialization (only offset!) */
-#define CORTEX_VTOR_INIT 0x00006000
-
-#endif  /* _CHCONF_H_ */
-
-/** @} */
diff --git a/devices/LightRing/exti.cpp b/devices/LightRing/exti.cpp
deleted file mode 100644
index 97132fb..0000000
--- a/devices/LightRing/exti.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <board.h>
-
-#include "exti.hpp"
-
-volatile uint32_t shutdown_now = 0x00000000u; // = BL_SHUTDOWN_NONE in main.cpp
-
-EXTConfig extcfg = {
-
-  {
-    /* channel 0 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 1 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 2 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 3 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 4 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 5 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 6 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 7 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 8 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 9 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 10 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 11 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 12 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 13 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 14 */
-    {
-      /* mode */ EXT_MODE_GPIOC | EXT_CH_MODE_AUTOSTART | EXT_CH_MODE_FALLING_EDGE,
-      /* cb   */ power_down_cb,
-    },
-    /* channel 15 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 16 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 17 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 18 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-  }
-};
-
-void power_down_cb(EXTDriver *extp, expchannel_t channel) {
-
-  (void) extp;
-  (void) channel;
-  // make sure we don't accidentally power down when somebody tries to wake us
-  if (!palReadPad(GPIOC, GPIOC_SYS_PD_N))
-    palWritePad(GPIOD, GPIOD_SYS_INT_N, PAL_LOW); // indicate that the module needs some time to shut down
-    shutdown_now = 5; // = SHUTDOWN_HANDLE_REQUEST in main.cpp
-}
diff --git a/devices/LightRing/exti.hpp b/devices/LightRing/exti.hpp
deleted file mode 100644
index 97b8683..0000000
--- a/devices/LightRing/exti.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef EXT_HPP_
-#define EXT_HPP_
-
-extern volatile uint32_t shutdown_now;
-
-extern EXTConfig extcfg;
-
-void power_down_cb(EXTDriver *extp, expchannel_t channel);
-
-#endif /* EXT_HPP_ */
diff --git a/devices/LightRing/global.hpp b/devices/LightRing/global.hpp
deleted file mode 100644
index 7141df6..0000000
--- a/devices/LightRing/global.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef AMIRO_GLOBAL_HPP_
-#define AMIRO_GLOBAL_HPP_
-
-#include <hal.h>
-
-#include <board.h>
-#include <amiro/bus/i2c/HWI2CDriver.hpp>
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/leds/tlc5947.hpp>
-#include <amiro/eeprom/at24.hpp>
-#include <amiro/FileSystemInputOutput/FSIOLightRing.hpp>
-#include <LightRing.h>
-#include <amiro/Lidar.h>
-#include <amiro/radio/a2500r24a.hpp>
-#include <amiro/serial_reset/serial_can_mux.hpp>
-#include <userthread.hpp>
-
-namespace amiro {
-
-class Global final
-{
-public:
-  I2CConfig i2c2_config{
-    /* I2C mode                 */ OPMODE_I2C,
-    /* frequency                */ 400000,
-    /* I2C fast mode duty cycle */ FAST_DUTY_CYCLE_2
-  };
-
-  SerialConfig sd1_config{
-    /* speed        */ 115200,
-    /* CR1 register */ 0,
-    /* CR2 register */ 0,
-    /* CR3 register */ 0
-  };
-  SerialConfig sd2_config{
-    /* speed        */ 19200,
-    /* CR1 register */ 0,
-    /* CR2 register */ 0,
-    /* CR3 register */ 0
-  };
-
-  SPIConfig spi1_config{
-    /* callback function pointer   */ NULL,
-    /* chip select line port       */ GPIOC,
-    /* chip select line pad number */ GPIOC_LIGHT_XLAT,
-    /* initialzation data          */ SPI_CR1_BR_0 | SPI_CR1_BR_1
-  };
-  SPIConfig spi2_config{
-    /* callback function pointer   */ NULL,
-    /* chip select line port       */ GPIOB,
-    /* chip select line pad number */ GPIOB_WL_SS_N,
-    /* initialzation data          */ SPI_CR1_BR_0
-  };
-
-  /**
-   * @brief I2C Bus 2
-   * Conected devices:
-   *   AT24Cxx
-   */
-  HWI2CDriver HW_I2C2;
-
-  HWSPIDriver HW_SPI1;
-  HWSPIDriver HW_SPI2;
-
-  TLC5947 tlc5947;
-
-  AT24 at24c01;
-  fileSystemIo::FSIOLightRing memory;
-
-  LightRing robot;
-
-  SerialCanMux sercanmux1;
-
-  Lidar lidar;
-
-  A2500R24A a2500r24a;
-
-  UserThread userThread;
-
-  uint8_t shellTermID;
-
-public:
-  Global() :
-    HW_I2C2(&I2CD2),
-    HW_SPI1(&SPID1, &spi1_config), HW_SPI2(&SPID2, &spi2_config),
-    tlc5947(&HW_SPI1, GPIOA, GPIOA_LIGHT_BLANK),
-    at24c01(0x400u / 0x08u, 0x08u, 500u, &HW_I2C2),
-    memory(at24c01, /*BMSV*/ 1, /*bmsv*/ 2, /*HMV*/ 1, /*hmv*/ 0),
-    robot(&CAND1, &tlc5947, &memory),
-    sercanmux1(&SD1, &CAND1, CAN::LIGHT_RING_ID),
-    lidar(CAN::LIGHT_RING_ID, Lidar::SETUP::POWER_ONLY),
-    a2500r24a(&HW_SPI2),
-    userThread()
-  {
-    return;
-  }
-
-  ~Global()
-  {
-    return;
-  }
-};
-
-} // end of namespace amiro
-
-#endif /* AMIRO_GLOBAL_HPP_ */
diff --git a/devices/LightRing/halconf.h b/devices/LightRing/halconf.h
deleted file mode 100644
index c343416..0000000
--- a/devices/LightRing/halconf.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/**
- * @file    devices/LightRing/halconf.h
- * @brief   HAL configuration header.
- * @details HAL configuration file, this file allows to enable or disable the
- *          various device drivers from your application. You may also use
- *          this file in order to override the device drivers default settings.
- *
- * @addtogroup HAL_CONF
- * @{
- */
-
-#ifndef _HALCONF_H_
-#define _HALCONF_H_
-
-#include "mcuconf.h"
-
-/**
- * @brief   Enables the TM subsystem.
- */
-#if !defined(HAL_USE_TM) || defined(__DOXYGEN__)
-#define HAL_USE_TM                  TRUE
-#endif
-
-/**
- * @brief   Enables the PAL subsystem.
- */
-#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
-#define HAL_USE_PAL                 TRUE
-#endif
-
-/**
- * @brief   Enables the ADC subsystem.
- */
-#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
-#define HAL_USE_ADC                 FALSE
-#endif
-
-/**
- * @brief   Enables the CAN subsystem.
- */
-#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
-#define HAL_USE_CAN                 TRUE
-#endif
-
-/**
- * @brief   Enables the EXT subsystem.
- */
-#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
-#define HAL_USE_EXT                 TRUE
-#endif
-
-/**
- * @brief   Enables the GPT subsystem.
- */
-#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
-#define HAL_USE_GPT                 FALSE
-#endif
-
-/**
- * @brief   Enables the I2C subsystem.
- */
-#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
-#define HAL_USE_I2C                 TRUE
-#endif
-
-/**
- * @brief   Enables the ICU subsystem.
- */
-#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
-#define HAL_USE_ICU                 FALSE
-#endif
-
-/**
- * @brief   Enables the MAC subsystem.
- */
-#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
-#define HAL_USE_MAC                 FALSE
-#endif
-
-/**
- * @brief   Enables the MMC_SPI subsystem.
- */
-#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_MMC_SPI             FALSE
-#endif
-
-/**
- * @brief   Enables the PWM subsystem.
- */
-#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
-#define HAL_USE_PWM                 FALSE
-#endif
-
-/**
- * @brief   Enables the RTC subsystem.
- */
-#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
-#define HAL_USE_RTC                 FALSE
-#endif
-
-/**
- * @brief   Enables the SDC subsystem.
- */
-#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
-#define HAL_USE_SDC                 FALSE
-#endif
-
-/**
- * @brief   Enables the SERIAL subsystem.
- */
-#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL              TRUE
-#endif
-
-/**
- * @brief   Enables the SERIAL over USB subsystem.
- */
-#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL_USB          FALSE
-#endif
-
-/**
- * @brief   Enables the SPI subsystem.
- */
-#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_SPI                 TRUE
-#endif
-
-/**
- * @brief   Enables the UART subsystem.
- */
-#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
-#define HAL_USE_UART                FALSE
-#endif
-
-/**
- * @brief   Enables the USB subsystem.
- */
-#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
-#define HAL_USE_USB                 FALSE
-#endif
-
-/*===========================================================================*/
-/* ADC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables synchronous APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
-#define ADC_USE_WAIT                TRUE
-#endif
-
-/**
- * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define ADC_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-/*===========================================================================*/
-/* CAN driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Sleep mode related APIs inclusion switch.
- */
-#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
-#define CAN_USE_SLEEP_MODE          TRUE
-#endif
-
-/*===========================================================================*/
-/* I2C driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables the mutual exclusion APIs on the I2C bus.
- */
-#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define I2C_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-/*===========================================================================*/
-/* MAC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
-#define MAC_USE_ZERO_COPY           FALSE
-#endif
-
-/**
- * @brief   Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
-#define MAC_USE_EVENTS              TRUE
-#endif
-
-/*===========================================================================*/
-/* MMC_SPI driver related settings.                                          */
-/*===========================================================================*/
-
-/**
- * @brief   Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- *          routines releasing some extra CPU time for the threads with
- *          lower priority, this may slow down the driver a bit however.
- *          This option is recommended also if the SPI driver does not
- *          use a DMA channel and heavily loads the CPU.
- */
-#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
-#define MMC_NICE_WAITING            TRUE
-#endif
-
-/*===========================================================================*/
-/* SDC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Number of initialization attempts before rejecting the card.
- * @note    Attempts are performed at 10mS intervals.
- */
-#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
-#define SDC_INIT_RETRY              100
-#endif
-
-/**
- * @brief   Include support for MMC cards.
- * @note    MMC support is not yet implemented so this option must be kept
- *          at @p FALSE.
- */
-#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
-#define SDC_MMC_SUPPORT             FALSE
-#endif
-
-/**
- * @brief   Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- *          routines releasing some extra CPU time for the threads with
- *          lower priority, this may slow down the driver a bit however.
- */
-#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
-#define SDC_NICE_WAITING            TRUE
-#endif
-
-/*===========================================================================*/
-/* SERIAL driver related settings.                                           */
-/*===========================================================================*/
-
-/**
- * @brief   Default bit rate.
- * @details Configuration parameter, this is the baud rate selected for the
- *          default configuration.
- */
-#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
-#define SERIAL_DEFAULT_BITRATE      38400
-#endif
-
-/**
- * @brief   Serial buffers size.
- * @details Configuration parameter, you can change the depth of the queue
- *          buffers depending on the requirements of your application.
- * @note    The default is 64 bytes for both the transmission and receive
- *          buffers.
- */
-#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
-#define SERIAL_BUFFERS_SIZE         16
-#endif
-
-/*===========================================================================*/
-/* SPI driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables synchronous APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
-#define SPI_USE_WAIT                TRUE
-#endif
-
-/**
- * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define SPI_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-#endif /* _HALCONF_H_ */
-
-/** @} */
diff --git a/devices/LightRing/main.cpp b/devices/LightRing/main.cpp
deleted file mode 100644
index 447d1de..0000000
--- a/devices/LightRing/main.cpp
+++ /dev/null
@@ -1,706 +0,0 @@
-#define BL_CALLBACK_TABLE_ADDR  (0x08000000 + 0x01C0)
-#define BL_MAGIC_NUMBER         ((uint32_t)0xFF669900u)
-
-#define SHUTDOWN_NONE             0
-#define SHUTDOWN_TRANSPORTATION   1
-#define SHUTDOWN_DEEPSLEEP        2
-#define SHUTDOWN_HIBERNATE        3
-#define SHUTDOWN_RESTART          4
-#define SHUTDOWN_HANDLE_REQUEST   5
-
-#include <ch.hpp>
-
-#include "global.hpp"
-#include <amiro/util/util.h>
-#include <amiro/Color.h>
-#include <exti.hpp>
-
-#include <chprintf.h>
-#include <shell.h>
-
-using namespace amiro;
-using namespace chibios_rt;
-
-Global global;
-
-struct blVersion_t {
-  const uint8_t identifier;
-  const uint8_t major;
-  const uint8_t minor;
-  const uint8_t patch;
-} __attribute__((packed));
-
-void shellRequestShutdown(BaseSequentialStream* chp, int argc, char *argv[]) {
-
-  chprintf(chp, "shellRequestShutdown\n");
-
-  /* if nor argument was given, print some help text */
-  if (argc == 0 || strcmp(argv[0], "help") == 0) {
-    chprintf(chp, "\tUSAGE:\n");
-    chprintf(chp, "> shutdown <type>\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\ttype\n");
-    chprintf(chp, "The type of shutdown to perform.\n");
-    chprintf(chp, "Choose one of the following types:\n");
-    chprintf(chp, "  transportation - Ultra low-power mode with all wakeups disabled.\n");
-    chprintf(chp, "                   The robot can not be charged.\n");
-    chprintf(chp, "  deepsleep      - Ultra low-power mode with several wakeups enabled.\n");
-    chprintf(chp, "                   The robot can only be charged via the power plug.\n");
-    chprintf(chp, "  hibernate      - Medium low-power mode, but with full charging capabilities.\n");
-    chprintf(chp, "  restart        - Performs a system restart.\n");
-    chprintf(chp, "Alternatively, you can use the shortcuts 't', 'd', 'h', and 'r' respectively.");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  if (strcmp(argv[0],"transportation") == 0 || strcmp(argv[0],"t") == 0) {
-    shutdown_now = SHUTDOWN_TRANSPORTATION;
-    chprintf(chp, "shutdown to transportation mode initialized\n");
-  } else if (strcmp(argv[0],"deepsleep") == 0 || strcmp(argv[0],"d") == 0) {
-    shutdown_now = SHUTDOWN_DEEPSLEEP;
-    chprintf(chp, "shutdown to deepsleep mode initialized\n");
-  } else if (strcmp(argv[0],"hibernate") == 0 || strcmp(argv[0],"h") == 0) {
-    shutdown_now = SHUTDOWN_HIBERNATE;
-    chprintf(chp, "shutdown to hibernate mode initialized\n");
-  } else if (strcmp(argv[0],"restart") == 0 || strcmp(argv[0],"r") == 0) {
-    chprintf(chp, "restart initialized\n");
-    shutdown_now = SHUTDOWN_RESTART;
-  } else {
-    chprintf(chp, "ERROR: unknown argument!\n");
-    shutdown_now = SHUTDOWN_NONE;
-  }
-
-  return;
-}
-
-void testLights() {
-  for (int i = 0; i < (8 * 16 * 2); i++) {
-    Color color;
-    int brightness;
-
-    switch (((i / 16) / 2) % 8) {
-      case 0:
-        color = Color::WHITE;
-        break;
-      case 1:
-        color = Color::RED;
-        break;
-      case 2:
-        color = Color::FUCHSIA;
-        break;
-      case 3:
-        color = Color::BLUE;
-        break;
-      case 4:
-        color = Color::AQUA;
-        break;
-      case 5:
-        color = Color::LIME;
-        break;
-      case 6:
-        color = Color::YELLOW;
-        break;
-      case 7:
-      default:
-        color = Color::BLACK;
-        break;
-    }
-
-    if (i & (1 << 4))
-      brightness = 10 + (i % 16) * 6;
-    else
-      brightness = 10;
-
-    global.robot.setLightBrightness(brightness);
-    global.robot.setLightColor((i / 2) % 8, color);
-
-    BaseThread::sleep(MS2ST(250));
-  }
-}
-
-void testColors() {
-  Color color;
-
-  global.robot.setLightBrightness(50);
-
-  for (int i = 0; i < Color::YELLOWGREEN; i++) {
-    color = Color(static_cast<Color::GlobalColor>(i));
-    for (int j = 0; j < 8; j++)
-      global.robot.setLightColor(j, color);
-
-    BaseThread::sleep(MS2ST(250));
-  }
-
-}
-
-void testFade() {
-  for (int i = 0; i < 255; i += 16) {
-    Color color(255 - i, i, 0);
-    for (int j = 0; j < 8; j++) {
-      global.robot.setLightColor(j, color);
-      BaseThread::sleep(MS2ST(250));
-    }
-  }
-}
-
-void testBrightness() {
-  for (int j = 0; j < 8; j++)
-    global.robot.setLightColor(j, Color::WHITE);
-
-  for (int i = 0; i < 200; i += 5) {
-    int brightness = (i > 100) ? 200 - i : i;
-    global.robot.setLightBrightness(brightness);
-    BaseThread::sleep(MS2ST(100));
-  }
-}
-
-static msg_t shutdownRequest(void *arg) {
-
-  (void) arg;
-  const size_t max_str_len = strlen("shutdown");
-  uint8_t buffer[20];
-  uint8_t num_bytes = 0x00u;
-  uint8_t consume;
-
-  while (true) {
-
-    num_bytes += sdAsynchronousRead(&SD1, &buffer[num_bytes], sizeof(buffer) - num_bytes);
-
-    if (num_bytes) {
-
-      consume = 0x01u;
-
-      if (num_bytes >= strlen("shutdown") && !strncmp((char*) buffer, "shutdown", strlen("shutdown"))) {
-
-        boardRequestShutdown();
-        consume = strlen("shutdown");
-
-      }
-
-      if (consume != 0x01 || num_bytes >= max_str_len) {
-
-        num_bytes -= consume;
-        memcpy(&buffer[0], &buffer[consume], num_bytes);
-
-      }
-
-    }
-
-    BaseThread::sleep(MS2ST(1000));
-
-  }
-
-  return RDY_OK;
-
-}
-
-void systemShutdown() {
-
-  global.userThread.requestTerminate();
-  global.userThread.wait();
-
-  global.robot.setLightBrightness(0);
-  global.robot.terminate();
-
-  global.tlc5947.requestTerminate();
-  global.tlc5947.update();
-  global.tlc5947.wait();
-
-  global.lidar.requestTerminate();
-  global.lidar.wait();
-
-//  boardStandby();
-
-  return;
-}
-
-void shellRequestResetMemory(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestInitMemory\n");
-
-  msg_t res = global.memory.resetMemory();
-  if ( res != global.memory.OK)
-    chprintf(chp, "Memory Init: FAIL\n");
-  else
-    chprintf(chp, "Memory Init: OK\n");
-}
-
-void shellRequestGetBoardId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetBoardId\n");
-
-  uint8_t id = 0xFFu;
-  msg_t res = global.memory.getBoardId(&id);
-  if (res != global.memory.OK)
-    chprintf(chp, "Get Board ID: FAIL\n");
-  else
-    chprintf(chp, "Get Board ID: %u\n", id);
-}
-
-void shellRequestSetBoardId(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetBoardId\n");
-
-  if (argc == 0) {
-    chprintf(chp, "Usage: %s\n","set_board_id <idx>");
-  } else {
-    msg_t res = global.memory.setBoardId(atoi(argv[0]));
-    if (res != global.memory.OK)
-      chprintf(chp, "Set Board ID: FAIL\n");
-    else
-      chprintf(chp, "Set Board ID: OK\n");
-  }
-}
-
-void boardPeripheryCheck(BaseSequentialStream *chp) {
-  msg_t result;
-  chprintf(chp, "\nCHECK: START\n");
-
-  // Check the radio
-  result = global.a2500r24a.getCheck();
-  if (result == global.a2500r24a.CHECK_OK)
-    chprintf(chp, "A2500R24A: OK\n");
-  else
-    chprintf(chp, "A2500R24A: FAIL\n");
-
-  // Check the eeprom
-  result = global.memory.getCheck();
-  if ( result != global.memory.OK)
-    chprintf(chp, "Memory Structure: FAIL\n");
-  else
-    chprintf(chp, "Memory Structure: OK\n");
-
-  // Check the lights
-  chprintf(chp, "LEDs: Test colors\n");
-  testColors();
-  chprintf(chp, "LEDs: Off\n");
-  global.robot.setLightBrightness(0);
-
-  chprintf(chp, "CHECK: FINISH\n");
-}
-
-void shellRequestGetMemoryData(BaseSequentialStream *chp, int argc, char *argv[]) {
-
-  enum Type {HEX, U8, U16, U32, S8, S16, S32};
-
-  chprintf(chp, "shellRequestReadData\n");
-
-  if (argc < 2 || strcmp(argv[0],"help") == 0)
-  {
-    chprintf(chp, "Usage: %s\n","get_memory_data <type> <start> [<count>]");
-    chprintf(chp, "\n");
-    chprintf(chp, "\ttype\n");
-    chprintf(chp, "The data type as which to interpret the data.\n");
-    chprintf(chp, "Choose one of the following types:\n");
-    chprintf(chp, "  hex - one byte as hexadecimal value\n");
-    chprintf(chp, "  u8  - unsigned integer (8 bit)\n");
-    chprintf(chp, "  u16 - unsigned integer (16 bit)\n");
-    chprintf(chp, "  u32 - unsigned integer (32 bit)\n");
-    chprintf(chp, "  s8  - signed integer (8 bit)\n");
-    chprintf(chp, "  s16 - signed integer (16 bit)\n");
-    chprintf(chp, "  s32 - signed integer (32 bit)\n");
-    chprintf(chp, "\tstart\n");
-    chprintf(chp, "The first byte to read from the memory.\n");
-    chprintf(chp, "\tcount [default = 1]\n");
-    chprintf(chp, "The number of elements to read.\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tNOTE\n");
-    chprintf(chp, "Type conversions of this function might fail.\n");
-    chprintf(chp, "If so, use type=hex and convert by hand.\n");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  uint8_t type_size = 0;
-  Type type = HEX;
-  if (strcmp(argv[0],"hex") == 0) {
-    type_size = sizeof(unsigned char);
-    type = HEX;
-  } else if(strcmp(argv[0],"u8") == 0) {
-    type_size = sizeof(uint8_t);
-    type = U8;
-  } else if(strcmp(argv[0],"u16") == 0) {
-    type_size = sizeof(uint16_t);
-    type = U16;
-  } else if(strcmp(argv[0],"u32") == 0) {
-    type_size = sizeof(uint32_t);
-    type = U32;
-  } else if(strcmp(argv[0],"s8") == 0) {
-    type_size = sizeof(int8_t);
-    type = S8;
-  } else if(strcmp(argv[0],"s16") == 0) {
-    type_size = sizeof(int16_t);
-    type = S16;
-  } else if(strcmp(argv[0],"s32") == 0) {
-    type_size = sizeof(int32_t);
-    type = S32;
-  } else {
-    chprintf(chp, "First argument invalid. Use 'get_memory_data help' for help.\n");
-    return;
-  }
-
-  unsigned int start_byte = atoi(argv[1]);
-
-  unsigned int num_elements = 1;
-  if (argc >= 3)
-    num_elements = atoi(argv[2]);
-
-  const size_t eeprom_size = EEPROM::getsize(&global.at24c01);
-  uint8_t buffer[eeprom_size];
-  if (start_byte + (type_size * num_elements) > eeprom_size) {
-    num_elements = (eeprom_size - start_byte) / type_size;
-    chprintf(chp, "Warning: request exceeds eeprom size -> limiting to %u values.\n", num_elements);
-  }
-
-  chFileStreamSeek((BaseFileStream*)&global.at24c01, start_byte);
-
-  // Work around, because stm32f1 cannot read a single byte
-  if (type_size*num_elements < 2)
-    type_size = 2;
-
-  uint32_t bytes_read = chSequentialStreamRead((BaseFileStream*)&global.at24c01, buffer, type_size*num_elements);
-
-  if (bytes_read != type_size*num_elements)
-    chprintf(chp, "Warning: %u of %u requested bytes were read.\n", bytes_read, type_size*num_elements);
-
-  for (unsigned int i = 0; i < num_elements; ++i) {
-    switch (type) {
-      case HEX:
-        chprintf(chp, "%02X ", buffer[i]);
-        break;
-      case U8:
-        chprintf(chp, "%03u ", ((uint8_t*)buffer)[i]);
-        break;
-      case U16:
-        chprintf(chp, "%05u ", ((uint16_t*)buffer)[i]);
-        break;
-      case U32:
-        chprintf(chp, "%010u ", ((uint32_t*)buffer)[i]);
-        break;
-      case S8:
-        chprintf(chp, "%+03d ", ((int8_t*)buffer)[i]);
-        break;
-      case S16:
-        chprintf(chp, "%+05d ", ((int16_t*)buffer)[i]);
-        break;
-      case S32:
-        chprintf(chp, "%+010d ", ((int32_t*)buffer)[i]);
-        break;
-      default:
-        break;
-    }
-  }
-  chprintf(chp, "\n");
-
-  return;
-
-}
-
-void shellRequestCheck(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestCheck\n");
-  boardPeripheryCheck(chp);
-}
-
-void shellRequestGetRobotId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetRobotId\n");
-  chprintf(chp, "Robot ID: %u\n", global.robot.getRobotID());
-  if (global.robot.getRobotID() == 0)
-    chprintf(chp, "Warning: The ID seems to be uninitialized. Is CAN communication working correctly?\n");
-}
-
-void shellRequestGetSystemLoad(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetSystemLoad\n");
-  uint8_t seconds = 1;
-  if (argc >= 1) {
-    seconds = atoi(argv[0]);
-  }
-  chprintf(chp, "measuring CPU load for %u %s...\n", seconds, (seconds>1)? "seconds" : "second");
-
-  const systime_t before = chThdGetTicks(chSysGetIdleThread());
-  BaseThread::sleep(S2ST(seconds));
-  const systime_t after = chThdGetTicks(chSysGetIdleThread());
-  const float usage = 1.0f - (float(after - before) / float(seconds * CH_FREQUENCY));
-
-  chprintf(chp, "CPU load: %3.2f%%\n", usage * 100);
-  const uint32_t memory_total = 0x10000;
-  const uint32_t memory_load = memory_total - chCoreStatus();
-  chprintf(chp, "RAM load: %3.2f%% (%u / %u Byte)\n", float(memory_load)/float(memory_total) * 100, memory_load, memory_total);
-}
-
-void shellSwitchBoardCmd(BaseSequentialStream *chp, int argc, char *argv[]) {
-  if (argc != 1) {
-    chprintf(chp, "Call with decimal numbers: shell_board <idx>\n");
-    return;
-  }
-  uint8_t boardIdx = static_cast<uint8_t>(atoi(argv[0]));
-
-  chprintf(chp, "shellSwitchBoardCmd\n");
-  global.sercanmux1.sendSwitchCmd(boardIdx);
-}
-
-void shellRequestGetBootloaderInfo(BaseSequentialStream* chp, int argc, char *argv[]) {
-  // check the magic number
-  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
-    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
-      break;
-
-    case BL_MAGIC_NUMBER:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
-      break;
-
-    default:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
-      break;
-  }
-
-  return;
-}
-
-static const ShellCommand commands[] = {
-  {"shutdown", shellRequestShutdown},
-  {"check", shellRequestCheck},
-  {"reset_memory", shellRequestResetMemory},
-  {"get_board_id", shellRequestGetBoardId},
-  {"set_board_id", shellRequestSetBoardId},
-  {"get_memory_data", shellRequestGetMemoryData},
-  {"get_robot_id", shellRequestGetRobotId},
-  {"get_system_load", shellRequestGetSystemLoad},
-  {"shell_board", shellSwitchBoardCmd},
-  {"get_bootloader_info", shellRequestGetBootloaderInfo},
-  {NULL, NULL}
-};
-
-static const ShellConfig shell_cfg1 = {
-  (BaseSequentialStream *) &global.sercanmux1,
-  commands
-};
-
-
-
-/*
- * Application entry point.
- */
-int main(void) {
-
-  Thread *shelltp = NULL;
-//  global.shellTermID = CAN::LIGHT_RING_ID;
-  /*
-   * System initializations.
-   * - HAL initialization, this also initializes the configured device drivers
-   *   and performs the board-specific initializations.
-   * - Kernel initialization, the main() function becomes a thread and the
-   *   RTOS is active.
-   */
-  halInit();
-  System::init();
-
-  /*
-   * Activates the serial driver 2 using the driver default configuration.
-   */
-  sdStart(&SD1, &global.sd1_config);
-  sdStart(&SD2, &global.sd2_config);
-
-  chprintf((BaseSequentialStream*) &SD1, "\n");
-  chprintf((BaseSequentialStream*) &SD1, BOARD_NAME " " BOARD_VERSION "\n");
-  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
-    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
-      break;
-
-    case BL_MAGIC_NUMBER:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
-      break;
-
-    default:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
-      break;
-  }
-  chprintf((BaseSequentialStream*) &SD1, "ChibiOS " CH_KERNEL_VERSION "\n");
-  // make sure that the info text is completetly printed
-  BaseThread::sleep(10);
-
-  extStart(&EXTD1, &extcfg);
-
-  boardClearI2CBus(GPIOB_MEM_SCL, GPIOB_MEM_SDA);
-
-  global.HW_I2C2.start(&global.i2c2_config);
-
-  global.memory.init();
-
-  uint8_t i = 0;
-  if (global.memory.getBoardId(&i) == fileSystemIo::FileSystemIoBase::OK) {
-    chprintf((BaseSequentialStream*) &SD1, "Board ID: %u\n", i);
-  } else {
-    chprintf((BaseSequentialStream*) &SD1, "Error reading board ID\n");
-  }
-  chprintf((BaseSequentialStream*) &SD1, "\n");
-
-  global.tlc5947.start(NORMALPRIO + 5);
-  global.tlc5947.enable();
-
-  global.robot.start(HIGHPRIO - 1);
-
-//   lidar.start(NORMALPRIO + 15); UNCOMMENT TO START LIDAR
-
-  global.lidar.start(NORMALPRIO);
-
-  global.userThread.start(NORMALPRIO);
-
-  /* let the SYS_SYNC_N pin go, to signal that the initialization of the module is done */
-  palWritePad(GPIOD, GPIOD_SYS_INT_N, PAL_HIGH);
-
-  /* wait until all modules are done */
-  while (palReadPad(GPIOD, GPIOD_SYS_INT_N) == PAL_LOW) {
-    continue;
-  }
-
-  global.robot.setLightBrightness(10);
-  global.robot.setLightColor(0, Color::RED);
-  global.robot.setLightColor(1, Color::LIME);
-  global.robot.setLightColor(2, Color::BLUE);
-  global.robot.setLightColor(3, Color::WHITE);
-  global.robot.setLightColor(4, Color::RED);
-  global.robot.setLightColor(5, Color::LIME);
-  global.robot.setLightColor(6, Color::BLUE);
-  global.robot.setLightColor(7, Color::WHITE);
-
-//   static uint16_t scannedData[NUMBER_OF_STEPS /*see lidar.h for this variable*/] = {}; UNCOMMENT TO START LIDAR
-  while (true) {
-
-    if (!shelltp)
-      shelltp = shellCreate(&shell_cfg1, THD_WA_SIZE(1024), NORMALPRIO);
-    else if (chThdTerminated(shelltp)) {
-      chThdRelease(shelltp);    /* Recovers memory of the previous shell. */
-      shelltp = NULL;           /* Triggers spawning of a new shell.      */
-    }
-
-//    testLights();
-//    testColors();
-//    testFade();
-//    testBrightness();
-    if (shutdown_now != SHUTDOWN_NONE) {
-      if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) && (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != BL_MAGIC_NUMBER)) {
-        chprintf((BaseSequentialStream*) &SD1, "ERROR: unable to shut down (bootloader deprecated).\n");
-        shutdown_now = SHUTDOWN_NONE;
-      } else {
-        uint32_t blCallbackPtrAddr = BL_CALLBACK_TABLE_ADDR;
-        // handle bootloader version 0.2.x
-        if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
-            (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 2)) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 10 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-        // handle bootloader version 0.3.x
-        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
-                 (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 3)) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 7 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-              blCallbackPtrAddr += 8 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-        // handle bootloader version 1.0.x
-        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) &&
-                 ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major == 1 && ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor == 0) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 7 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-              blCallbackPtrAddr += 8 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-
-        void (*blCallback)(void) = NULL;
-        if (blCallbackPtrAddr > BL_CALLBACK_TABLE_ADDR) {
-          blCallback = (void (*)(void))(*((uint32_t*)blCallbackPtrAddr));
-
-          if (!blCallback) {
-            chprintf((BaseSequentialStream*) &SD1, "ERROR: Requested shutdown not supported.\n");
-            shutdown_now = SHUTDOWN_NONE;
-          } else {
-            chprintf((BaseSequentialStream*)&SD1, "initiating shutdown sequence...\n");
-            palWritePad(GPIOD, GPIOD_SYS_INT_N, PAL_LOW);
-            palWritePad(GPIOC, GPIOC_SYS_PD_N, PAL_LOW);
-
-            chprintf((BaseSequentialStream*)&SD1, "stopping all threads and periphery...");
-            systemShutdown();
-            chprintf((BaseSequentialStream*)&SD1, "\tdone\n");
-            BaseThread::sleep(MS2ST(10)); // sleep to print everything
-
-            blCallback();
-          }
-
-        } else {
-          chprintf((BaseSequentialStream*) &SD1, "ERROR: invalid shutdown requested (%u).\n", shutdown_now);
-          shutdown_now = SHUTDOWN_NONE;
-        }
-      }
-    }
-
-//     // Print LIDAR scan
-//     if (global.lidar.getScan(scannedData)) {
-//       for (uint16_t idx = 0; idx < NUMBER_OF_STEPS; ++idx) {
-//         chprintf((BaseSequentialStream*) &SD1, "%d ", scannedData[idx]);
-//       }
-//       chprintf((BaseSequentialStream*) &SD1, "\n\n");
-//     }
-    BaseThread::sleep(MS2ST(500));
-  }
-
-  return 0;
-}
diff --git a/devices/LightRing/mcuconf.h b/devices/LightRing/mcuconf.h
deleted file mode 100644
index 8e7bdcf..0000000
--- a/devices/LightRing/mcuconf.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#define STM32F103_MCUCONF
-
-/*
- * STM32F103 drivers configuration.
- * The following settings override the default settings present in
- * the various device driver implementation headers.
- * Note that the settings for each driver only have effect if the whole
- * driver is enabled in halconf.h.
- *
- * IRQ priorities:
- * 15...0       Lowest...Highest.
- *
- * DMA priorities:
- * 0...3        Lowest...Highest.
- */
-
-/*
- * HAL driver system settings.
- */
-#define STM32_NO_INIT                       FALSE
-#define STM32_HSI_ENABLED                   TRUE
-#define STM32_LSI_ENABLED                   FALSE
-#define STM32_HSE_ENABLED                   TRUE
-#define STM32_LSE_ENABLED                   FALSE
-#define STM32_SW                            STM32_SW_PLL
-#define STM32_PLLSRC                        STM32_PLLSRC_HSE
-#define STM32_PLLXTPRE                      STM32_PLLXTPRE_DIV1
-#define STM32_PLLMUL_VALUE                  9
-#define STM32_HPRE                          STM32_HPRE_DIV1
-#define STM32_PPRE1                         STM32_PPRE1_DIV2
-#define STM32_PPRE2                         STM32_PPRE2_DIV2
-#define STM32_ADCPRE                        STM32_ADCPRE_DIV4
-#define STM32_USB_CLOCK_REQUIRED            TRUE
-#define STM32_USBPRE                        STM32_USBPRE_DIV1P5
-#define STM32_MCOSEL                        STM32_MCOSEL_NOCLOCK
-#define STM32_RTCSEL                        STM32_RTCSEL_HSEDIV
-#define STM32_PVD_ENABLE                    FALSE
-#define STM32_PLS                           STM32_PLS_LEV0
-
-/*
- * ADC driver system settings.
- */
-#define STM32_ADC_USE_ADC1                  FALSE
-#define STM32_ADC_ADC1_DMA_PRIORITY         2
-#define STM32_ADC_ADC1_IRQ_PRIORITY         6
-
-/*
- * CAN driver system settings.
- */
-#define STM32_CAN_USE_CAN1                  TRUE
-#define STM32_CAN_CAN1_IRQ_PRIORITY         11
-
-/*
- * EXT driver system settings.
- */
-#define STM32_EXT_EXTI0_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI1_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI2_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI3_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI4_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI5_9_IRQ_PRIORITY      6
-#define STM32_EXT_EXTI10_15_IRQ_PRIORITY    6
-#define STM32_EXT_EXTI16_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI17_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI18_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI19_IRQ_PRIORITY       6
-
-/*
- * GPT driver system settings.
- */
-#define STM32_GPT_USE_TIM1                  FALSE
-#define STM32_GPT_USE_TIM2                  FALSE
-#define STM32_GPT_USE_TIM3                  FALSE
-#define STM32_GPT_USE_TIM4                  FALSE
-#define STM32_GPT_USE_TIM5                  FALSE
-#define STM32_GPT_USE_TIM8                  FALSE
-#define STM32_GPT_TIM1_IRQ_PRIORITY         7
-#define STM32_GPT_TIM2_IRQ_PRIORITY         7
-#define STM32_GPT_TIM3_IRQ_PRIORITY         7
-#define STM32_GPT_TIM4_IRQ_PRIORITY         7
-#define STM32_GPT_TIM5_IRQ_PRIORITY         7
-#define STM32_GPT_TIM8_IRQ_PRIORITY         7
-
-/*
- * I2C driver system settings.
- */
-#define STM32_I2C_USE_I2C1                  FALSE
-#define STM32_I2C_USE_I2C2                  TRUE
-#define STM32_I2C_I2C1_IRQ_PRIORITY         5
-#define STM32_I2C_I2C2_IRQ_PRIORITY         5
-#define STM32_I2C_I2C1_DMA_PRIORITY         3
-#define STM32_I2C_I2C2_DMA_PRIORITY         3
-#define STM32_I2C_I2C1_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_I2C2_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_USE_DMA                   FALSE
-
-/*
- * ICU driver system settings.
- */
-#define STM32_ICU_USE_TIM1                  FALSE
-#define STM32_ICU_USE_TIM2                  FALSE
-#define STM32_ICU_USE_TIM3                  FALSE
-#define STM32_ICU_USE_TIM4                  FALSE
-#define STM32_ICU_USE_TIM5                  FALSE
-#define STM32_ICU_USE_TIM8                  FALSE
-#define STM32_ICU_TIM1_IRQ_PRIORITY         7
-#define STM32_ICU_TIM2_IRQ_PRIORITY         7
-#define STM32_ICU_TIM3_IRQ_PRIORITY         7
-#define STM32_ICU_TIM4_IRQ_PRIORITY         7
-#define STM32_ICU_TIM5_IRQ_PRIORITY         7
-#define STM32_ICU_TIM8_IRQ_PRIORITY         7
-
-/*
- * PWM driver system settings.
- */
-#define STM32_PWM_USE_ADVANCED              FALSE
-#define STM32_PWM_USE_TIM1                  FALSE
-#define STM32_PWM_USE_TIM2                  FALSE
-#define STM32_PWM_USE_TIM3                  FALSE
-#define STM32_PWM_USE_TIM4                  FALSE
-#define STM32_PWM_USE_TIM5                  FALSE
-#define STM32_PWM_USE_TIM8                  FALSE
-#define STM32_PWM_TIM1_IRQ_PRIORITY         7
-#define STM32_PWM_TIM2_IRQ_PRIORITY         7
-#define STM32_PWM_TIM3_IRQ_PRIORITY         7
-#define STM32_PWM_TIM4_IRQ_PRIORITY         7
-#define STM32_PWM_TIM5_IRQ_PRIORITY         7
-#define STM32_PWM_TIM8_IRQ_PRIORITY         7
-
-/*
- * RTC driver system settings.
- */
-#define STM32_RTC_IRQ_PRIORITY              15
-
-/*
- * SERIAL driver system settings.
- */
-#define STM32_SERIAL_USE_USART1             TRUE
-#define STM32_SERIAL_USE_USART2             TRUE
-#define STM32_SERIAL_USE_USART3             FALSE
-#define STM32_SERIAL_USE_UART4              FALSE
-#define STM32_SERIAL_USE_UART5              FALSE
-#define STM32_SERIAL_USART1_PRIORITY        12
-#define STM32_SERIAL_USART2_PRIORITY        12
-#define STM32_SERIAL_USART3_PRIORITY        12
-#define STM32_SERIAL_UART4_PRIORITY         12
-#define STM32_SERIAL_UART5_PRIORITY         12
-
-/*
- * SPI driver system settings.
- */
-#define STM32_SPI_USE_SPI1                  TRUE
-#define STM32_SPI_USE_SPI2                  TRUE
-#define STM32_SPI_USE_SPI3                  FALSE
-#define STM32_SPI_SPI1_DMA_PRIORITY         1
-#define STM32_SPI_SPI2_DMA_PRIORITY         1
-#define STM32_SPI_SPI3_DMA_PRIORITY         1
-#define STM32_SPI_SPI1_IRQ_PRIORITY         10
-#define STM32_SPI_SPI2_IRQ_PRIORITY         10
-#define STM32_SPI_SPI3_IRQ_PRIORITY         10
-#define STM32_SPI_DMA_ERROR_HOOK(spip)      chSysHalt()
-
-/*
- * UART driver system settings.
- */
-#define STM32_UART_USE_USART1               FALSE
-#define STM32_UART_USE_USART2               FALSE
-#define STM32_UART_USE_USART3               FALSE
-#define STM32_UART_USART1_IRQ_PRIORITY      12
-#define STM32_UART_USART2_IRQ_PRIORITY      12
-#define STM32_UART_USART3_IRQ_PRIORITY      12
-#define STM32_UART_USART1_DMA_PRIORITY      0
-#define STM32_UART_USART2_DMA_PRIORITY      0
-#define STM32_UART_USART3_DMA_PRIORITY      0
-#define STM32_UART_DMA_ERROR_HOOK(uartp)    chSysHalt()
-
-/*
- * USB driver system settings.
- */
-#define STM32_USB_USE_USB1                  FALSE
-#define STM32_USB_LOW_POWER_ON_SUSPEND      FALSE
-#define STM32_USB_USB1_HP_IRQ_PRIORITY      13
-#define STM32_USB_USB1_LP_IRQ_PRIORITY      14
-
diff --git a/devices/LightRing/userthread.cpp b/devices/LightRing/userthread.cpp
deleted file mode 100644
index b21efac..0000000
--- a/devices/LightRing/userthread.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "userthread.hpp"
-
-#include <global.hpp>
-
-using namespace amiro;
-
-extern Global global;
-
-UserThread::UserThread() :
-  chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>()
-{
-}
-
-UserThread::~UserThread()
-{
-}
-
-msg_t
-UserThread::main()
-{
-  while (!this->shouldTerminate())
-  {
-    /*
-     * INSERT CUSTOM CODE HERE
-     */
-
-    this->sleep(MS2ST(1000));
-  }
-
-  return RDY_OK;
-}
-
diff --git a/devices/LightRing/userthread.hpp b/devices/LightRing/userthread.hpp
deleted file mode 100644
index 80304fb..0000000
--- a/devices/LightRing/userthread.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef AMIRO_USERTHREAD_H_
-#define AMIRO_USERTHREAD_H_
-
-#include <ch.hpp>
-#include <amiroosconf.h>
-
-namespace amiro {
-
-class UserThread : public chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>
-{
-public:
-  explicit UserThread();
-  virtual ~UserThread();
-
-  virtual msg_t main();
-};
-
-} // end of namespace amiro
-
-#endif // AMIRO_USERTHREAD_H_
diff --git a/devices/Makefile b/devices/Makefile
deleted file mode 100644
index 1b0e004..0000000
--- a/devices/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-all: devices
-
-include flash.mk
-
-CLEANTRGS = $(DEVICES:%=clean-%)
-
-.PHONY: $(DEVICES)
-
-devices: $(DEVICES)
-
-$(DEVICES):
-	$(MAKE) -C $@
-
-$(FLASHTRGS):
-	$(MAKE) -C $(firstword $(subst /, ,$@))
-
-clean: $(CLEANTRGS)
-$(CLEANTRGS):
-	$(MAKE) -C $(@:clean-%=%) clean
diff --git a/devices/PowerManagement/Makefile b/devices/PowerManagement/Makefile
deleted file mode 100644
index 536824d..0000000
--- a/devices/PowerManagement/Makefile
+++ /dev/null
@@ -1,270 +0,0 @@
-##############################################################################
-# Build global options
-# NOTE: Can be overridden externally.
-#
-
-# Compiler options here.
-ifeq ($(USE_OPT),)
-  USE_OPT = -O2 -fomit-frame-pointer -falign-functions=16 -DCHPRINTF_USE_FLOAT=1 -fstack-usage -DSERIAL_BUFFERS_SIZE=64
-endif
-
-# C specific options here (added to USE_OPT).
-ifeq ($(USE_COPT),)
-  USE_COPT =
-endif
-
-# C++ specific options here (added to USE_OPT).
-ifeq ($(USE_CPPOPT),)
-  USE_CPPOPT = -fno-rtti -fno-exceptions -std=c++11 -U__STRICT_ANSI__
-endif
-
-# Enable this if you want the linker to remove unused code and data
-ifeq ($(USE_LINK_GC),)
-  USE_LINK_GC = yes
-endif
-
-# Linker extra options here.
-ifeq ($(USE_LDOPT),)
-  USE_LDOPT =
-endif
-
-# Enable this if you want link time optimizations (LTO)
-ifeq ($(USE_LTO),)
-  USE_LTO = no
-endif
-
-# If enabled, this option allows to compile the application in THUMB mode.
-ifeq ($(USE_THUMB),)
-  USE_THUMB = yes
-endif
-
-# Enable this if you want to see the full log while compiling.
-ifeq ($(USE_VERBOSE_COMPILE),)
-  USE_VERBOSE_COMPILE = no
-endif
-
-#
-# Build global options
-##############################################################################
-
-##############################################################################
-# Architecture or project specific options
-#
-
-# Enables the use of FPU on Cortex-M4.
-# Possible selections are:
-#   no     - no FPU is used (propably equals 'soft')
-#   soft   - does not use the FPU, thus all floating point operations are emulated
-#   softfp - uses the FPU, but uses the integer registers only
-#   hard   - uses the FPU and passes data via the FPU registers
-ifeq ($(USE_FPU),)
-  USE_FPU = hard
-endif
-
-# Enable this if you really want to use the STM FWLib.
-ifeq ($(USE_FWLIB),)
-  USE_FWLIB = no
-endif
-
-#
-# Architecture or project specific options
-##############################################################################
-
-##############################################################################
-# Project, sources and paths
-#
-
-# Define project name here
-PROJECT = PowerManagement
-
-# Imported source files and paths
-CHIBIOS = ../../../ChibiOS
-AMIRO = ../..
-include $(AMIRO)/boards/PowerManagement/board.mk
-include $(CHIBIOS)/os/hal/platforms/STM32F4xx/platform.mk
-include $(CHIBIOS)/os/hal/hal.mk
-include $(CHIBIOS)/os/ports/GCC/ARMCMx/STM32F4xx/port.mk
-include $(CHIBIOS)/os/kernel/kernel.mk
-include $(CHIBIOS)/os/various/cpp_wrappers/kernel.mk
-
-# Define linker script file here
-LDSCRIPT= $(BOARDLD)/STM32F405xG.ld
-
-# C sources that can be compiled in ARM or THUMB mode depending on the global
-# setting.
-CSRC = $(PORTSRC) \
-       $(KERNSRC) \
-       $(HALSRC) \
-       $(PLATFORMSRC) \
-       $(BOARDSRC) \
-       $(CHIBIOS)/os/various/evtimer.c \
-       $(CHIBIOS)/os/various/syscalls.c \
-       $(CHIBIOS)/os/various/chprintf.c \
-       $(CHIBIOS)/os/various/shell.c \
-       $(CHIBIOS)/os/various/memstreams.c \
-       $(AMIRO)/stubs.c \
-       $(AMIRO)/components/Debug.c
-
-# C++ sources that can be compiled in ARM or THUMB mode depending on the global
-# setting.
-CPPSRC = $(CHCPPSRC) \
-         $(AMIRO)/components/Color.cpp \
-         $(AMIRO)/components/ControllerAreaNetworkRx.cpp \
-         $(AMIRO)/components/ControllerAreaNetworkTx.cpp \
-         $(AMIRO)/components/bus/i2c/HWI2CDriver.cpp \
-         $(AMIRO)/components/bus/i2c/I2CMultiplexer.cpp \
-         $(AMIRO)/components/bus/i2c/VI2CDriver.cpp \
-         $(AMIRO)/components/proximity/vcnl4020.cpp \
-         $(AMIRO)/components/eeprom/eeprom.cpp \
-         $(AMIRO)/components/eeprom/at24.cpp \
-         $(AMIRO)/components/FileSystemInputOutput/FileSystemInputOutputBase.cpp \
-         $(AMIRO)/components/FileSystemInputOutput/FSIOPowerManagement.cpp \
-         $(AMIRO)/components/input/mpr121.cpp \
-         $(AMIRO)/components/power/adconverter.cpp \
-         $(AMIRO)/components/power/ina219.cpp \
-         $(AMIRO)/components/power/bq27500.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth-descriptor.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth-transport.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth-connector.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth-wiimote.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth-serial.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth-iwrap.cpp \
-         $(AMIRO)/components/bluetooth/bluetooth.cpp \
-         $(AMIRO)/components/serial_reset/iwrap_can_mux.cpp \
-         $(AMIRO)/components/serial_reset/serial_can_mux.cpp \
-         PowerManagement.cpp \
-         userthread.cpp \
-         main.cpp \
-         exti.cpp
-
-# C sources to be compiled in ARM mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-ACSRC =
-
-# C++ sources to be compiled in ARM mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-ACPPSRC =
-
-# C sources to be compiled in THUMB mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-TCSRC =
-
-# C sources to be compiled in THUMB mode regardless of the global setting.
-# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
-#       option that results in lower performance and larger code size.
-TCPPSRC =
-
-# List ASM source files here
-ASMSRC = $(PORTASM)
-
-INCDIR = $(PORTINC) $(KERNINC) $(TESTINC) \
-         $(HALINC) $(PLATFORMINC) $(BOARDINC) \
-         $(CHCPPINC) \
-         $(CHIBIOS)/os/various \
-         $(AMIRO) \
-         $(AMIRO)/include
-
-#
-# Project, sources and paths
-##############################################################################
-
-##############################################################################
-# Compiler settings
-#
-
-MCU  = cortex-m4
-
-#TRGT = arm-elf-
-TRGT = arm-none-eabi-
-CC   = $(TRGT)gcc
-CPPC = $(TRGT)g++
-# Enable loading with g++ only if you need C++ runtime support.
-# NOTE: You can use C++ even without C++ support if you are careful. C++
-#       runtime support makes code size explode.
-#LD   = $(TRGT)gcc
-LD   = $(TRGT)g++
-CP   = $(TRGT)objcopy
-AS   = $(TRGT)gcc -x assembler-with-cpp
-OD   = $(TRGT)objdump
-SZ   = $(TRGT)size
-HEX  = $(CP) -O ihex
-BIN  = $(CP) -O binary
-SREC = $(CP) -O srec --srec-len=248
-
-# ARM-specific options here
-AOPT =
-
-# THUMB-specific options here
-TOPT = -mthumb -DTHUMB
-
-# Define C warning options here
-CWARN = -Wall -Wextra -Wstrict-prototypes
-
-# Define C++ warning options here
-CPPWARN = -Wall -Wextra
-
-#
-# Compiler settings
-##############################################################################
-
-##############################################################################
-# Start of default section
-#
-
-# List all default C defines here, like -D_DEBUG=1
-DDEFS =
-
-# List all default ASM defines here, like -D_DEBUG=1
-DADEFS =
-
-# List all default directories to look for include files here
-DINCDIR =
-
-# List the default directory to look for the libraries here
-DLIBDIR =
-
-# List all default libraries here
-DLIBS =
-
-#
-# End of default section
-##############################################################################
-
-##############################################################################
-# Start of user section
-#
-
-# List all user C define here, like -D_DEBUG=1
-UDEFS =
-
-# Define ASM defines here
-UADEFS =
-
-# List all user directories here
-UINCDIR =
-
-# List the user directory to look for the libraries here
-ULIBDIR =
-
-# List all user libraries here
-ULIBS =
-
-#
-# End of user defines
-##############################################################################
-
-ifeq ($(USE_FWLIB),yes)
-  include $(CHIBIOS)/ext/stm32lib/stm32lib.mk
-  CSRC += $(STM32SRC)
-  INCDIR += $(STM32INC)
-  USE_OPT += -DUSE_STDPERIPH_DRIVER
-endif
-
-RULESPATH = $(CHIBIOS)/os/ports/GCC/ARMCMx
-include $(RULESPATH)/rules.mk
-
-include $(AMIRO)/ports/rules.mk
-include $(AMIRO)/devices/flash.mk
diff --git a/devices/PowerManagement/PowerManagement.cpp b/devices/PowerManagement/PowerManagement.cpp
deleted file mode 100644
index 92143fd..0000000
--- a/devices/PowerManagement/PowerManagement.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-#include "ch.hpp"
-#include "hal.h"
-#include "PowerManagement.h"
-
-#include <amiro/proximity/vcnl4020.hpp>
-#include <global.hpp>
-
-#include <algorithm>
-#include <chprintf.h>
-
-using namespace chibios_rt;
-using namespace amiro;
-
-extern Global global;
-
-PowerManagement::PowerManagement(CANDriver *can)
-    : ControllerAreaNetworkTx(can, CAN::POWER_MANAGEMENT_ID),
-      ControllerAreaNetworkRx(can, CAN::POWER_MANAGEMENT_ID),
-      bc_counter(0)
-{
-  this->powerStatus.charging_flags.value = 0;
-}
-
-msg_t PowerManagement::receiveMessage(CANRxFrame *frame) {
-  int deviceId = this->decodeDeviceId(frame);
-  switch (deviceId) {
-
-    case CAN::SHELL_REPLY_ID(CAN::POWER_MANAGEMENT_ID):
-      if (frame->DLC > 0) {
-        sdWrite(&SD1, frame->data8, frame->DLC);
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::SHELL_QUERY_ID(CAN::POWER_MANAGEMENT_ID):
-      if (frame->DLC != 0) {
-        global.sercanmux1.convCan2Serial(frame->data8, frame->DLC);
-        return RDY_OK;
-      } else {
-        global.sercanmux1.rcvSwitchCmd(this->decodeBoardId(frame));
-        return RDY_OK;
-      }
-      break;
-
-    case CAN::CALIBRATE_PROXIMITY_RING:
-      // Dont care about the payload but start the calibration
-      // TODO Care about the payload. Differ between:
-      // 1: Do fresh calibration (Save values to memory and to temporary values)
-      // 2: Remove temporary Calibration and get uncalibrated values
-      // 3: Load calibration from memory
-      this->calibrate();
-      break;
-
-    case CAN::ROBOT_ID:
-      if (frame->DLC == 1) {
-        this->robotId = frame->data8[0];
-        return RDY_OK;
-      }
-      break;
-
-    default:
-      break;
-  }
-
-  return -1;
-}
-
-msg_t PowerManagement::updateSensorVal() {
-
-  // update charger status
-  this->powerStatus.charging_flags.content.powermanagement_plugged_in = global.ltc4412.isPluggedIn();
-
-  // update fuel gauges values
-  const BQ27500::Driver::UpdateData* power[2] {
-    &global.bq27500[constants::PowerManagement::BAT_A].getStatus(),
-    &global.bq27500[constants::PowerManagement::BAT_B].getStatus()
-  };
-  this->powerStatus.charging_flags.content.powermanagement_charging = (this->powerStatus.charging_flags.content.powermanagement_plugged_in &&
-                                                                       this->powerStatus.charging_flags.content.vsys_higher_than_9V &&
-                                                                       power[0]->minutes_to_empty == uint16_t(~0) &&
-                                                                       power[1]->minutes_to_empty == uint16_t(~0))?
-                                                                       true : false;
-  this->powerStatus.charging_flags.content.diwheeldrive_charging = (this->powerStatus.charging_flags.content.diwheeldrive_enable_power_path &&
-                                                                    this->powerStatus.charging_flags.content.vsys_higher_than_9V &&
-                                                                    power[0]->minutes_to_empty == uint16_t(~0) &&
-                                                                    power[1]->minutes_to_empty == uint16_t(~0))?
-                                                                    true : false;
-  this->powerStatus.state_of_charge = (power[0]->state_of_charge + power[1]->state_of_charge) / 2;
-  if (this->powerStatus.charging_flags.content.powermanagement_charging || this->powerStatus.charging_flags.content.diwheeldrive_charging) {
-    /*
-     * Assumption:
-     * When charging there is enough power available to charge both batteries at full rate simultaneously.
-     * Thus, the second battery will not charge faster when the first battery is fully charged.
-     */
-    this->powerStatus.minutes_remaining = std::max(power[0]->minutes_to_full, power[1]->minutes_to_full);
-  } else {
-    /*
-     * Computation of the remaining discharging time:
-     * Take the time until the first of the two batteries is empty and add the remaining time of the second battery but half.
-     *        time = min(a,b) + (max(a,b) - min(a,b))/2
-     * <=>  2*time = 2*min(a,b) + max(a,b) - min(a,b)
-     * <=>  2*time = min(a,b) + max(a,b)
-     * <=>  2*time = a + b
-     * <=>    time = (a + b)/2
-     */
-    this->powerStatus.minutes_remaining = (power[0]->minutes_to_empty + power[1]->minutes_to_empty) / 2;
-  }
-  this->powerStatus.power_consumption = (power[0]->average_power_mW + power[1]->average_power_mW) / 2;
-
-  // update infrared sensor value
-  // Note: The CANRx Value will never be updated in this thread
-  for (int idx = 0; idx < 8; idx++)
-    this->proximityRingValue[idx] = global.vcnl4020[idx].getProximityScaledWoOffset();
-
-  return 0;
-}
-
-void PowerManagement::periodicBroadcast() {
-  CANTxFrame frame;
-  if (this->bc_counter % 10 == 0) {
-    frame.SID = 0;
-    this->encodeDeviceId(&frame, CAN::POWER_STATUS_ID);
-    frame.data8[0] = this->powerStatus.charging_flags.value;
-    frame.data8[1] = this->powerStatus.state_of_charge;
-    frame.data16[1] = this->powerStatus.minutes_remaining;
-    frame.data16[2] = this->powerStatus.power_consumption;
-    frame.DLC = 6;
-    this->transmitMessage(&frame);
-  }
-  for (int i = 0; i < 8; i++) {
-    frame.SID = 0;
-    this->encodeDeviceId(&frame, CAN::PROXIMITY_RING_ID(i));
-    frame.data16[0] = this->proximityRingValue[i];
-    frame.DLC = 2;
-    this->transmitMessage(&frame);
-    BaseThread::sleep(US2ST(10)); // Use to sleep for 10 CAN cycle (@1Mbit), otherwise the cognition-board might not receive all messagee
-  }
-  ++this->bc_counter;
-}
-
-void PowerManagement::calibrate() {
-  // Stop sending and receiving of values to indicate the calibration phase
-//   eventTimerEvtSource->unregister(&this->eventTimerEvtListener);
-//   rxFullCanEvtSource->unregister(&this->rxFullCanEvtListener);
-
-  this->calibrateProximityRingValues();
-
-  // Start sending and receving of values
-//   eventTimerEvtSource->registerOne(&this->eventTimerEvtListener, CAN::PERIODIC_TIMER_ID);
-//   rxFullCanEvtSource->registerOne(&this->rxFullCanEvtListener, CAN::RECEIVED_ID);
-}
-
-void PowerManagement::calibrateProximityRingValues() {
-
-  uint16_t buffer;
-  for (uint8_t idx = 0; idx < 8; ++idx) {
-    global.vcnl4020[idx].calibrate();
-    buffer = global.vcnl4020[idx].getProximityOffset();
-    global.memory.setVcnl4020Offset(buffer,idx);
-  }
-}
-
-ThreadReference PowerManagement::start(tprio_t PRIO) {
-  this->ControllerAreaNetworkRx::start(PRIO + 1);
-  this->ControllerAreaNetworkTx::start(PRIO);
-  return NULL;
-}
-
-types::power_status&
-PowerManagement::getPowerStatus()
-{
-  return this->powerStatus;
-}
-
-msg_t PowerManagement::terminate(void) {
-  msg_t ret = RDY_OK;
-
-  this->ControllerAreaNetworkTx::requestTerminate();
-  ret |= this->ControllerAreaNetworkTx::wait();
-  this->ControllerAreaNetworkRx::requestTerminate();
-  ret |= this->ControllerAreaNetworkRx::wait();
-
-  return ret;
-}
diff --git a/devices/PowerManagement/PowerManagement.h b/devices/PowerManagement/PowerManagement.h
deleted file mode 100644
index 9927167..0000000
--- a/devices/PowerManagement/PowerManagement.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef AMIRO_POWER_MANAGEMENT_H_
-#define AMIRO_POWER_MANAGEMENT_H_
-
-#include <amiro/ControllerAreaNetworkRx.h>
-#include <amiro/ControllerAreaNetworkTx.h>
-#include <amiro/proximity/vcnl4020.hpp>
-#include <amiro/FileSystemInputOutput/FSIOPowerManagement.hpp>
-#include <amiro/power/bq27500.hpp>
-#include <amiro/power/ltc4412.hpp>
-
-namespace amiro {
-
-  class VCNL4020;
-
-  class PowerManagement : public ControllerAreaNetworkTx, public ControllerAreaNetworkRx  {
-  public:
-    PowerManagement(CANDriver *can);
-    virtual void  calibrate();
-
-    /** \brief Handle the termination of ControllerAreaNetworkTx and ControllerAreaNetworkRx threads
-     *         This includes waiting until the threads have terminated, thus this function might block a relatively long time.
-     */
-    msg_t terminate(void);
-
-    /** \brief Handle the start of ControllerAreaNetworkTx and ControllerAreaNetworkRx threads */
-    ThreadReference start(tprio_t PRIO);
-
-    types::power_status& getPowerStatus();
-
-  protected:
-    virtual msg_t receiveMessage(CANRxFrame *frame);
-    virtual msg_t updateSensorVal();
-    virtual void periodicBroadcast();
-
-    void  calibrateProximityRingValues();
-
-  private:
-    uint32_t bc_counter;
-
-  };
-
-}
-
-#endif /* AMIRO_POWER_MANAGEMENT_H_ */
diff --git a/devices/PowerManagement/amiroosconf.h b/devices/PowerManagement/amiroosconf.h
deleted file mode 100644
index 4bb1b27..0000000
--- a/devices/PowerManagement/amiroosconf.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef AMIRO_AMIROOSCONF_H_
-#define AMIRO_AMIROOSCONF_H_
-
-/**
- * @brief Stack size of the user thread object
- */
-#if !defined(USER_THREAD_STACK_SIZE) || defined(__DOXYGEN__)
-#define USER_THREAD_STACK_SIZE         1024
-#endif
-
-/**
- * @brief Flag to enable/disable als amiroDbgXXX macros
- */
-#if !defined(AMIRO_DBG) || defined(__DOXYGEN__)
-#define AMIRO_DBG                      TRUE
-#endif
-
-#endif // AMIRO_AMIROOSCONF_H_
-
diff --git a/devices/PowerManagement/chconf.h b/devices/PowerManagement/chconf.h
deleted file mode 100644
index 380a917..0000000
--- a/devices/PowerManagement/chconf.h
+++ /dev/null
@@ -1,518 +0,0 @@
-/**
- * @file    devices/PowerManagement/chconf.h
- * @brief   Configuration file.
- *
- * @addtogroup config
- * @details Kernel related settings and hooks.
- * @{
- */
-
-#ifndef _CHCONF_H_
-#define _CHCONF_H_
-
-/*===========================================================================*/
-/**
- * @name Kernel parameters and options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   System tick frequency.
- * @details Frequency of the system timer that drives the system ticks. This
- *          setting also defines the system tick time unit.
- */
-#if !defined(CH_FREQUENCY) || defined(__DOXYGEN__)
-#define CH_FREQUENCY                    1000
-#endif
-
-/**
- * @brief   Round robin interval.
- * @details This constant is the number of system ticks allowed for the
- *          threads before preemption occurs. Setting this value to zero
- *          disables the preemption for threads with equal priority and the
- *          round robin becomes cooperative. Note that higher priority
- *          threads can still preempt, the kernel is always preemptive.
- *
- * @note    Disabling the round robin preemption makes the kernel more compact
- *          and generally faster.
- */
-#if !defined(CH_TIME_QUANTUM) || defined(__DOXYGEN__)
-#define CH_TIME_QUANTUM                 20
-#endif
-
-/**
- * @brief   Managed RAM size.
- * @details Size of the RAM area to be managed by the OS. If set to zero
- *          then the whole available RAM is used. The core memory is made
- *          available to the heap allocator and/or can be used directly through
- *          the simplified core memory allocator.
- *
- * @note    In order to let the OS manage the whole RAM the linker script must
- *          provide the @p __heap_base__ and @p __heap_end__ symbols.
- * @note    Requires @p CH_USE_MEMCORE.
- */
-#if !defined(CH_MEMCORE_SIZE) || defined(__DOXYGEN__)
-#define CH_MEMCORE_SIZE                 0
-#endif
-
-/**
- * @brief   Idle thread automatic spawn suppression.
- * @details When this option is activated the function @p chSysInit()
- *          does not spawn the idle thread automatically. The application has
- *          then the responsibility to do one of the following:
- *          - Spawn a custom idle thread at priority @p IDLEPRIO.
- *          - Change the main() thread priority to @p IDLEPRIO then enter
- *            an endless loop. In this scenario the @p main() thread acts as
- *            the idle thread.
- *          .
- * @note    Unless an idle thread is spawned the @p main() thread must not
- *          enter a sleep state.
- */
-#if !defined(CH_NO_IDLE_THREAD) || defined(__DOXYGEN__)
-#define CH_NO_IDLE_THREAD               FALSE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Performance options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   OS optimization.
- * @details If enabled then time efficient rather than space efficient code
- *          is used when two possible implementations exist.
- *
- * @note    This is not related to the compiler optimization options.
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_OPTIMIZE_SPEED) || defined(__DOXYGEN__)
-#define CH_OPTIMIZE_SPEED               TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Subsystem options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Threads registry APIs.
- * @details If enabled then the registry APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_REGISTRY) || defined(__DOXYGEN__)
-#define CH_USE_REGISTRY                 TRUE
-#endif
-
-/**
- * @brief   Threads synchronization APIs.
- * @details If enabled then the @p chThdWait() function is included in
- *          the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_WAITEXIT) || defined(__DOXYGEN__)
-#define CH_USE_WAITEXIT                 TRUE
-#endif
-
-/**
- * @brief   Semaphores APIs.
- * @details If enabled then the Semaphores APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_SEMAPHORES) || defined(__DOXYGEN__)
-#define CH_USE_SEMAPHORES               TRUE
-#endif
-
-/**
- * @brief   Semaphores queuing mode.
- * @details If enabled then the threads are enqueued on semaphores by
- *          priority rather than in FIFO order.
- *
- * @note    The default is @p FALSE. Enable this if you have special requirements.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_SEMAPHORES_PRIORITY) || defined(__DOXYGEN__)
-#define CH_USE_SEMAPHORES_PRIORITY      FALSE
-#endif
-
-/**
- * @brief   Atomic semaphore API.
- * @details If enabled then the semaphores the @p chSemSignalWait() API
- *          is included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_SEMSW) || defined(__DOXYGEN__)
-#define CH_USE_SEMSW                    TRUE
-#endif
-
-/**
- * @brief   Mutexes APIs.
- * @details If enabled then the mutexes APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MUTEXES) || defined(__DOXYGEN__)
-#define CH_USE_MUTEXES                  TRUE
-#endif
-
-/**
- * @brief   Conditional Variables APIs.
- * @details If enabled then the conditional variables APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_MUTEXES.
- */
-#if !defined(CH_USE_CONDVARS) || defined(__DOXYGEN__)
-#define CH_USE_CONDVARS                 TRUE
-#endif
-
-/**
- * @brief   Conditional Variables APIs with timeout.
- * @details If enabled then the conditional variables APIs with timeout
- *          specification are included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_CONDVARS.
- */
-#if !defined(CH_USE_CONDVARS_TIMEOUT) || defined(__DOXYGEN__)
-#define CH_USE_CONDVARS_TIMEOUT         TRUE
-#endif
-
-/**
- * @brief   Events Flags APIs.
- * @details If enabled then the event flags APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_EVENTS) || defined(__DOXYGEN__)
-#define CH_USE_EVENTS                   TRUE
-#endif
-
-/**
- * @brief   Events Flags APIs with timeout.
- * @details If enabled then the events APIs with timeout specification
- *          are included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_EVENTS.
- */
-#if !defined(CH_USE_EVENTS_TIMEOUT) || defined(__DOXYGEN__)
-#define CH_USE_EVENTS_TIMEOUT           TRUE
-#endif
-
-/**
- * @brief   Synchronous Messages APIs.
- * @details If enabled then the synchronous messages APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MESSAGES) || defined(__DOXYGEN__)
-#define CH_USE_MESSAGES                 TRUE
-#endif
-
-/**
- * @brief   Synchronous Messages queuing mode.
- * @details If enabled then messages are served by priority rather than in
- *          FIFO order.
- *
- * @note    The default is @p FALSE. Enable this if you have special requirements.
- * @note    Requires @p CH_USE_MESSAGES.
- */
-#if !defined(CH_USE_MESSAGES_PRIORITY) || defined(__DOXYGEN__)
-#define CH_USE_MESSAGES_PRIORITY        FALSE
-#endif
-
-/**
- * @brief   Mailboxes APIs.
- * @details If enabled then the asynchronous messages (mailboxes) APIs are
- *          included in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_SEMAPHORES.
- */
-#if !defined(CH_USE_MAILBOXES) || defined(__DOXYGEN__)
-#define CH_USE_MAILBOXES                TRUE
-#endif
-
-/**
- * @brief   I/O Queues APIs.
- * @details If enabled then the I/O queues APIs are included in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_QUEUES) || defined(__DOXYGEN__)
-#define CH_USE_QUEUES                   TRUE
-#endif
-
-/**
- * @brief   Core Memory Manager APIs.
- * @details If enabled then the core memory manager APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MEMCORE) || defined(__DOXYGEN__)
-#define CH_USE_MEMCORE                  TRUE
-#endif
-
-/**
- * @brief   Heap Allocator APIs.
- * @details If enabled then the memory heap allocator APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_MEMCORE and either @p CH_USE_MUTEXES or
- *          @p CH_USE_SEMAPHORES.
- * @note    Mutexes are recommended.
- */
-#if !defined(CH_USE_HEAP) || defined(__DOXYGEN__)
-#define CH_USE_HEAP                     TRUE
-#endif
-
-/**
- * @brief   C-runtime allocator.
- * @details If enabled the the heap allocator APIs just wrap the C-runtime
- *          @p malloc() and @p free() functions.
- *
- * @note    The default is @p FALSE.
- * @note    Requires @p CH_USE_HEAP.
- * @note    The C-runtime may or may not require @p CH_USE_MEMCORE, see the
- *          appropriate documentation.
- */
-#if !defined(CH_USE_MALLOC_HEAP) || defined(__DOXYGEN__)
-#define CH_USE_MALLOC_HEAP              FALSE
-#endif
-
-/**
- * @brief   Memory Pools Allocator APIs.
- * @details If enabled then the memory pools allocator APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- */
-#if !defined(CH_USE_MEMPOOLS) || defined(__DOXYGEN__)
-#define CH_USE_MEMPOOLS                 TRUE
-#endif
-
-/**
- * @brief   Dynamic Threads APIs.
- * @details If enabled then the dynamic threads creation APIs are included
- *          in the kernel.
- *
- * @note    The default is @p TRUE.
- * @note    Requires @p CH_USE_WAITEXIT.
- * @note    Requires @p CH_USE_HEAP and/or @p CH_USE_MEMPOOLS.
- */
-#if !defined(CH_USE_DYNAMIC) || defined(__DOXYGEN__)
-#define CH_USE_DYNAMIC                  TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Debug options
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Debug option, system state check.
- * @details If enabled the correct call protocol for system APIs is checked
- *          at runtime.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_SYSTEM_STATE_CHECK) || defined(__DOXYGEN__)
-#define CH_DBG_SYSTEM_STATE_CHECK       TRUE
-#endif
-
-/**
- * @brief   Debug option, parameters checks.
- * @details If enabled then the checks on the API functions input
- *          parameters are activated.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_CHECKS            TRUE
-#endif
-
-/**
- * @brief   Debug option, consistency checks.
- * @details If enabled then all the assertions in the kernel code are
- *          activated. This includes consistency checks inside the kernel,
- *          runtime anomalies and port-defined checks.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_ASSERTS           TRUE
-#endif
-
-/**
- * @brief   Debug option, trace buffer.
- * @details If enabled then the context switch circular trace buffer is
- *          activated.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_ENABLE_TRACE) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_TRACE             TRUE
-#endif
-
-/**
- * @brief   Debug option, stack checks.
- * @details If enabled then a runtime stack check is performed.
- *
- * @note    The default is @p FALSE.
- * @note    The stack check is performed in a architecture/port dependent way.
- *          It may not be implemented or some ports.
- * @note    The default failure mode is to halt the system with the global
- *          @p panic_msg variable set to @p NULL.
- */
-#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__)
-#define CH_DBG_ENABLE_STACK_CHECK       TRUE
-#endif
-
-/**
- * @brief   Debug option, stacks initialization.
- * @details If enabled then the threads working area is filled with a byte
- *          value when a thread is created. This can be useful for the
- *          runtime measurement of the used stack.
- *
- * @note    The default is @p FALSE.
- */
-#if !defined(CH_DBG_FILL_THREADS) || defined(__DOXYGEN__)
-#define CH_DBG_FILL_THREADS             FALSE
-#endif
-
-/**
- * @brief   Debug option, threads profiling.
- * @details If enabled then a field is added to the @p Thread structure that
- *          counts the system ticks occurred while executing the thread.
- *
- * @note    The default is @p TRUE.
- * @note    This debug option is defaulted to TRUE because it is required by
- *          some test cases into the test suite.
- */
-#if !defined(CH_DBG_THREADS_PROFILING) || defined(__DOXYGEN__)
-#define CH_DBG_THREADS_PROFILING        TRUE
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/**
- * @name Kernel hooks
- * @{
- */
-/*===========================================================================*/
-
-/**
- * @brief   Threads descriptor structure extension.
- * @details User fields added to the end of the @p Thread structure.
- */
-#if !defined(THREAD_EXT_FIELDS) || defined(__DOXYGEN__)
-#define THREAD_EXT_FIELDS                                                   \
-  /* Add threads custom fields here.*/
-#endif
-
-/**
- * @brief   Threads initialization hook.
- * @details User initialization code added to the @p chThdInit() API.
- *
- * @note    It is invoked from within @p chThdInit() and implicitly from all
- *          the threads creation APIs.
- */
-#if !defined(THREAD_EXT_INIT_HOOK) || defined(__DOXYGEN__)
-#define THREAD_EXT_INIT_HOOK(tp) {                                          \
-  /* Add threads initialization code here.*/                                \
-}
-#endif
-
-/**
- * @brief   Threads finalization hook.
- * @details User finalization code added to the @p chThdExit() API.
- *
- * @note    It is inserted into lock zone.
- * @note    It is also invoked when the threads simply return in order to
- *          terminate.
- */
-#if !defined(THREAD_EXT_EXIT_HOOK) || defined(__DOXYGEN__)
-#define THREAD_EXT_EXIT_HOOK(tp) {                                          \
-  /* Add threads finalization code here.*/                                  \
-}
-#endif
-
-/**
- * @brief   Context switch hook.
- * @details This hook is invoked just before switching between threads.
- */
-#if !defined(THREAD_CONTEXT_SWITCH_HOOK) || defined(__DOXYGEN__)
-#define THREAD_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
-  /* Context switch code here.*/                                            \
-}
-#endif
-
-/**
- * @brief   Idle Loop hook.
- * @details This hook is continuously invoked by the idle thread loop.
- */
-#if !defined(IDLE_LOOP_HOOK) || defined(__DOXYGEN__)
-#define IDLE_LOOP_HOOK() {                                                  \
-  /* Idle loop code here.*/                                                 \
-}
-#endif
-
-/**
- * @brief   System tick event hook.
- * @details This hook is invoked in the system tick handler immediately
- *          after processing the virtual timers queue.
- */
-#if !defined(SYSTEM_TICK_EVENT_HOOK) || defined(__DOXYGEN__)
-#define SYSTEM_TICK_EVENT_HOOK() {                                          \
-  /* System tick event code here.*/                                         \
-}
-#endif
-
-/**
- * @brief   System halt hook.
- * @details This hook is invoked in case to a system halting error before
- *          the system is halted.
- */
-#if !defined(SYSTEM_HALT_HOOK) || defined(__DOXYGEN__)
-void haltErrorCode(void);
-#define SYSTEM_HALT_HOOK() {                                                \
-  /* System halt code here.*/                                               \
-  haltErrorCode();                                                          \
-}
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/* Port-specific settings (override port settings defaulted in chcore.h).    */
-/*===========================================================================*/
-
-/* NVIC VTOR initialization (only offset!) */
-#define CORTEX_VTOR_INIT 0x00008000
-
-#endif  /* _CHCONF_H_ */
-
-/** @} */
diff --git a/devices/PowerManagement/exti.cpp b/devices/PowerManagement/exti.cpp
deleted file mode 100644
index 2315337..0000000
--- a/devices/PowerManagement/exti.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-#include <ch.hpp>
-#include <hal.h>
-
-#include <board.h>
-
-#include "exti.hpp"
-
-volatile uint32_t shutdown_now = 0x00000000u;
-volatile uint32_t pathdc_change = 0x00000000u;
-
-EXTConfig extcfg = {
-
-  {
-    /* channel 0 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 1 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 2 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 3 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 4 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 5 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 6 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 7 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 8 */
-    {
-      /* mode */ EXT_MODE_GPIOC | EXT_CH_MODE_AUTOSTART | EXT_CH_MODE_BOTH_EDGES,
-      /* cb   */ pathdc_cb,
-    },
-    /* channel 9 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel A */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel B */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel C */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel D */
-    {
-      /* mode */ EXT_MODE_GPIOC | EXT_CH_MODE_AUTOSTART | EXT_CH_MODE_FALLING_EDGE,
-      /* cb   */ power_down_cb,
-    },
-    /* channel E */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel F */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 10 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 11 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 12 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 13 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 14 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 15 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-    /* channel 16 */
-    {
-      /* mode */ EXT_CH_MODE_DISABLED,
-      /* cb   */ NULL,
-    },
-  }
-};
-
-void power_down_cb(EXTDriver *extp, expchannel_t channel) {
-
-  (void) extp;
-  (void) channel;
-  // make sure we don't accidentally power down when somebody tries to wake us
-  if (!palReadPad(GPIOC, GPIOC_SYS_PD_N))
-    palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_LOW); // indicate that the module needs some time to shut down
-    shutdown_now = 5; // = SHUTDOWN_HANDLE_REQUEST in main.cpp
-}
-
-void pathdc_cb(EXTDriver *extp, expchannel_t channel) {
-
-  (void) extp;
-  (void) channel;
-
-  pathdc_change = ~0u;
-
-}
diff --git a/devices/PowerManagement/exti.hpp b/devices/PowerManagement/exti.hpp
deleted file mode 100644
index ace6689..0000000
--- a/devices/PowerManagement/exti.hpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef EXT_HPP_
-#define EXT_HPP_
-
-extern volatile uint32_t shutdown_now;
-extern volatile uint32_t pathdc_change;
-extern volatile uint32_t pathdc_value;
-
-extern EXTConfig extcfg;
-
-void power_down_cb(EXTDriver *extp, expchannel_t channel);
-void pathdc_cb(EXTDriver *extp, expchannel_t channel);
-
-#endif /* EXT_HPP_ */
diff --git a/devices/PowerManagement/global.hpp b/devices/PowerManagement/global.hpp
deleted file mode 100644
index 6d8060a..0000000
--- a/devices/PowerManagement/global.hpp
+++ /dev/null
@@ -1,212 +0,0 @@
-#ifndef AMIRO_GLOBAL_HPP_
-#define AMIRO_GLOBAL_HPP_
-
-#include <hal.h>
-
-#include <array>
-
-#include <amiro/power/adconverter.hpp>
-#include <amiro/bus/i2c/HWI2CDriver.hpp>
-#include <amiro/bus/i2c/VI2CDriver.hpp>
-#include <amiro/bus/i2c/mux/pca9544.hpp>
-#include <amiro/proximity/vcnl4020.hpp>
-#include <amiro/eeprom/at24.hpp>
-#include <amiro/FileSystemInputOutput/FSIOPowerManagement.hpp>
-#include <amiro/input/mpr121.hpp>
-#include <amiro/power/ltc4412.hpp>
-#include <amiro/power/ina219.hpp>
-#include <amiro/power/bq27500.hpp>
-#include <amiro/power/bq24103a.hpp>
-#include <amiro/power/tps62113.hpp>
-#include <amiro/bluetooth/bluetooth.hpp>
-#include <amiro/bluetooth/bluetooth-serial.hpp>
-#include <amiro/bluetooth/bluetooth-wiimote.hpp>
-#include <amiro/serial_reset/iwrap_can_mux.hpp>
-#include <amiro/serial_reset/serial_can_mux.hpp>
-#include <PowerManagement.h>
-#include <userthread.h>
-
-namespace amiro {
-
-class Global final
-{
-public:
-
-  SerialConfig sd1_config{
-    /* speed        */ 115200,
-    /* CR1 register */ 0,
-    /* CR2 register */ 0,
-    /* CR3 register */ 0
-  };
-
-  PWMConfig pwm3_config{
-    /* frequency [Hz]    */ 10000,
-    /* period [ticks]    */ 100,
-    /* callback          */ NULL,
-    /* channels          */ {
-      {PWM_OUTPUT_DISABLED, NULL},
-      {PWM_OUTPUT_ACTIVE_HIGH, NULL},
-      {PWM_OUTPUT_DISABLED, NULL},
-      {PWM_OUTPUT_DISABLED, NULL}
-    },
-    /* CR2 register      */ 0,
-    /* break & dead time */ 0
-  };
-
-  I2CConfig i2c1_config{
-    /* I2C mode                 */ OPMODE_I2C,
-    /* frequency                */ 100000,
-    /* I2C fast mode duty cycle */ STD_DUTY_CYCLE
-  };
-  I2CConfig i2c2_config{
-    /* I2C mode                 */ OPMODE_I2C,
-    /* frequency                */ 100000,
-    /* I2C fast mode duty cycle */ STD_DUTY_CYCLE
-  };
-
-  VCNL4020::VCNL4020Config vcnl4020_config{
-    /* command             */ VCNL4020::ALS_EN | VCNL4020::PROX_EN | VCNL4020::SELFTIMED_EN,
-    /* ambient parameter   */ VCNL4020::AMBIENT_RATE_2 | VCNL4020::AMBIENT_AUTO_OFFSET | VCNL4020::AMBIENT_AVG_32,
-    /* IR LED current [mA] */ 200u,
-    /* proximity rate      */ VCNL4020::PROX_RATE_125
-  };
-
-  adcsample_t adc1_buffer[1];
-  ADCConversionGroup adc1_conversion_group{
-    /* buffer type        */ TRUE, // TRUE=continuous; FALSE=linear
-    /* number of channels */ 1,
-    /* callback function  */ NULL,
-    /* error callback     */ NULL,
-    /* CR1                */ 0,
-    /* CR2                */ ADC_CR2_SWSTART | ADC_CR2_CONT,
-    /* SMPR1              */ 0,
-    /* SMPR2              */ ADC_SMPR2_SMP_AN9(ADC_SAMPLE_480),
-    /* HTR                */ ADC_HTR_HT,
-    /* LTR                */ 0,
-    /* SQR1               */ ADC_SQR1_NUM_CH(1),
-    /* SQR2               */ 0,
-    /* SQR3               */ ADC_SQR3_SQ1_N(ADC_CHANNEL_IN9)
-  };
-  ADConverter adc1_vsys;
-
-  HWI2CDriver HW_I2C1;
-  HWI2CDriver HW_I2C2;
-
-  AT24 at24c01;
-  fileSystemIo::FSIOPowerManagement memory;
-
-  LTC4412<(uintptr_t)GPIOC, GPIOC_PATH_DC> ltc4412;
-
-  std::array<INA219::Driver,5> ina219;
-
-  std::array<BQ27500::Driver,2> bq27500;
-
-private:
-  BQ24103A<(uintptr_t)GPIOC, GPIOC_CHARGE_EN1_N, (uintptr_t)GPIOC, GPIOC_CHARGE_STAT1A> bq24103a_p7;
-  BQ24103A<(uintptr_t)GPIOD, GPIOD_CHARGE_EN2_N, (uintptr_t)GPIOB, GPIOB_CHARGE_STAT2A> bq24103a_p8;
-public:
-  std::array<BaseBQ24103A*,2> bq24103a;
-
-  TPS62113<(uintptr_t)GPIOA, GPIOA_SYS_REG_EN> tps62113_vio18_33_50;
-  TPS62113<(uintptr_t)GPIOB, GPIOB_POWER_EN> tps62113_vsys42;
-
-  BLUETOOTH wt12;
-
-  std::array<PCA9544<true>, 2> HW_PCA9544;
-
-  std::array<VI2CDriver, 4> V_I2C1;
-  std::array<VI2CDriver, 4> V_I2C2;
-
-  std::array<VCNL4020, 8> vcnl4020;
-
-  MPR121::MPR121Config mpr121_run_config{
-    /* global_config  */ MPR121::CDT_1 | MPR121::SFI_10 | MPR121::ESI_32 | MPR121::FFI_18 | 16,
-    /* ele_config     */ MPR121::CL_ON_ALL | MPR121::ELEPROX_0 | 4,
-    /* auto_config    */ MPR121::FFI_18 | MPR121::RETRY_2 | MPR121::BVA_ON_ALL | MPR121::AC_RECONF_EN | MPR121::AC_ENABLE,
-    /* up_side_limit  */ 0x96u,
-    /* low_side_limit */ 0x58u,
-    /* target_level   */ 0x68u
-  };
-  MPR121::MPR121Config mpr121_stdby_config{
-    /* global_config  */ MPR121::CDT_1 | MPR121::SFI_10 | MPR121::ESI_32 | MPR121::FFI_18 | 0,
-    /* ele_config     */ MPR121::CL_ON_ALL | MPR121::ELEPROX_0 | 0, /* TODO: hack: turn buttons off for standby */
-    /* auto_config    */ MPR121::FFI_18 | MPR121::RETRY_2 | MPR121::BVA_ON_ALL | MPR121::AC_RECONF_EN | MPR121::AC_ENABLE,
-    /* up_side_limit  */ 0x96u,
-    /* low_side_limit */ 0x58u,
-    /* target_level   */ 0x68u
-  };
-  MPR121 mpr121;
-
-  IwrapCanMux iwrapcanmux1;
-  SerialCanMux sercanmux1;
-
-  PowerManagement robot;
-
-  UserThread userThread;
-
-  uint8_t shellTermID;
-
-public:
-  Global() :
-    adc1_vsys(ADCD1, adc1_conversion_group, 9000000),
-    HW_I2C1(&I2CD1), HW_I2C2(&I2CD2),
-    at24c01(0x400u / 0x08u, 0x08u, 500u, &HW_I2C2),
-    memory(at24c01, /*BMSV*/ 1, /*bmsv*/ 2, /*HMV*/ 1, /*hmv*/ 1),
-    ina219{{/* VDD      */ INA219::Driver(HW_I2C2, 0x45u),
-            /* VIO 1.8V */ INA219::Driver(HW_I2C1, 0x44u),
-            /* VIO 3.3V */ INA219::Driver(HW_I2C1, 0x40u),
-            /* VIO 4.2V */ INA219::Driver(HW_I2C2, 0x40u),
-            /* VIO 5.0V */ INA219::Driver(HW_I2C2, 0x44u)}
-          },
-    bq27500{{/* connector P7 */ BQ27500::Driver(HW_I2C2, *GPIOC, GPIOC_GAUGE_BATGD1_N, *GPIOC, GPIOC_GAUGE_BATLOW1),
-             /* connector P8 */ BQ27500::Driver(HW_I2C1, *GPIOB, GPIOB_GAUGE_BATGD2_N, *GPIOB, GPIOB_GAUGE_BATLOW2)}
-           },
-    bq24103a_p7(), bq24103a_p8(),
-    bq24103a{{&bq24103a_p7,
-              &bq24103a_p8}
-            },
-    tps62113_vio18_33_50(), tps62113_vsys42(),
-    wt12(&UARTD3),
-    HW_PCA9544{{PCA9544<true>(&HW_I2C1, 0x07u),
-                PCA9544<true>(&HW_I2C2, 0x07u)}
-              },
-    V_I2C1{{VI2CDriver(&HW_PCA9544[0], 0),
-            VI2CDriver(&HW_PCA9544[0], 1),
-            VI2CDriver(&HW_PCA9544[0], 2),
-            VI2CDriver(&HW_PCA9544[0], 3)}
-          },
-    V_I2C2{{VI2CDriver(&HW_PCA9544[1], 0),
-            VI2CDriver(&HW_PCA9544[1], 1),
-            VI2CDriver(&HW_PCA9544[1], 2),
-            VI2CDriver(&HW_PCA9544[1], 3)}
-          },
-    vcnl4020{{/* rear left        */ VCNL4020(&V_I2C1[1], &vcnl4020_config),
-              /* left side rear   */ VCNL4020(&V_I2C1[3], &vcnl4020_config),
-              /* left side front  */ VCNL4020(&V_I2C1[2], &vcnl4020_config),
-              /* front left       */ VCNL4020(&V_I2C2[0], &vcnl4020_config),
-              /* front right      */ VCNL4020(&V_I2C2[1], &vcnl4020_config),
-              /* right side front */ VCNL4020(&V_I2C2[3], &vcnl4020_config),
-              /* right side rear  */ VCNL4020(&V_I2C2[2], &vcnl4020_config),
-              /* rear right       */ VCNL4020(&V_I2C1[0], &vcnl4020_config)}
-            },
-    mpr121(&HW_I2C2, 0),
-    iwrapcanmux1(&SD1, &CAND1, CAN::POWER_MANAGEMENT_ID),
-    sercanmux1(&SD1, &CAND1, CAN::POWER_MANAGEMENT_ID),
-    robot(&CAND1),
-    userThread()
-  {
-    memset(this->adc1_buffer, 0, sizeof(adc1_buffer));
-
-    return;
-  }
-
-  ~Global()
-  {
-    return;
-  }
-
-};
-
-} // end of namespace amiro
-
-#endif /* AMIRO_GLOBAL_HPP_ */
diff --git a/devices/PowerManagement/halconf.h b/devices/PowerManagement/halconf.h
deleted file mode 100644
index 3a1d56c..0000000
--- a/devices/PowerManagement/halconf.h
+++ /dev/null
@@ -1,296 +0,0 @@
-/**
- * @file    devices/PowerManagement/halconf.h
- * @brief   HAL configuration header.
- * @details HAL configuration file, this file allows to enable or disable the
- *          various device drivers from your application. You may also use
- *          this file in order to override the device drivers default settings.
- *
- * @addtogroup HAL_CONF
- * @{
- */
-
-#ifndef _HALCONF_H_
-#define _HALCONF_H_
-
-#include "mcuconf.h"
-
-/**
- * @brief   Enables the TM subsystem.
- */
-#if !defined(HAL_USE_TM) || defined(__DOXYGEN__)
-#define HAL_USE_TM                  FALSE
-#endif
-
-/**
- * @brief   Enables the PAL subsystem.
- */
-#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
-#define HAL_USE_PAL                 TRUE
-#endif
-
-/**
- * @brief   Enables the ADC subsystem.
- */
-#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
-#define HAL_USE_ADC                 TRUE
-#endif
-
-/**
- * @brief   Enables the CAN subsystem.
- */
-#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
-#define HAL_USE_CAN                 TRUE
-#endif
-
-/**
- * @brief   Enables the EXT subsystem.
- */
-#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
-#define HAL_USE_EXT                 TRUE
-#endif
-
-/**
- * @brief   Enables the GPT subsystem.
- */
-#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
-#define HAL_USE_GPT                 FALSE
-#endif
-
-/**
- * @brief   Enables the I2C subsystem.
- */
-#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
-#define HAL_USE_I2C                 TRUE
-#endif
-
-/**
- * @brief   Enables the ICU subsystem.
- */
-#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
-#define HAL_USE_ICU                 FALSE
-#endif
-
-/**
- * @brief   Enables the MAC subsystem.
- */
-#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
-#define HAL_USE_MAC                 FALSE
-#endif
-
-/**
- * @brief   Enables the MMC_SPI subsystem.
- */
-#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_MMC_SPI             FALSE
-#endif
-
-/**
- * @brief   Enables the PWM subsystem.
- */
-#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
-#define HAL_USE_PWM                 TRUE
-#endif
-
-/**
- * @brief   Enables the RTC subsystem.
- */
-#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
-#define HAL_USE_RTC                 FALSE
-#endif
-
-/**
- * @brief   Enables the SDC subsystem.
- */
-#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
-#define HAL_USE_SDC                 FALSE
-#endif
-
-/**
- * @brief   Enables the SERIAL subsystem.
- */
-#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL              TRUE
-#endif
-
-/**
- * @brief   Enables the SERIAL over USB subsystem.
- */
-#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
-#define HAL_USE_SERIAL_USB          FALSE
-#endif
-
-/**
- * @brief   Enables the SPI subsystem.
- */
-#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
-#define HAL_USE_SPI                 FALSE
-#endif
-
-/**
- * @brief   Enables the UART subsystem.
- */
-#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
-#define HAL_USE_UART                TRUE
-#endif
-
-/**
- * @brief   Enables the USB subsystem.
- */
-#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
-#define HAL_USE_USB                 FALSE
-#endif
-
-/*===========================================================================*/
-/* ADC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables synchronous APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
-#define ADC_USE_WAIT                TRUE
-#endif
-
-/**
- * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define ADC_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-/*===========================================================================*/
-/* CAN driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Sleep mode related APIs inclusion switch.
- */
-#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
-#define CAN_USE_SLEEP_MODE          TRUE
-#endif
-
-/*===========================================================================*/
-/* I2C driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables the mutual exclusion APIs on the I2C bus.
- */
-#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define I2C_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-/*===========================================================================*/
-/* MAC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
-#define MAC_USE_ZERO_COPY           FALSE
-#endif
-
-/**
- * @brief   Enables an event sources for incoming packets.
- */
-#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
-#define MAC_USE_EVENTS              TRUE
-#endif
-
-/*===========================================================================*/
-/* MMC_SPI driver related settings.                                          */
-/*===========================================================================*/
-
-/**
- * @brief   Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- *          routines releasing some extra CPU time for the threads with
- *          lower priority, this may slow down the driver a bit however.
- *          This option is recommended also if the SPI driver does not
- *          use a DMA channel and heavily loads the CPU.
- */
-#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
-#define MMC_NICE_WAITING            TRUE
-#endif
-
-/*===========================================================================*/
-/* SDC driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Number of initialization attempts before rejecting the card.
- * @note    Attempts are performed at 10mS intervals.
- */
-#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
-#define SDC_INIT_RETRY              100
-#endif
-
-/**
- * @brief   Include support for MMC cards.
- * @note    MMC support is not yet implemented so this option must be kept
- *          at @p FALSE.
- */
-#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
-#define SDC_MMC_SUPPORT             FALSE
-#endif
-
-/**
- * @brief   Delays insertions.
- * @details If enabled this options inserts delays into the MMC waiting
- *          routines releasing some extra CPU time for the threads with
- *          lower priority, this may slow down the driver a bit however.
- */
-#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
-#define SDC_NICE_WAITING            TRUE
-#endif
-
-/*===========================================================================*/
-/* SERIAL driver related settings.                                           */
-/*===========================================================================*/
-
-/**
- * @brief   Default bit rate.
- * @details Configuration parameter, this is the baud rate selected for the
- *          default configuration.
- */
-#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
-#define SERIAL_DEFAULT_BITRATE      38400
-#endif
-
-/**
- * @brief   Serial buffers size.
- * @details Configuration parameter, you can change the depth of the queue
- *          buffers depending on the requirements of your application.
- * @note    The default is 64 bytes for both the transmission and receive
- *          buffers.
- */
-#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
-#define SERIAL_BUFFERS_SIZE         16
-#endif
-
-/*===========================================================================*/
-/* SPI driver related settings.                                              */
-/*===========================================================================*/
-
-/**
- * @brief   Enables synchronous APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
-#define SPI_USE_WAIT                TRUE
-#endif
-
-/**
- * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
- * @note    Disabling this option saves both code and data space.
- */
-#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define SPI_USE_MUTUAL_EXCLUSION    TRUE
-#endif
-
-#endif /* _HALCONF_H_ */
-
-/** @} */
diff --git a/devices/PowerManagement/main.cpp b/devices/PowerManagement/main.cpp
deleted file mode 100644
index f87e9ba..0000000
--- a/devices/PowerManagement/main.cpp
+++ /dev/null
@@ -1,1251 +0,0 @@
-#ifndef IN_CCM
-/*
- * @brief Makro to store data in the core coupled memory (ccm).
- *        Example:
- *        int compute_buffer[128] IN_CCM;
- *
- * @note The ccm is not connected to any bus system.
- */
-#define IN_CCM  __attribute__((section(".ccm"))) __attribute__((aligned(4)))
-#endif
-
-#ifndef IN_ETH
-/*
- * @brief Makro to store data in the ethernet memory (eth).
- *        Example:
- *        int dma_buffer[128] IN_ETH;
- *
- * @note The eth is a dedicated memory block with its own DMA controller.
- */
-#define IN_ETH  __attribute__((section(".eth"))) __attribute__((aligned(4)))
-#endif
-
-#define BL_CALLBACK_TABLE_ADDR  (0x08000000 + 0x01C0)
-#define BL_MAGIC_NUMBER         ((uint32_t)0xFF669900u)
-
-#define SHUTDOWN_NONE             0
-#define SHUTDOWN_TRANSPORTATION   1
-#define SHUTDOWN_DEEPSLEEP        2
-#define SHUTDOWN_HIBERNATE        3
-#define SHUTDOWN_RESTART          4
-#define SHUTDOWN_HANDLE_REQUEST   5
-
-#include <ch.hpp>
-#include <shell.h>
-#include <chprintf.h>
-#include <wakeup.h>
-#include <cstdlib>
-#include <cstring>
-#include <amiro/util/util.h>
-#include <global.hpp>
-#include <exti.hpp>
-
-using namespace amiro;
-using namespace constants::PowerManagement;
-
-Global global;
-
-struct blVersion_t {
-  const uint8_t identifier;
-  const uint8_t major;
-  const uint8_t minor;
-  const uint8_t patch;
-} __attribute__((packed));
-
-void shutdownTimeoutISR(void *arg) {
-
-  (void) arg;
-
-}
-
-void systemStop() {
-
-//  VirtualTimer shutdownTimeout;
-  uint8_t i;
-
-  // tell all boards that it's time to shut down
-  global.robot.broadcastShutdown();
-
-  global.userThread.requestTerminate();
-  global.userThread.wait();
-
-  // kill bluetooth
-  boardBluetoothSetState(0);
-
-  global.adc1_vsys.requestTerminate();
-  global.adc1_vsys.wait();
-
-  for (i = 0; i < global.vcnl4020.size(); ++i) {
-    global.vcnl4020[i].requestTerminate();
-    global.vcnl4020[i].wait();
-  }
-
-  for (i = 0; i < global.bq27500.size(); ++i) {
-    global.bq27500[i].requestTerminate();
-    global.bq27500[i].wait();
-  }
-
-  for (i = 0; i < global.ina219.size(); ++i) {
-    global.ina219[i].requestTerminate();
-    global.ina219[i].wait();
-  }
-
-//  boardWriteIoPower(0);
-  global.mpr121.configure(&global.mpr121_stdby_config);
-  /* cannot shut down touch, b/c we need it to
-   * clear any interrupt, so WKUP is not blocked
-   */
-
-  // stop I²C
-  for (i = 0; i < global.V_I2C1.size(); ++i)
-    global.V_I2C1[i].stop();
-  for (i = 0; i < global.V_I2C2.size(); ++i)
-    global.V_I2C2[i].stop();
-
-  global.mpr121.requestTerminate();
-  global.mpr121.wait();
-
-  global.HW_I2C2.stop();
-  global.HW_I2C1.stop();
-
-  // stop all threads
-  global.robot.terminate();
-
-//  // 60 sec timeout
-//  palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_HIGH);
-//  chVTSet(&shutdownTimeout, MS2ST(60000), shutdownTimeoutISR, NULL);
-//  // wait for all boards to release SYS_INT_N
-//  while (palReadPad(GPIOC, GPIOC_SYS_INT_N)!=PAL_HIGH && chVTIsArmedI(&shutdownTimeout)) {
-//    BaseThread::sleep(MS2ST(1)); /* must sleep for VT, else it will never fire */
-//  }
-//  chVTReset(&shutdownTimeout);
-
-//  chprintf((BaseSequentialStream*) &SD1, "Stop\n");
-//  boardWriteSystemPower(0);
-//  boardWriteLed(1);
-//  boardStop(0x00, 0x00);
-
-//  /*
-//   * HSI-PLL domain now.
-//   */
-//  //chprintf((BaseSequentialStream*) &SD1, "After Stop\n");
-//  boardWriteLed(1);
-
-//  while (true)
-//    BaseThread::sleep(MS2ST(250));
-
-  return;
-}
-
-void systemShutdown() {
-
-  VirtualTimer shutdownTimeout;
-  uint8_t i;
-
-  // tell all boards that it's time to shut down
-  global.robot.broadcastShutdown();
-
-  // wait a little to make sure all boards got the message and had time to pull their SYS_PD_N pins down
-  BaseThread::sleep(MS2ST(500));
-
-  // stop the user thread
-  global.userThread.requestTerminate();
-  global.userThread.wait();
-
-  // kill bluetooth
-  boardBluetoothSetState(0);
-
-  // stop all threads
-  global.robot.terminate();
-
-  global.adc1_vsys.requestTerminate();
-  global.adc1_vsys.wait();
-
-  for (i = 0; i < global.vcnl4020.size(); ++i) {
-    global.vcnl4020[i].requestTerminate();
-    global.vcnl4020[i].wait();
-  }
-
-  for (i = 0; i < global.bq27500.size(); ++i) {
-    global.bq27500[i].requestTerminate();
-    global.bq27500[i].wait();
-  }
-
-  for (i = 0; i < global.ina219.size(); ++i) {
-    global.ina219[i].requestTerminate();
-    global.ina219[i].wait();
-  }
-
-  // 60 sec timeout
-  chVTSet(&shutdownTimeout, MS2ST(60000), shutdownTimeoutISR, NULL);
-
-  // wait for all boards to release SYS_PD_N
-  while (!palReadPad(GPIOC, GPIOC_SYS_PD_N) && chVTIsArmedI(&shutdownTimeout))
-    BaseThread::sleep(MS2ST(1)); /* must sleep for VT, else it will never fire */
-
-  chVTReset(&shutdownTimeout);
-  boardWriteIoPower(0);
-  global.mpr121.configure(&global.mpr121_stdby_config);
-  /* cannot shut down touch, b/c we need it to
-   * clear any interrupt, so WKUP is not blocked
-   */
-
-  // stop I²C
-  for (i = 0; i < global.V_I2C1.size(); ++i)
-    global.V_I2C1[i].stop();
-  for (i = 0; i < global.V_I2C2.size(); ++i)
-    global.V_I2C2[i].stop();
-
-  boardWriteSystemPower(0);
-  boardStandby();
-
-}
-
-
-void boardPeripheryCheck(BaseSequentialStream *chp) {
-
-#ifndef AMIRO_NSELFTEST
-  chprintf(chp, "\nCHECK: START\n");
-  msg_t result = 0;
-
-    // Check the proximitysensors
-  for (uint8_t i = 0; i < global.vcnl4020.size(); i++) {
-    result = global.vcnl4020[i].getCheck();
-    if (result == global.vcnl4020[i].CHECK_OK)
-      chprintf(chp, "VCNL4020: %d OK\n", i);
-    else
-      chprintf(chp, "VCNL4020: %d FAIL\n", i);
-  }
-  chprintf(chp, "----------------------------------------\n");
-
-  // check the PowerPath controller
-  chprintf(chp, "\n");
-  if (global.ltc4412.isPluggedIn())
-    chprintf(chp, "LTC4412: plugged in\n");
-  else
-    chprintf(chp, "LTC4412: not plugged in\n");
-  chprintf(chp, "----------------------------------------\n");
-
-  // Check the eeprom
-  result = global.memory.getCheck();
-  if ( result != global.memory.OK)
-    chprintf(chp, "Memory Structure: FAIL\n");
-  else
-    chprintf(chp, "Memory Structure: OK\n");
-  chprintf(chp, "----------------------------------------\n");
-
-  // Check the power monitors
-  INA219::BusVoltage bus_voltage;
-  chprintf(chp, "\n");
-  chprintf(chp, "INA219:\n");
-  chprintf(chp, "\tVDD (3.3V):\n");
-  uint8_t result_ina219_vdd = global.ina219[INA_VDD].selftest();
-  chprintf(chp, "->\t");
-  if (result_ina219_vdd == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_ina219_vdd != INA219::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vdd);
-  else
-    chprintf(chp, "OK");
-
-  chprintf(chp, "\n\n");
-  chprintf(chp, "\tVIO1.8:\n");
-  uint8_t result_ina219_vio18 = global.ina219[INA_VIO18].selftest();
-  chprintf(chp, "->\t");
-  if (result_ina219_vio18 == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_ina219_vio18 != INA219::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio18);
-  else
-    chprintf(chp, "OK");
-
-  chprintf(chp, "\n\n");
-  chprintf(chp, "\tVIO3.3:\n");
-  uint8_t result_ina219_vio33 = global.ina219[INA_VIO33].selftest();
-  chprintf(chp, "->\t");
-  if (result_ina219_vio33 == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_ina219_vio33 != INA219::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio33);
-  else
-    chprintf(chp, "OK");
-
-  chprintf(chp, "\n\n");
-  chprintf(chp, "\tVIO4.2:\n");
-  uint8_t result_ina219_vio42 = global.ina219[INA_VIO42].selftest();
-  chprintf(chp, "->\t");
-  if (result_ina219_vio42 == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_ina219_vio42 != INA219::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio42);
-  else
-    chprintf(chp, "OK");
-
-  bus_voltage = global.ina219[INA_VIO42].readBusVoltage();
-  chprintf(chp, "\n\n");
-  chprintf(chp, "\tVIO5.0:\n");
-  uint8_t result_ina219_vio50 = global.ina219[INA_VIO50].selftest();
-  chprintf(chp, "->\t");
-  if (result_ina219_vio50 == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_ina219_vio50 != INA219::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result_ina219_vio50);
-  else
-    chprintf(chp, "OK");
-
-  chprintf(chp, "\n\n");
-  result = result_ina219_vdd | result_ina219_vio18 | result_ina219_vio33 | result_ina219_vio42 | result_ina219_vio50;
-  if (result == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "->\tINA219: not implemented\n");
-  else
-    chprintf(chp, "->\tINA219: %s\n", (result != INA219::Driver::ST_OK)? "FAIL" : "OK");
-  chprintf(chp, "----------------------------------------\n");
-
-  // check the fuel gauges
-  chprintf(chp, "\n");
-  chprintf(chp, "BQ27500:\n");
-  chprintf(chp, "\tP7:\n");
-  msg_t result_bq27500_p7 = global.bq27500[BAT_P7].selftest();
-  chprintf(chp, "->\tP7: ");
-  if (result == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_bq27500_p7 == BQ27500::Driver::ST_ABORT_NO_BAT)
-    chprintf(chp, "ABORT (no battery detected)");
-  else if (result_bq27500_p7 != BQ27500::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result);
-  else
-    chprintf(chp, "OK");
-
-  chprintf(chp, "\n\n");
-  chprintf(chp, "\tP8:\n");
-  msg_t result_bq27500_p8 = global.bq27500[BAT_P8].selftest();
-  chprintf(chp, "->\tP8: ");
-  if (result == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "not implemented");
-  else if (result_bq27500_p8 == BQ27500::Driver::ST_ABORT_NO_BAT)
-      chprintf(chp, "ABORT (no battery detected)");
-  else if (result_bq27500_p8 != BQ27500::Driver::ST_OK)
-    chprintf(chp, "FAIL (error code 0x%02X)", result);
-  else
-    chprintf(chp, "OK");
-
-  chprintf(chp, "\n");
-  result = result_bq27500_p7 | result_bq27500_p8;
-  if (result == BaseSensor<>::NOT_IMPLEMENTED)
-    chprintf(chp, "\n->\tBQ27500: not implemented\n");
-  else
-    chprintf(chp, "\n->\tBQ27500: %s\n", (result != BQ27500::Driver::ST_OK)? "FAIL" : "OK");
-  chprintf(chp, "----------------------------------------\n");
-
-  // check the chargers
-  chprintf(chp, "\n");
-  chprintf(chp, "BQ24103A:\n");
-  if (!global.ltc4412.isPluggedIn())
-    chprintf(chp, "This test is skipped. Rerun when plugged in.\n");
-  else {
-    bool status1, status2, status3;
-    chprintf(chp, "\tP7:\n");
-    bool status_p7 = global.bq27500[BAT_P7].isBatteryGood();
-    chprintf(chp, "Battery good: %s\n", (status_p7? "yes" : "no"));
-    if (!status_p7) {
-      chprintf(chp, "-> Rerun test with (another) battery!\n");
-      status_p7 = true;
-    } else {
-      status1 = global.bq24103a[BAT_P7]->isCharging();
-      chprintf(chp, "status:%scharging\n", (status1? " " : " not "));
-      chprintf(chp, "%sabling charger...\n", (status1? "dis" : "en"));
-      global.bq24103a[BAT_P7]->enable(!status1);
-      BaseThread::sleep(MS2ST(1500));
-      status2 = global.bq24103a[BAT_P7]->isCharging();
-      chprintf(chp, "status:%scharging\n", (status2? " " : " not "));
-      chprintf(chp, "%sabling charger...\n", (!status1? "dis" : "en"));
-      global.bq24103a[BAT_P7]->enable(status1);
-      BaseThread::sleep(MS2ST(1500));
-      status3 = global.bq24103a[BAT_P7]->isCharging();
-      chprintf(chp, "status:%scharging\n", (status3? " " : " not "));
-      status_p7 = status2 != status1 && status3 == status1;
-      chprintf(chp, "->\t");
-      if (status_p7) {
-        chprintf(chp, "OK");
-      } else {
-        chprintf(chp, "FAIL");
-      }
-      chprintf(chp, "\n");
-    }
-    chprintf(chp, "\n");
-    chprintf(chp, "\tP8:\n");
-    bool status_p8 = global.bq27500[BAT_P8].isBatteryGood();
-    chprintf(chp, "Battery good: %s\n", (status_p8? "yes" : "no"));
-    if (!status_p8) {
-      chprintf(chp, "-> Rerun test with (another) battery!\n");
-      status_p8 = true;
-    } else {
-      status1 = global.bq24103a[BAT_P8]->isCharging();
-      chprintf(chp, "status:%scharging\n", (status1? " " : " not "));
-      chprintf(chp, "%sabling charger...\n", (status1? "dis" : "en"));
-      global.bq24103a[BAT_P8]->enable(!status1);
-      BaseThread::sleep(MS2ST(1500));
-      status2 = global.bq24103a[BAT_P8]->isCharging();
-      chprintf(chp, "status:%scharging\n", (status2? " " : " not "));
-      chprintf(chp, "%sabling charger...\n", (!status1? "dis" : "en"));
-      global.bq24103a[BAT_P8]->enable(status1);
-      BaseThread::sleep(MS2ST(1500));
-      status3 = global.bq24103a[BAT_P8]->isCharging();
-      chprintf(chp, "status:%scharging\n", (status3? " " : "not "));
-      status_p8 = status2 != status1 && status3 == status1;
-      chprintf(chp, "->\t");
-      if (status_p8)
-        chprintf(chp, "OK");
-      else
-        chprintf(chp, "FAIL");
-      chprintf(chp, "\n");
-    }
-    chprintf(chp, "\n");
-    chprintf(chp, "->\tBQ24103A: ");
-    if (status_p7 && status_p8)
-      chprintf(chp, "OK");
-    else
-      chprintf(chp, "FAIL");
-    chprintf(chp, "\n");
-  }
-  chprintf(chp, "----------------------------------------\n");
-
-  // check Bluetooth (TODO: move this check to driver)
-  chprintf(chp, "\n");
-  chprintf(chp, "WT12-A-AI:\n");
-
-  chprintf(chp, "testing for MUX mode:\t");
-
-  if (global.wt12.bluetoothIsMuxMode()) {
-    chprintf(chp, "PASSED\n");
-  } else {
-    chprintf(chp, "FAILED -> setting MUX mode now\n");
-    /* initialise the WT-12 bluetooth chip on AMIRO (Please, run this processes once) */
-    global.wt12.bluetoothSendCommand("SET BT AUTH *");
-    global.wt12.bluetoothSendCommand("SET BT PAIR *");
-    global.wt12.bluetoothSendCommand("SET BT SSP 3 0");
-    global.wt12.bluetoothEnableMux();
-    global.wt12.bluetoothReset();
-  }
-
-  global.wt12.bluetoothSendCommand("TEMP");
-  global.wt12.bluetoothSendCommand("SET");
-
-  chprintf(chp, "----------------------------------------\n");
-
-  // check the buzzer
-  chprintf(chp, "\n");
-  chprintf(chp, "PKLCS1212E4001:\n");
-  chprintf(chp, "you should hear the buzzer for one second...\n");
-  pwmEnableChannel(&PWMD3, 1, 50);
-  BaseThread::sleep(MS2ST(1000));
-  pwmDisableChannel(&PWMD3, 1);
-  chprintf(chp, "----------------------------------------\n");
-
-  chprintf(chp, "CHECK: FINISH\n");
-#endif
-
-  return;
-}
-
-void shellRequestShutdown(BaseSequentialStream* chp, int __unused argc, char __unused *argv[]) {
-
-  chprintf(chp, "shellRequestShutdown\n");
-
-  /* if no argument was given, print some help text */
-  if (argc == 0 || strcmp(argv[0],"help") == 0) {
-    chprintf(chp, "\tUSAGE:\n");
-    chprintf(chp, "> shutdown <type>\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\ttype\n");
-    chprintf(chp, "The type of shutdown to perform.\n");
-    chprintf(chp, "Choose one of the following types:\n");
-    chprintf(chp, "  transportation - Ultra low-power mode with all wakeups disabled.\n");
-    chprintf(chp, "                   The robot can not be charged.\n");
-    chprintf(chp, "  deepsleep      - Ultra low-power mode with several wakeups enabled.\n");
-    chprintf(chp, "                   The robot can only be charged via the power plug.\n");
-    chprintf(chp, "  hibernate      - Medium low-power mode, but with full charging capabilities.\n");
-    chprintf(chp, "  restart        - Performs a system restart.\n");
-    chprintf(chp, "Alternatively, you can use the shortcuts 't', 'd', 'h', and 'r' respectively.");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  if (strcmp(argv[0],"transportation") == 0 || strcmp(argv[0],"t") == 0) {
-    shutdown_now = SHUTDOWN_TRANSPORTATION;
-    chprintf(chp, "shutdown to transportation mode initialized\n");
-  } else if (strcmp(argv[0],"deepsleep") == 0 || strcmp(argv[0],"d") == 0) {
-    shutdown_now = SHUTDOWN_DEEPSLEEP;
-    chprintf(chp, "shutdown to deepsleep mode initialized\n");
-  } else if (strcmp(argv[0],"hibernate") == 0 || strcmp(argv[0],"h") == 0) {
-    shutdown_now = SHUTDOWN_HIBERNATE;
-    chprintf(chp, "shutdown to hibernate mode initialized\n");
-  } else if (strcmp(argv[0],"restart") == 0 || strcmp(argv[0],"r") == 0) {
-    chprintf(chp, "restart initialized\n");
-    shutdown_now = SHUTDOWN_RESTART;
-  } else {
-    chprintf(chp, "ERROR: unknown argument!\n");
-    shutdown_now = SHUTDOWN_NONE;
-  }
-
-  return;
-}
-
-void shellRequestResetMemory(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestInitMemory\n");
-
-  msg_t res = global.memory.resetMemory();
-
-  if ( res != global.memory.OK)
-    chprintf(chp, "Memory Init: FAIL\n");
-  else
-    chprintf(chp, "Memory Init: OK\n");
-}
-
-void shellRequestGetBoardId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetBoardId\n");
-
-  uint8_t id = 0xFFu;
-  msg_t res = global.memory.getBoardId(&id);
-  if (res != global.memory.OK)
-    chprintf(chp, "Get Board ID: FAIL\n");
-  else
-    chprintf(chp, "Get Board ID: %u\n", id);
-}
-
-void shellRequestSetBoardId(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetBoardId\n");
-
-  if (argc == 0) {
-    chprintf(chp, "Usage: %s\n","set_board_id <idx>");
-  } else {
-    msg_t res = global.memory.setBoardId(atoi(argv[0]));
-    if (res != global.memory.OK)
-      chprintf(chp, "Set Board ID: FAIL\n");
-    else
-      chprintf(chp, "Set Board ID: OK\n");
-  }
-
-}
-
-void shellRequestGetMemoryData(BaseSequentialStream *chp, int argc, char *argv[]) {
-  enum Type {HEX, U8, U16, U32, S8, S16, S32};
-
-  chprintf(chp, "shellRequestReadData\n");
-
-  if (argc < 2 || strcmp(argv[0],"help") == 0)
-  {
-    chprintf(chp, "Usage: %s\n","get_memory_data <type> <start> [<count>]");
-    chprintf(chp, "\n");
-    chprintf(chp, "\ttype\n");
-    chprintf(chp, "The data type as which to interpret the data.\n");
-    chprintf(chp, "Choose one of the following types:\n");
-    chprintf(chp, "  hex - one byte as hexadecimal value\n");
-    chprintf(chp, "  u8  - unsigned integer (8 bit)\n");
-    chprintf(chp, "  u16 - unsigned integer (16 bit)\n");
-    chprintf(chp, "  u32 - unsigned integer (32 bit)\n");
-    chprintf(chp, "  s8  - signed integer (8 bit)\n");
-    chprintf(chp, "  s16 - signed integer (16 bit)\n");
-    chprintf(chp, "  s32 - signed integer (32 bit)\n");
-    chprintf(chp, "\tstart\n");
-    chprintf(chp, "The first byte to read from the memory.\n");
-    chprintf(chp, "\tcount [default = 1]\n");
-    chprintf(chp, "The number of elements to read.\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tNOTE\n");
-    chprintf(chp, "Type conversions of this function might fail.\n");
-    chprintf(chp, "If so, use type=hex and convert by hand.\n");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  uint8_t type_size = 0;
-  Type type = HEX;
-  if (strcmp(argv[0],"hex") == 0) {
-    type_size = sizeof(unsigned char);
-    type = HEX;
-  } else if(strcmp(argv[0],"u8") == 0) {
-    type_size = sizeof(uint8_t);
-    type = U8;
-  } else if(strcmp(argv[0],"u16") == 0) {
-    type_size = sizeof(uint16_t);
-    type = U16;
-  } else if(strcmp(argv[0],"u32") == 0) {
-    type_size = sizeof(uint32_t);
-    type = U32;
-  } else if(strcmp(argv[0],"s8") == 0) {
-    type_size = sizeof(int8_t);
-    type = S8;
-  } else if(strcmp(argv[0],"s16") == 0) {
-    type_size = sizeof(int16_t);
-    type = S16;
-  } else if(strcmp(argv[0],"s32") == 0) {
-    type_size = sizeof(int32_t);
-    type = S32;
-  } else {
-    chprintf(chp, "First argument invalid. Use 'get_memory_data help' for help.\n");
-    return;
-  }
-
-  unsigned int start_byte = atoi(argv[1]);
-
-  unsigned int num_elements = 1;
-  if (argc >= 3) {
-    num_elements = atoi(argv[2]);
-  }
-
-  const size_t eeprom_size = EEPROM::getsize(&global.at24c01);
-  uint8_t buffer[eeprom_size];
-  if (start_byte + (type_size * num_elements) > eeprom_size) {
-    num_elements = (eeprom_size - start_byte) / type_size;
-    chprintf(chp, "Warning: request exceeds eeprom size -> limiting to %u values.\n", num_elements);
-  }
-
-  chFileStreamSeek((BaseFileStream*)&global.at24c01, start_byte);
-  uint32_t bytes_read = chSequentialStreamRead((BaseFileStream*)&global.at24c01, buffer, type_size*num_elements);
-
-  if (bytes_read != type_size*num_elements) {
-    chprintf(chp, "Warning: %u of %u requested bytes were read.\n", bytes_read, type_size*num_elements);
-  }
-
-  for (unsigned int i = 0; i < num_elements; ++i)
-  {
-    switch (type)
-    {
-      case HEX:
-        chprintf(chp, "%02X ", buffer[i]);
-        break;
-      case U8:
-        chprintf(chp, "%03u ", ((uint8_t*)buffer)[i]);
-        break;
-      case U16:
-        chprintf(chp, "%05u ", ((uint16_t*)buffer)[i]);
-        break;
-      case U32:
-        chprintf(chp, "%010u ", ((uint32_t*)buffer)[i]);
-        break;
-      case S8:
-        chprintf(chp, "%+03d ", ((int8_t*)buffer)[i]);
-        break;
-      case S16:
-        chprintf(chp, "%+05d ", ((int16_t*)buffer)[i]);
-        break;
-      case S32:
-        chprintf(chp, "%+010d ", ((int32_t*)buffer)[i]);
-        break;
-      default:
-        break;
-    }
-  }
-  chprintf(chp, "\n");
-
-  return;
-}
-
-void shellRequestSetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetVcnlOffset\n");
-  if (argc != 2) {
-    chprintf(chp, "Usage: %s\n","set_vcnl <idx> <offset>");
-    return;
-  }
-
-  uint8_t vcnlIdx = static_cast<uint8_t>(atoi(argv[0]));
-  uint16_t vcnlOffset = static_cast<uint16_t>(atoi(argv[1]));
-
-  if (vcnlIdx >= global.vcnl4020.size()) {
-    chprintf((BaseSequentialStream *)&SD1, "Wrong VCNL index: Choose [0 .. %d]\n", global.vcnl4020.size()-1);
-    return;
-  }
-
-  msg_t res = global.memory.setVcnl4020Offset(vcnlOffset, vcnlIdx);
-  if (res != global.memory.OK) {
-    chprintf(chp, "Set Offset: FAIL\n");
-  } else {
-    chprintf(chp, "Set Offset: OK\n");
-    global.vcnl4020[vcnlIdx].setProximityOffset(vcnlOffset);
-  }
-}
-
-void shellRequestResetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
-  msg_t res = global.memory.OK;
-  for (uint8_t idx = 0; idx < 8; ++idx) {
-    msg_t r = global.memory.setVcnl4020Offset(0, idx);
-    if (r == global.memory.OK) {
-      global.vcnl4020[idx].setProximityOffset(0);
-    } else {
-      chprintf(chp, "Reset Offset %u: FAIL\n", idx);
-      res = r;
-    }
-  }
-
-  if (res == global.memory.OK) {
-    chprintf(chp, "Reset Offset: DONE\n");
-  }
-
-  return;
-}
-
-void shellRequestGetVcnlOffset(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetVcnlOffset\n");
-  if (argc != 1) {
-    chprintf(chp, "Usage: %s\n","get_vcnl_offset <idx>");
-    return;
-  }
-
-  uint8_t vcnlIdx = static_cast<uint8_t>(atoi(argv[0]));
-
-  if (vcnlIdx >= global.vcnl4020.size()) {
-    chprintf((BaseSequentialStream *)&SD1, "Wrong VCNL index: Choose [0 .. %d]\n", global.vcnl4020.size()-1);
-    return;
-  }
-
-  uint16_t vcnlOffset;
-  msg_t res = global.memory.getVcnl4020Offset(&vcnlOffset, vcnlIdx);
-  if (res != global.memory.OK) {
-    chprintf(chp, "Get Offset: FAIL\n");
-  } else {
-    chprintf(chp, "Get Offset: OK \t Offset=%d\n", vcnlOffset);
-  }
-}
-
-void shellRequestCheck(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestCheck\n");
-  boardPeripheryCheck(chp);
-
-}
-
-void shellRequestGetVcnl(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetVcnl\n");
-  // Print the sensor information
-  if (argc != 1) {
-    chprintf(chp, "Usage: %s\n","get_vcnl <rep>");
-    return;
-  }
-  for (int32_t rep = 0x00; rep < atoi(argv[0]); ++rep) {
-    for (uint8_t idx = 0x00; idx < global.vcnl4020.size(); idx++) {
-     chprintf(chp, "%d: Ambi %d\tProx raw %d\tProx scaled %d\n", idx, global.vcnl4020[idx].getAmbientLight(), global.vcnl4020[idx].getProximity(), global.vcnl4020[idx].getProximityScaledWoOffset());
-    }
-    chprintf(chp, "\n\n");
-    BaseThread::sleep(MS2ST(250));
-  }
-}
-
-void shellRequestCalib(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestCalib\n");
-  global.robot.calibrate();
-
-}
-
-void shellRequestGetRobotId(BaseSequentialStream *chp, int __unused argc, char __unused *argv[]) {
-  chprintf(chp, "shellRequestGetRobotId\n");
-  chprintf(chp, "Robot ID: %u\n", global.robot.getRobotID());
-  if (global.robot.getRobotID() == 0) {
-    chprintf(chp, "Warning: The ID seems to be uninitialized. Is CAN communication working correctly?\n");
-  }
-}
-
-void shellRequestGetSystemLoad(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestGetSystemLoad\n");
-  uint8_t seconds = 1;
-  if (argc >= 1) {
-    seconds = atoi(argv[0]);
-  }
-  chprintf(chp, "measuring CPU load for %u %s...\n", seconds, (seconds>1)? "seconds" : "second");
-
-  const systime_t before = chThdGetTicks(chSysGetIdleThread());
-  BaseThread::sleep(S2ST(seconds));
-  const systime_t after = chThdGetTicks(chSysGetIdleThread());
-  const float usage = 1.0f - (float(after - before) / float(seconds * CH_FREQUENCY));
-
-  chprintf(chp, "CPU load: %3.2f%%\n", usage * 100);
-  const uint32_t memory_total = 0x1C000;
-  const uint32_t memory_load = memory_total - chCoreStatus();
-  chprintf(chp, "RAM load: %3.2f%% (%u / %u Byte)\n", float(memory_load)/float(memory_total) * 100, memory_load, memory_total);
-}
-
-void shellRequestSetCharging(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestSetCharging\n");
-  if (argc < 1) {
-    chprintf(chp, "Usage: %s\n","set_charging <enable>");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tenable\n");
-    chprintf(chp, "Whether to enable (1) or to disable (0) the power path controller of the DiWheelDrive board.\n");
-    chprintf(chp, "\n");
-    return;
-  }
-
-  const bool enable = atoi(argv[0]);
-  chprintf(chp, "%s power path controller\n", enable ? "enabling" : "disabling");
-  global.robot.getPowerStatus().charging_flags.content.diwheeldrive_enable_power_path = enable;
-
-  return;
-}
-
-void shellRequestPrintVCNL(BaseSequentialStream *chp, int argc, char *argv[]) {
-  chprintf(chp, "shellRequestPrintVCNL\n");
-  if (argc < 1) {
-    chprintf(chp, "Warning: no arguments specified.\n");
-    chprintf(chp, "Using default values (prints one measurement).\n");
-    chprintf(chp, "Type 'print_vcnl help' for help.\n");
-    chprintf(chp, "----------------------------------------\n");
-  }
-
-  if (strcmp(argv[0],"help") == 0) {
-    chprintf(chp, "Usage: %s\n","print_vcnl [<seconds>] [<frequency>]");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tseconds\n");
-    chprintf(chp, "Number of seconds to print the VCNL values. (default: 1)\n");
-    chprintf(chp, "\n");
-    chprintf(chp, "\tfrequency\n");
-    chprintf(chp, "Number prints per second. (default: 1)\n");
-    return;
-  }
-
-  const uint32_t seconds = (argc >= 1) ? atoi(argv[0]) : 1;
-  const uint32_t freq = (argc >= 2) ? atoi(argv[1]) : 1;
-
-  uint16_t ambient = 0;
-  uint16_t proximity = 0;
-
-  for (uint32_t loop = 0; loop < seconds*freq; ++loop) {
-    // Print proximity and ambilight values
-    for (uint8_t i = 0x00; i < global.vcnl4020.size(); ++i) {
-      ambient = global.vcnl4020[i].getAmbientLight();
-      proximity = global.vcnl4020[i].getProximity();
-      chprintf(chp, "#%d: ambient=0x%04X\tproximity=0x%04X\n", i, ambient, proximity);
-    }
-    chprintf(chp, "----------------------------------------\n");
-
-    BaseThread::sleep(US2ST(1000000 / freq));
-  }
-
-  return;
-}
-
-void shellSwitchBoardCmd(BaseSequentialStream *chp, int argc, char *argv[]) {
-  if (argc != 1) {
-    chprintf(chp, "Call with decimal numbers: shell_board <idx>\n");
-    return;
-  }
-  uint8_t boardIdx = static_cast<uint8_t>(atoi(argv[0]));
-
-  chprintf(chp, "shellSwitchBoardCmd\n");
-  global.sercanmux1.sendSwitchCmd(boardIdx);
-}
-
-void shellRequestGetBootloaderInfo(BaseSequentialStream* chp, int argc, char *argv[]) {
-  // check the magic number
-  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
-    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
-      break;
-
-    case BL_MAGIC_NUMBER:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
-      break;
-
-    default:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
-      break;
-  }
-
-  return;
-}
-
-void shellRequestWiiSteering(BaseSequentialStream* chp, int argc, char *argv[]) {
-  // if Wii steering is currently active, stop it
-  if (global.userThread.getCurrenState() == UserThread::WII_STEERING) {
-    global.userThread.setNextState(UserThread::IDLE);
-  }
-  // check arguments and (try to) enable Wii steering
-  else {
-    // if arguments invalid
-    if (argc < 1 || argc > 2 || global.userThread.setWiiAddress(argv[0]) != RDY_OK) {
-      chprintf(chp, "Warning: invalid arguments\n");
-      chprintf(chp, "Usage: %s\n", "wii_steering <address> [<deadzone>]");
-      chprintf(chp, "\n");
-      chprintf(chp, "\taddress\n");
-      chprintf(chp, "bluetooth address of the Wiimote controller to pair with.\n");
-      chprintf(chp, "\tdeadzone\n");
-      chprintf(chp, "deadzone to set for the Wiimote controller [default = 10%%].\n");
-      return;
-    }
-    else {
-      // set deadzone
-      const float deadzone = global.userThread.setWiiDeadzone((argc == 2) ? std::atof(argv[1]) : 0.1f);
-      chprintf(chp, "deadzone set to %u%%\n", (unsigned int)(deadzone * 100.0f));
-
-      // start Wii steering behaviour
-      global.userThread.setNextState(UserThread::WII_STEERING);
-    }
-  }
-  return;
-}
-
-static const ShellCommand commands[] = {
-  {"shutdown", shellRequestShutdown},
-  {"check", shellRequestCheck},
-  {"reset_memory", shellRequestResetMemory},
-  {"get_board_id", shellRequestGetBoardId},
-  {"set_board_id", shellRequestSetBoardId},
-  {"get_memory_data", shellRequestGetMemoryData},
-  {"get_vcnl", shellRequestGetVcnl},
-  {"calib_vcnl_offset", shellRequestCalib},
-  {"set_vcnl_offset", shellRequestSetVcnlOffset},
-  {"reset_vcnl_offset", shellRequestResetVcnlOffset},
-  {"get_vcnl_offset", shellRequestGetVcnlOffset},
-  {"get_robot_id", shellRequestGetRobotId},
-  {"get_system_load", shellRequestGetSystemLoad},
-  {"set_charging", shellRequestSetCharging},
-  {"print_vcnl", shellRequestPrintVCNL},
-  {"shell_board", shellSwitchBoardCmd},
-  {"get_bootloader_info", shellRequestGetBootloaderInfo},
-  {"wii_steering", shellRequestWiiSteering},
-  {NULL, NULL}
-};
-
-static const ShellConfig shell_cfg1 = {
-  (BaseSequentialStream *) &global.sercanmux1,
-  commands
-};
-
-void charger_logic() {
-  /*
-   * if supply connected, activate charger, else
-   * deactivate charger
-   */
-  if (global.ltc4412.isPluggedIn()) {
-    boardChargerSetState(0x03u, 1), chprintf((BaseSequentialStream*) &SD1, "Charging.\n");
-  } else {
-    boardChargerSetState(0x03u, 0), chprintf((BaseSequentialStream*) &SD1, "Not charging.\n");
-  }
-}
-
-void init_powermonitor(INA219::Driver &ina219, const float shunt_resistance_O, const float max_expected_current_A, const uint16_t current_lsb_uA)
-{
-  INA219::CalibData calib_data;
-  INA219::InitData init_data;
-
-  calib_data.input.configuration.content.brng = INA219::Configuration::BRNG_16V;
-  calib_data.input.configuration.content.pg = INA219::Configuration::PGA_40mV;
-  calib_data.input.configuration.content.badc = INA219::Configuration::ADC_68100us;
-  calib_data.input.configuration.content.sadc = INA219::Configuration::ADC_68100us;
-  calib_data.input.configuration.content.mode = INA219::Configuration::MODE_ShuntBus_Continuous;
-  calib_data.input.shunt_resistance_O = shunt_resistance_O;
-  calib_data.input.max_expected_current_A = max_expected_current_A;
-  calib_data.input.current_lsb_uA = current_lsb_uA;
-  if (ina219.calibration(&calib_data) != BaseSensor<>::SUCCESS)
-    chprintf((BaseSequentialStream*)&SD1, "WARNING: calibration of INA219 failed.\n");
-
-  init_data.configuration.value = calib_data.input.configuration.value;
-  init_data.calibration = calib_data.output.calibration_value;
-  init_data.current_lsb_uA = calib_data.output.current_lsb_uA;
-  if (ina219.init(&init_data) != BaseSensor<>::SUCCESS)
-    chprintf((BaseSequentialStream*)&SD1, "WARNING: initialization of INA219 failed.\n");
-
-  if (calib_data.input.current_lsb_uA != init_data.current_lsb_uA)
-  {
-    chprintf((BaseSequentialStream*)&SD1, "NOTE: LSB for current measurement was limited when initializing INA219 (%u -> %u)", calib_data.input.current_lsb_uA, init_data.current_lsb_uA);
-  }
-
-  return;
-}
-
-/*
- * Application entry point.
- */
-int main(void) {
-
-  Thread *shelltp = NULL;
-
-  /*
-   * System initializations.
-   * - HAL initialization, this also initializes the configured device drivers
-   *   and performs the board-specific initializations.
-   * - Kernel initialization, the main() function becomes a thread and the
-   *   RTOS is active.
-   */
-  halInit();
-  System::init();
-
-  /*
-   * TODO: detect the reason why the system was started by reading the 1st backup register of the RTC.
-   *       To do that, it is probably required to extend the RTC LLD by the required methods.
-   *       For further details, how to interprete the data in the backu register, please have a look at the bootloader project.
-   */
-
-  /*
-   * Activates the serial driver 1 using the driver default configuration.
-   */
-  sdStart(&SD1, &global.sd1_config);
-
-  chprintf((BaseSequentialStream*) &SD1, "\n");
-  chprintf((BaseSequentialStream*) &SD1, BOARD_NAME " " BOARD_VERSION "\n");
-  switch (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR))) {
-    case (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0)):
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor,
-               ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->patch);
-      break;
-
-    case BL_MAGIC_NUMBER:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader %u.%u.%u\n",
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))),
-               *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))));
-      break;
-
-    default:
-      chprintf((BaseSequentialStream*) &SD1, "Bootloader incompatible\n");
-      break;
-  }
-  chprintf((BaseSequentialStream*) &SD1, "ChibiOS " CH_KERNEL_VERSION "\n");
-  // make sure that the info text is completetly printed
-  BaseThread::sleep(10);
-
-//  boardWriteSystemPower(1);
-//  boardWriteIoPower(1);
-//  boardWriteWarmRestart(0);
-
-  global.robot.start(HIGHPRIO - 1);
-
-  pwmStart(&PWMD3, &global.pwm3_config);
-  pwmDisableChannel(&PWMD3, 1);
-
-  adcStart(&ADCD1, NULL);
-
-  extStart(&EXTD1, &extcfg);
-
-  boardClearI2CBus(GPIOB_GAUGE_SCL1, GPIOB_GAUGE_SDA1);
-  boardClearI2CBus(GPIOB_GAUGE_SCL2, GPIOB_GAUGE_SDA2);
-
-  global.HW_I2C1.start(&global.i2c1_config);
-  global.HW_I2C2.start(&global.i2c2_config);
-
-  uint16_t i2c_test = 0;
-  while (global.ina219[INA_VIO18].readRegister(INA219::Driver::REG_BUS_VOLTAGE, i2c_test) != RDY_OK) {
-    chprintf((BaseSequentialStream*)&global.sercanmux1, "I2C #1 stalled! trying to clear the bus... (this will take 20 seconds)\n");
-    boardWriteLed(1);
-    boardResetBQ27500I2C(GPIOB_GAUGE_SCL2, GPIOB_GAUGE_SDA2);
-    boardWriteLed(0);
-  }
-  while (global.ina219[INA_VDD].readRegister(INA219::Driver::REG_BUS_VOLTAGE, i2c_test) != RDY_OK) {
-    chprintf((BaseSequentialStream*)&global.sercanmux1, "I2C #2 stalled! trying to clear the bus... (this will take 20 seconds)\n");
-    boardWriteLed(1);
-    boardResetBQ27500I2C(GPIOB_GAUGE_SCL1, GPIOB_GAUGE_SDA1);
-    boardWriteLed(0);
-  }
-
-  global.memory.init();
-  uint8_t i = 0;
-  if (global.memory.getBoardId(&i) == fileSystemIo::FileSystemIoBase::OK) {
-    chprintf((BaseSequentialStream*) &SD1, "Board ID: %u\n", i);
-  } else {
-    chprintf((BaseSequentialStream*) &SD1, "Error reading board ID\n");
-  }
-  chprintf((BaseSequentialStream*) &SD1, "\n");
-
-  shelltp = shellCreate(&shell_cfg1, THD_WA_SIZE(1024), NORMALPRIO);
-
-  // initialize the power monitors
-  init_powermonitor(global.ina219[INA_VDD], 0.1f, 0.075f, 10);
-  init_powermonitor(global.ina219[INA_VIO18], 0.01f, 1.5f, 100);
-  init_powermonitor(global.ina219[INA_VIO33], 0.01f, 1.5f, 100);
-  init_powermonitor(global.ina219[INA_VIO42], 0.01f, 1.5f, 100);
-  init_powermonitor(global.ina219[INA_VIO50], 0.01f, 1.5f, 100);
-
-  // start the ADC watchdog
-  global.adc1_vsys.start(NORMALPRIO);
-
-  // start the ina threads
-  for (i = 0; i < global.ina219.size(); ++i)
-    global.ina219[i].start(NORMALPRIO);
-
-//  // calibrate the fuel gauges (TODO)
-//  BQ27500::CalibData bq27500_calib_data;
-//  bq27500_p7.calibration(&bq27500_calib_data);
-
-  // start the fuel gauge threads
-  for (i = 0; i < global.bq27500.size(); ++i)
-    global.bq27500[i].start(NORMALPRIO);
-
-  // start the proximity sensor threads
-  for (i = 0; i < global.vcnl4020.size(); ++i) {
-    uint16_t buffer;
-    global.memory.getVcnl4020Offset(&buffer,i);
-    global.vcnl4020[i].setProximityOffset(buffer);
-    global.vcnl4020[i].start(NORMALPRIO);
-  }
-
-  /* Start uart port connecting bluetooth chip */
-  global.wt12.bluetoothStart();
-
-  global.mpr121.configure(&global.mpr121_run_config);
-  global.mpr121.start(NORMALPRIO);
-
-  global.userThread.start(NORMALPRIO);
-
-  /* let the SYS_SYNC_N pin go, to signal that the initialization of the module is done */
-  palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_HIGH);
-
-  /* wait until all modules are done */
-  while (palReadPad(GPIOC, GPIOC_SYS_INT_N) == PAL_LOW) {
-    continue;
-  }
-
-  while (true) {
-
-    if (!shelltp)
-      shelltp = shellCreate(&shell_cfg1, THD_WA_SIZE(1024), NORMALPRIO);
-    else if (chThdTerminated(shelltp)) {
-      chThdRelease(shelltp); /* Recovers memory of the previous shell. */
-      shelltp = NULL; /* Triggers spawning of a new shell.      */
-    }
-
-    // Let the LED just blink as an alive signal
-    boardWriteLed(1);
-    BaseThread::sleep(MS2ST(250));
-    boardWriteLed(0);
-    BaseThread::sleep(MS2ST(250));
-
-    /*
-     * Charger logic before shutdown logic,
-     * so we don't need to call it twice.
-     */
-    if (pathdc_change) {
-      pathdc_change = 0x00u;
-//      charger_logic();
-    }
-
-    /*
-     * Shutdown logic before user logic,
-     * so user does not get hopes up and
-     * prepares wheels to drive into the
-     * next wall or something like that.
-     */
-    if (shutdown_now != SHUTDOWN_NONE) {
-      if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) && (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) != BL_MAGIC_NUMBER)) {
-        chprintf((BaseSequentialStream*) &SD1, "ERROR: unable to shut down (bootloader deprecated).\n");
-        shutdown_now = SHUTDOWN_NONE;
-      } else {
-        uint32_t blCallbackPtrAddr = BL_CALLBACK_TABLE_ADDR;
-        // handle bootloader version 0.2.x
-        if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
-            (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 2)) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 10 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-        // handle bootloader version 0.3.x
-        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == BL_MAGIC_NUMBER) &&
-                 (*((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (1*4))) == 0 && *((uint32_t*)(BL_CALLBACK_TABLE_ADDR + (2*4))) == 3)) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 7 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-              blCallbackPtrAddr += 8 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-        // handle bootloader version 1.0.x
-        else if ((*((uint32_t*)(BL_CALLBACK_TABLE_ADDR)) == (('A'<<24) | ('-'<<16) | ('B'<<8) | ('L'<<0))) &&
-                 ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->major == 1 && ((blVersion_t*)(BL_CALLBACK_TABLE_ADDR + (1*4)))->minor == 0) {
-          switch (shutdown_now) {
-            case SHUTDOWN_TRANSPORTATION:
-              blCallbackPtrAddr += 6 * 4;
-              break;
-            case SHUTDOWN_DEEPSLEEP:
-              blCallbackPtrAddr += 5 * 4;
-              break;
-            case SHUTDOWN_HIBERNATE:
-              blCallbackPtrAddr += 4 * 4;
-              break;
-            case SHUTDOWN_RESTART:
-              blCallbackPtrAddr += 7 * 4;
-              break;
-            case SHUTDOWN_HANDLE_REQUEST:
-              blCallbackPtrAddr += 8 * 4;
-              break;
-            default:
-              blCallbackPtrAddr = 0;
-              break;
-          }
-        }
-
-        void (*blCallback)(void) = NULL;
-        if (blCallbackPtrAddr > BL_CALLBACK_TABLE_ADDR) {
-          blCallback = (void (*)(void))(*((uint32_t*)blCallbackPtrAddr));
-
-          if (!blCallback) {
-            chprintf((BaseSequentialStream*) &SD1, "ERROR: Requested shutdown not supported.\n");
-            shutdown_now = SHUTDOWN_NONE;
-          } else {
-            chprintf((BaseSequentialStream*) &SD1, "initiating shutdown sequence...\n");
-            palWritePad(GPIOC, GPIOC_SYS_INT_N, PAL_LOW);
-            palWritePad(GPIOC, GPIOC_SYS_PD_N, PAL_LOW);
-
-            chprintf((BaseSequentialStream*) &SD1, "stopping all threads and periphery...");
-            systemStop();
-            chprintf((BaseSequentialStream*) &SD1, "\tdone\n");
-            BaseThread::sleep(MS2ST(10)); // sleep to print everything
-
-            blCallback();
-          }
-
-        } else {
-          chprintf((BaseSequentialStream*) &SD1, "ERROR: invalid shutdown requested (%u).\n", shutdown_now);
-          shutdown_now = SHUTDOWN_NONE;
-        }
-      }
-
-//      shutdown_now = 0x00u;
-//      if (palReadPad(GPIOC, GPIOC_PATH_DC))
-//        systemStop();
-//      else
-//        systemShutdown();
-//      //boardStop(0x00u, 0x00u);
-//      //chprintf((BaseSequentialStream*) &SD1, "Stop exit\n");
-    }
-
-  }
-
-  global.HW_I2C2.stop();
-  global.HW_I2C1.stop();
-
-  return 0;
-}
diff --git a/devices/PowerManagement/mcuconf.h b/devices/PowerManagement/mcuconf.h
deleted file mode 100644
index e1dc7a8..0000000
--- a/devices/PowerManagement/mcuconf.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * STM32F4xx drivers configuration.
- * The following settings override the default settings present in
- * the various device driver implementation headers.
- * Note that the settings for each driver only have effect if the whole
- * driver is enabled in halconf.h.
- *
- * IRQ priorities:
- * 15...0       Lowest...Highest.
- *
- * DMA priorities:
- * 0...3        Lowest...Highest.
- */
-
-#define STM32F4xx_MCUCONF
-
-/*
- * HAL driver system settings.
- */
-#define STM32_NO_INIT                       FALSE
-#define STM32_HSI_ENABLED                   TRUE
-#define STM32_LSI_ENABLED                   TRUE
-#define STM32_HSE_ENABLED                   TRUE
-#define STM32_LSE_ENABLED                   FALSE
-#define STM32_CLOCK48_REQUIRED              TRUE
-#define STM32_SW                            STM32_SW_PLL
-#define STM32_PLLSRC                        STM32_PLLSRC_HSE
-#define STM32_PLLM_VALUE                    8
-#define STM32_PLLN_VALUE                    336
-#define STM32_PLLP_VALUE                    2
-#define STM32_PLLQ_VALUE                    7
-#define STM32_HPRE                          STM32_HPRE_DIV1
-#define STM32_PPRE1                         STM32_PPRE1_DIV4
-#define STM32_PPRE2                         STM32_PPRE2_DIV2
-#define STM32_RTCSEL                        STM32_RTCSEL_LSI
-#define STM32_RTCPRE_VALUE                  8
-#define STM32_MCO1SEL                       STM32_MCO1SEL_HSI
-#define STM32_MCO1PRE                       STM32_MCO1PRE_DIV1
-#define STM32_MCO2SEL                       STM32_MCO2SEL_SYSCLK
-#define STM32_MCO2PRE                       STM32_MCO2PRE_DIV5
-#define STM32_I2SSRC                        STM32_I2SSRC_CKIN
-#define STM32_PLLI2SN_VALUE                 192
-#define STM32_PLLI2SR_VALUE                 5
-#define STM32_PVD_ENABLE                    FALSE
-#define STM32_PLS                           STM32_PLS_LEV0
-#define STM32_BKPRAM_ENABLE                 FALSE
-
-/*
- * ADC driver system settings.
- */
-#define STM32_ADC_ADCPRE                    ADC_CCR_ADCPRE_DIV4
-#define STM32_ADC_USE_ADC1                  TRUE
-#define STM32_ADC_USE_ADC2                  FALSE
-#define STM32_ADC_USE_ADC3                  FALSE
-#define STM32_ADC_ADC1_DMA_STREAM           STM32_DMA_STREAM_ID(2, 4)
-#define STM32_ADC_ADC2_DMA_STREAM           STM32_DMA_STREAM_ID(2, 2)
-#define STM32_ADC_ADC3_DMA_STREAM           STM32_DMA_STREAM_ID(2, 1)
-#define STM32_ADC_ADC1_DMA_PRIORITY         2
-#define STM32_ADC_ADC2_DMA_PRIORITY         2
-#define STM32_ADC_ADC3_DMA_PRIORITY         2
-#define STM32_ADC_IRQ_PRIORITY              6
-#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY     6
-#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY     6
-#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY     6
-
-/*
- * CAN driver system settings.
- */
-#define STM32_CAN_USE_CAN1                  TRUE
-#define STM32_CAN_USE_CAN2                  FALSE
-#define STM32_CAN_CAN1_IRQ_PRIORITY         11
-#define STM32_CAN_CAN2_IRQ_PRIORITY         11
-
-/*
- * EXT driver system settings.
- */
-#define STM32_EXT_EXTI0_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI1_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI2_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI3_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI4_IRQ_PRIORITY        6
-#define STM32_EXT_EXTI5_9_IRQ_PRIORITY      6
-#define STM32_EXT_EXTI10_15_IRQ_PRIORITY    6
-#define STM32_EXT_EXTI16_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI17_IRQ_PRIORITY       15
-#define STM32_EXT_EXTI18_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI19_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI20_IRQ_PRIORITY       6
-#define STM32_EXT_EXTI21_IRQ_PRIORITY       15
-#define STM32_EXT_EXTI22_IRQ_PRIORITY       15
-
-/*
- * GPT driver system settings.
- */
-#define STM32_GPT_USE_TIM1                  FALSE
-#define STM32_GPT_USE_TIM2                  FALSE
-#define STM32_GPT_USE_TIM3                  FALSE
-#define STM32_GPT_USE_TIM4                  FALSE
-#define STM32_GPT_USE_TIM5                  FALSE
-#define STM32_GPT_USE_TIM6                  FALSE
-#define STM32_GPT_USE_TIM7                  FALSE
-#define STM32_GPT_USE_TIM8                  FALSE
-#define STM32_GPT_USE_TIM9                  FALSE
-#define STM32_GPT_USE_TIM11                 FALSE
-#define STM32_GPT_USE_TIM12                 FALSE
-#define STM32_GPT_USE_TIM14                 FALSE
-#define STM32_GPT_TIM1_IRQ_PRIORITY         7
-#define STM32_GPT_TIM2_IRQ_PRIORITY         7
-#define STM32_GPT_TIM3_IRQ_PRIORITY         7
-#define STM32_GPT_TIM4_IRQ_PRIORITY         7
-#define STM32_GPT_TIM5_IRQ_PRIORITY         7
-#define STM32_GPT_TIM6_IRQ_PRIORITY         7
-#define STM32_GPT_TIM7_IRQ_PRIORITY         7
-#define STM32_GPT_TIM8_IRQ_PRIORITY         7
-#define STM32_GPT_TIM9_IRQ_PRIORITY         7
-#define STM32_GPT_TIM11_IRQ_PRIORITY        7
-#define STM32_GPT_TIM12_IRQ_PRIORITY        7
-#define STM32_GPT_TIM14_IRQ_PRIORITY        7
-
-/*
- * I2C driver system settings.
- */
-#define STM32_I2C_USE_I2C1                  TRUE
-#define STM32_I2C_USE_I2C2                  TRUE
-#define STM32_I2C_USE_I2C3                  FALSE
-#define STM32_I2C_I2C1_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 0)
-#define STM32_I2C_I2C1_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 6)
-#define STM32_I2C_I2C2_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 2)
-#define STM32_I2C_I2C2_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 7)
-#define STM32_I2C_I2C3_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 2)
-#define STM32_I2C_I2C3_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 4)
-#define STM32_I2C_I2C1_IRQ_PRIORITY         5
-#define STM32_I2C_I2C2_IRQ_PRIORITY         5
-#define STM32_I2C_I2C3_IRQ_PRIORITY         5
-#define STM32_I2C_I2C1_DMA_PRIORITY         3
-#define STM32_I2C_I2C2_DMA_PRIORITY         3
-#define STM32_I2C_I2C3_DMA_PRIORITY         3
-#define STM32_I2C_I2C1_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_I2C2_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_I2C3_DMA_ERROR_HOOK()     chSysHalt()
-#define STM32_I2C_USE_DMA                   TRUE
-
-/*
- * ICU driver system settings.
- */
-#define STM32_ICU_USE_TIM1                  FALSE
-#define STM32_ICU_USE_TIM2                  FALSE
-#define STM32_ICU_USE_TIM3                  FALSE
-#define STM32_ICU_USE_TIM4                  FALSE
-#define STM32_ICU_USE_TIM5                  FALSE
-#define STM32_ICU_USE_TIM8                  FALSE
-#define STM32_ICU_USE_TIM9                  FALSE
-#define STM32_ICU_TIM1_IRQ_PRIORITY         7
-#define STM32_ICU_TIM2_IRQ_PRIORITY         7
-#define STM32_ICU_TIM3_IRQ_PRIORITY         7
-#define STM32_ICU_TIM4_IRQ_PRIORITY         7
-#define STM32_ICU_TIM5_IRQ_PRIORITY         7
-#define STM32_ICU_TIM8_IRQ_PRIORITY         7
-#define STM32_ICU_TIM9_IRQ_PRIORITY         7
-
-/*
- * MAC driver system settings.
- */
-#define STM32_MAC_TRANSMIT_BUFFERS          2
-#define STM32_MAC_RECEIVE_BUFFERS           4
-#define STM32_MAC_BUFFERS_SIZE              1522
-#define STM32_MAC_PHY_TIMEOUT               100
-#define STM32_MAC_ETH1_CHANGE_PHY_STATE     TRUE
-#define STM32_MAC_ETH1_IRQ_PRIORITY         13
-#define STM32_MAC_IP_CHECKSUM_OFFLOAD       0
-
-/*
- * PWM driver system settings.
- */
-#define STM32_PWM_USE_ADVANCED              FALSE
-#define STM32_PWM_USE_TIM1                  FALSE
-#define STM32_PWM_USE_TIM2                  FALSE
-#define STM32_PWM_USE_TIM3                  TRUE
-#define STM32_PWM_USE_TIM4                  FALSE
-#define STM32_PWM_USE_TIM5                  FALSE
-#define STM32_PWM_USE_TIM8                  FALSE
-#define STM32_PWM_USE_TIM9                  FALSE
-#define STM32_PWM_TIM1_IRQ_PRIORITY         7
-#define STM32_PWM_TIM2_IRQ_PRIORITY         7
-#define STM32_PWM_TIM3_IRQ_PRIORITY         7
-#define STM32_PWM_TIM4_IRQ_PRIORITY         7
-#define STM32_PWM_TIM5_IRQ_PRIORITY         7
-#define STM32_PWM_TIM8_IRQ_PRIORITY         7
-#define STM32_PWM_TIM9_IRQ_PRIORITY         7
-
-/*
- * SERIAL driver system settings.
- */
-#define STM32_SERIAL_USE_USART1             TRUE
-#define STM32_SERIAL_USE_USART2             FALSE
-#define STM32_SERIAL_USE_USART3             FALSE
-#define STM32_SERIAL_USE_UART4              FALSE
-#define STM32_SERIAL_USE_UART5              FALSE
-#define STM32_SERIAL_USE_USART6             FALSE
-#define STM32_SERIAL_USART1_PRIORITY        12
-#define STM32_SERIAL_USART2_PRIORITY        12
-#define STM32_SERIAL_USART3_PRIORITY        12
-#define STM32_SERIAL_UART4_PRIORITY         12
-#define STM32_SERIAL_UART5_PRIORITY         12
-#define STM32_SERIAL_USART6_PRIORITY        12
-
-/*
- * SPI driver system settings.
- */
-#define STM32_SPI_USE_SPI1                  TRUE
-#define STM32_SPI_USE_SPI2                  FALSE
-#define STM32_SPI_USE_SPI3                  FALSE
-#define STM32_SPI_SPI1_RX_DMA_STREAM        STM32_DMA_STREAM_ID(2, 0)
-#define STM32_SPI_SPI1_TX_DMA_STREAM        STM32_DMA_STREAM_ID(2, 3)
-#define STM32_SPI_SPI2_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 3)
-#define STM32_SPI_SPI2_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 4)
-#define STM32_SPI_SPI3_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 0)
-#define STM32_SPI_SPI3_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 7)
-#define STM32_SPI_SPI1_DMA_PRIORITY         1
-#define STM32_SPI_SPI2_DMA_PRIORITY         1
-#define STM32_SPI_SPI3_DMA_PRIORITY         1
-#define STM32_SPI_SPI1_IRQ_PRIORITY         10
-#define STM32_SPI_SPI2_IRQ_PRIORITY         10
-#define STM32_SPI_SPI3_IRQ_PRIORITY         10
-#define STM32_SPI_DMA_ERROR_HOOK(spip)      chSysHalt()
-
-/*
- * UART driver system settings.
- */
-#define STM32_UART_USE_USART1               FALSE
-#define STM32_UART_USE_USART2               TRUE
-#define STM32_UART_USE_USART3               TRUE
-#define STM32_UART_USE_UART4                FALSE
-#define STM32_UART_USE_UART5                FALSE
-#define STM32_UART_USE_USART6               FALSE
-#define STM32_UART_USART1_RX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 5)
-#define STM32_UART_USART1_TX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 7)
-#define STM32_UART_USART2_RX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 5)
-#define STM32_UART_USART2_TX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 6)
-#define STM32_UART_USART3_RX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 1)
-#define STM32_UART_USART3_TX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 3)
-#define STM32_UART_UART4_RX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 2)
-#define STM32_UART_UART4_TX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 4)
-#define STM32_UART_UART5_RX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 0)
-#define STM32_UART_UART5_TX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 7)
-#define STM32_UART_USART6_RX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 2)
-#define STM32_UART_USART6_TX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 7)
-#define STM32_UART_USART1_IRQ_PRIORITY      12
-#define STM32_UART_USART2_IRQ_PRIORITY      12
-#define STM32_UART_USART3_IRQ_PRIORITY      12
-#define STM32_UART_UART4_IRQ_PRIORITY       12
-#define STM32_UART_UART5_IRQ_PRIORITY       12
-#define STM32_UART_USART6_IRQ_PRIORITY      12
-#define STM32_UART_USART1_DMA_PRIORITY      0
-#define STM32_UART_USART2_DMA_PRIORITY      0
-#define STM32_UART_USART3_DMA_PRIORITY      0
-#define STM32_UART_UART4_DMA_PRIORITY       0
-#define STM32_UART_UART5_DMA_PRIORITY       0
-#define STM32_UART_USART6_DMA_PRIORITY      0
-#define STM32_UART_DMA_ERROR_HOOK(uartp)    chSysHalt()
-
-/*
- * USB driver system settings.
- */
-#define STM32_USB_USE_OTG1                  FALSE
-#define STM32_USB_USE_OTG2                  FALSE
-#define STM32_USB_OTG1_IRQ_PRIORITY         14
-#define STM32_USB_OTG2_IRQ_PRIORITY         14
-#define STM32_USB_OTG1_RX_FIFO_SIZE         512
-#define STM32_USB_OTG2_RX_FIFO_SIZE         1024
-#define STM32_USB_OTG_THREAD_PRIO           LOWPRIO
-#define STM32_USB_OTG_THREAD_STACK_SIZE     128
-#define STM32_USB_OTGFIFO_FILL_BASEPRI      0
diff --git a/devices/PowerManagement/userthread.cpp b/devices/PowerManagement/userthread.cpp
deleted file mode 100644
index 94c0bf3..0000000
--- a/devices/PowerManagement/userthread.cpp
+++ /dev/null
@@ -1,431 +0,0 @@
-#include "userthread.h"
-
-#include "global.hpp"
-#include <array>
-#include <chprintf.h>
-#include <cmath>
-
-using namespace amiro;
-
-extern Global global;
-
-volatile UserThread::State current_state;
-volatile UserThread::State next_state;
-types::kinematic kinematic;
-
-namespace obstacle_avoidance {
-
-uint16_t constexpr proxThresholdLow = 0x0000;
-uint16_t constexpr proxThresholdHigh = 0x1000;
-uint16_t constexpr proxRange = proxThresholdHigh - proxThresholdLow;
-
-std::array< std::array<float, 2>, 8> constexpr namMatrix = {
-    /*                              x     w_z */
-    std::array<float, 2>/* SSW */{ 0.00f,  0.00f},
-    std::array<float, 2>/* WSW */{ 0.25f, -0.25f},
-    std::array<float, 2>/* WNW */{-0.75f, -0.50f},
-    std::array<float, 2>/* NNW */{-0.75f, -1.00f},
-    std::array<float, 2>/* NNE */{-0.75f,  1.00f},
-    std::array<float, 2>/* ENE */{-0.75f,  0.50f},
-    std::array<float, 2>/* ESE */{ 0.25f,  0.25f},
-    std::array<float, 2>/* SSE */{ 0.00f,  0.00f}
-};
-uint32_t constexpr baseTranslation = 100e3; // 2cm/s
-uint32_t constexpr baseRotation = 1e6; // 1rad/s
-types::kinematic constexpr defaultKinematic = {
-    /*  x  [µm/s]   */ baseTranslation,
-    /*  y  [µm/s]   */ 0,
-    /*  z  [µm/s]   */ 0,
-    /* w_x [µrad/s] */ 0,
-    /* w_y [µrad/s] */ 0,
-    /* w_z [µrad/s] */ 0
-};
-
-inline uint8_t ProxId2LedId(const uint8_t proxId) {
-    return (proxId < 4) ? proxId+4 : proxId-4;
-}
-
-Color Prox2Color(const float prox) {
-  float p = 0.0f;
-  if (prox < 0.5f) {
-    p = 2.0f * prox;
-    return Color(0x00, p*0xFF, (1.0f-p)*0xFF);
-  } else {
-    p = 2.0f * (prox - 0.5f);
-    return Color(p*0xFF, (1.0f-p)*0xFF, 0x00);
-  }
-}
-
-} /* namespace obstacle_avoidance */
-
-namespace wii_steering {
-
-BluetoothWiimote wiimote(&global.wt12, RX_TX);
-BluetoothSerial btserial(&global.wt12, RX_TX);
-
-float deadzone;
-char bt_address[18] = {'\0'};
-float wiimoteCalib[3] = {0.0f};
-uint8_t principal_axis = 1;
-int8_t axis_direction = -1;
-
-uint32_t constexpr maxTranslation = 500e3;
-uint32_t constexpr maxRotation = 3.1415927f * 1000000.0f * 2.0f;
-
-}
-
-UserThread::UserThread() :
-  chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>()
-{
-}
-
-UserThread::~UserThread()
-{
-}
-
-msg_t
-UserThread::main()
-{
-  /*
-   * initialize some variables
-   */
-  current_state = IDLE;
-
-  /*
-   * set all LEDs black (off)
-   */
-  for (uint8_t led = 0; led < 8; ++led) {
-    global.robot.setLightColor(led, Color(Color::BLACK));
-  }
-
-  /*
-   * thread loop
-   */
-  while (!this->shouldTerminate()) {
-    /*
-     * handle changes of the state
-     */
-    if (next_state != current_state) {
-      switch (current_state) {
-        case IDLE:
-        {
-          if (next_state == OBSTACLE_AVOIDANCE) {
-            // set all LEDs to white for one second
-            for (uint8_t led = 0; led < 8; ++led) {
-              global.robot.setLightColor(led, Color(Color::WHITE));
-            }
-            this->sleep(MS2ST(1000));
-            for (uint8_t led = 0; led < 8; ++led) {
-              global.robot.setLightColor(led, Color(Color::BLACK));
-            }
-          }
-          /* if (this->next_state == WII_STEERING) */ else {
-            // setup bluetooth
-            wii_steering::wiimote.bluetoothWiimoteListen(wii_steering::bt_address);
-            wii_steering::btserial.bluetoothSerialListen("ALL");
-
-            // set LEDs: front = green; rear = red; sides = blue
-            global.robot.setLightColor(constants::LightRing::LED_NNW, Color(Color::GREEN));
-            global.robot.setLightColor(constants::LightRing::LED_NNE, Color(Color::GREEN));
-            global.robot.setLightColor(constants::LightRing::LED_SSW, Color(Color::RED));
-            global.robot.setLightColor(constants::LightRing::LED_SSE, Color(Color::RED));
-            global.robot.setLightColor(constants::LightRing::LED_WNW, Color(Color::BLUE));
-            global.robot.setLightColor(constants::LightRing::LED_WSW, Color(Color::BLUE));
-            global.robot.setLightColor(constants::LightRing::LED_ENE, Color(Color::BLUE));
-            global.robot.setLightColor(constants::LightRing::LED_ESE, Color(Color::BLUE));
-
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "press buttons '1' and '2' to connect\n");
-          }
-          break;
-        }
-        case OBSTACLE_AVOIDANCE:
-        {
-          if (next_state == IDLE) {
-            // stop the robot
-            kinematic = {0, 0, 0, 0, 0, 0};
-            global.robot.setTargetSpeed(kinematic);
-
-            // set all LEDs to white for one second
-            for (uint8_t led = 0; led < 8; ++led) {
-              global.robot.setLightColor(led, Color(Color::WHITE));
-            }
-            this->sleep(MS2ST(1000));
-            for (uint8_t led = 0; led < 8; ++led) {
-              global.robot.setLightColor(led, Color(Color::BLACK));
-            }
-          }
-          /* if (this->next_state == WII_STEERING) */ else {
-            // must turn off obstacle avoidance first
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "ERROR: turn off obstacle avoidance first!\n");
-            next_state = OBSTACLE_AVOIDANCE;
-          }
-          break;
-        }
-        case WII_STEERING: {
-          if (next_state == IDLE) {
-            // stop the robot
-            kinematic = {0, 0, 0, 0, 0, 0};
-            global.robot.setTargetSpeed(kinematic);
-
-            // disconnect from Wiimote controller
-            wii_steering::wiimote.bluetoothWiimoteDisconnect(wii_steering::bt_address);
-            wii_steering::btserial.bluetoothSerialStop();
-            wii_steering::wiimote.bluetoothWiimoteStop();
-
-            // set all LEDs to black
-            for (uint8_t led = 0; led < 8; ++led) {
-              global.robot.setLightColor(led, Color(Color::BLACK));
-            }
-          }
-          /* if (this->next_state == OBSTACLE_AVOIDANCE) */ else {
-            // must turn off wii steering first
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "ERROR: turn off wii steering first!\n");
-            next_state = WII_STEERING;
-          }
-          break;
-        }
-      }
-      current_state = next_state;
-    }
-
-    // sleep here so the loop is executed as quickly as possible
-    this->sleep(CAN::UPDATE_PERIOD);
-
-    /*
-     * exeute behaviour depending on the current state
-     */
-    switch (current_state) {
-      case IDLE:
-      {
-        // read touch sensors
-        if (global.mpr121.getButtonStatus() == 0x0F) {
-          next_state = OBSTACLE_AVOIDANCE;
-        }
-        break;
-      }
-      case OBSTACLE_AVOIDANCE:
-      {
-        // read touch sensors
-        if (global.mpr121.getButtonStatus() == 0x0F) {
-          next_state = IDLE;
-          break;
-        }
-
-        // initialize some variables
-        uint8_t sensor = 0;
-        std::array<uint16_t, 8> proximity;
-        std::array<float, 8> proxNormalized;
-        float factor_x = 0.0f;
-        float factor_wz = 0.0f;
-
-        // read proximity values
-        for (sensor = 0; sensor < 8; ++sensor) {
-          proximity[sensor] = global.vcnl4020[sensor].getProximityScaledWoOffset();
-        }
-
-        // normalize proximity values
-        for (sensor = 0; sensor < 8; ++sensor) {
-          register uint16_t prox = proximity[sensor];
-          // limit to high treshold
-          if (prox > obstacle_avoidance::proxThresholdHigh)
-              prox = obstacle_avoidance::proxThresholdHigh;
-          // limit to low threshold
-          else if (prox < obstacle_avoidance::proxThresholdLow)
-              prox = obstacle_avoidance::proxThresholdLow;
-          // apply low threshold
-          prox -= obstacle_avoidance::proxThresholdLow;
-          // normalize to [0, 1]
-          proxNormalized[sensor] = float(prox) / float(obstacle_avoidance::proxRange);
-        }
-
-        // map the sensor values to the top LEDs
-        for (sensor = 0; sensor < 8; ++sensor) {
-          global.robot.setLightColor(obstacle_avoidance::ProxId2LedId(sensor), obstacle_avoidance::Prox2Color(proxNormalized[sensor]));
-        }
-
-        // evaluate NAM
-        for (sensor = 0; sensor < 8; ++sensor) {
-          factor_x += proxNormalized[sensor] * obstacle_avoidance::namMatrix[sensor][0];
-          factor_wz += proxNormalized[sensor] * obstacle_avoidance::namMatrix[sensor][1];
-        }
-
-        // set motor commands
-        kinematic = obstacle_avoidance::defaultKinematic;
-        kinematic.x += (factor_x * obstacle_avoidance::baseTranslation) + 0.5f;
-        kinematic.w_z += (factor_wz * obstacle_avoidance::baseRotation) + 0.5f;
-        global.robot.setTargetSpeed(kinematic);
-
-        break;
-      }
-      case WII_STEERING:
-      {
-        // if not yet connected to the Wiimote controller
-        if (!wii_steering::wiimote.bluetoothWiimoteIsConnected()) {
-          // try to connect
-          chprintf((BaseSequentialStream*)&global.sercanmux1, "connecting...\n");
-          wii_steering::wiimote.bluetoothWiimoteConnect(wii_steering::bt_address);
-
-          if (wii_steering::wiimote.bluetoothWiimoteIsConnected()) {
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "connection established\n");
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\n");
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "Wiimote control:\n");
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\tpress 'home' to calibrate\n");
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\thold 'A' to steer\n");
-          }
-        }
-        // steer AMiRo using the Wiimote controller like a joystick
-        else {
-          // initialize some variables
-          float wiimoteAcc[3] = {0.0f, 0.0f, 0.0f};
-
-          // get Wiimote accelerometer data
-          wiimoteAcc[0] = wii_steering::wiimote.getAccelerometer()->x_axis;
-          wiimoteAcc[1] = wii_steering::wiimote.getAccelerometer()->y_axis;
-          wiimoteAcc[2] = wii_steering::wiimote.getAccelerometer()->z_axis;
-
-          // calibrate accelerometer offset
-          if (wii_steering::wiimote.getButtons()->home) {
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "%f | %f | %f\n", wiimoteAcc[0], wiimoteAcc[1], wiimoteAcc[2]);
-
-            // detect principal axis
-            if (std::fabs(wiimoteAcc[0]) > std::fabs(wiimoteAcc[1]) && std::fabs(wiimoteAcc[0]) > std::fabs(wiimoteAcc[2])) {
-              wii_steering::principal_axis = 0;
-            } else if (std::fabs(wiimoteAcc[1]) > std::fabs(wiimoteAcc[0]) && std::fabs(wiimoteAcc[1]) > std::fabs(wiimoteAcc[2])) {
-              wii_steering::principal_axis = 1;
-            } else if (std::fabs(wiimoteAcc[2]) > std::fabs(wiimoteAcc[0]) && std::fabs(wiimoteAcc[2]) > std::fabs(wiimoteAcc[1])) {
-              wii_steering::principal_axis = 2;
-            }
-            wii_steering::axis_direction = (wiimoteAcc[wii_steering::principal_axis] >= 0) ? 1 : -1;
-
-            // get calibration offset
-            wii_steering::wiimoteCalib[0] = wiimoteAcc[0];
-            wii_steering::wiimoteCalib[1] = wiimoteAcc[1];
-            wii_steering::wiimoteCalib[2] = wiimoteAcc[2];
-            wii_steering::wiimoteCalib[wii_steering::principal_axis] += -100.0f * wii_steering::axis_direction;
-
-            // print information
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "accelerometer calibrated:\n");
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\tprincipal axis: %c\n", (wii_steering::principal_axis == 0) ? 'X' : (wii_steering::principal_axis == 1) ? 'Y' : 'Z');
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\tX = %d\n", (int32_t)wii_steering::wiimoteCalib[0]);
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\tY = %d\n", (int32_t)wii_steering::wiimoteCalib[1]);
-            chprintf((BaseSequentialStream*)&global.sercanmux1, "\tZ = %d\n", (int32_t)wii_steering::wiimoteCalib[2]);
-          }
-
-          for (uint8_t axis = 0; axis < 3; ++axis) {
-            // apply calibration values
-            wiimoteAcc[axis] -= wii_steering::wiimoteCalib[axis];
-
-            // normalize to (-1, 1)
-            wiimoteAcc[axis] /= 100.0f;
-
-            // limit to 1G
-            if (wiimoteAcc[axis] > 1.0f) {
-              wiimoteAcc[axis] = 1.0f;
-            } else if (wiimoteAcc[axis] < -1.0f) {
-              wiimoteAcc[axis] = -1.0f;
-            }
-
-            // apply deadzone
-            if (std::fabs(wiimoteAcc[axis]) < wii_steering::deadzone) {
-              wiimoteAcc[axis] = 0.0f;
-            }
-
-            /*
-             * the value is now in (-1 .. -deazone, 0, deadzone .. 1)
-             * note the gaps [-deadzone .. 0] and [0 .. deadzone]
-             */
-
-            // normalize (deadzone, 1) to (0, 1) and (-1, -deadzone) tpo (-1, 0)
-            if (wiimoteAcc[axis] > 0) {
-              wiimoteAcc[axis] -= wii_steering::deadzone;
-            } else if (wiimoteAcc[axis] < 0){
-              wiimoteAcc[axis] += wii_steering::deadzone;
-            }
-            wiimoteAcc[axis] *= (1.0f / (1.0f - wii_steering::deadzone));
-          }
-
-          // only move when A is pressed
-          if (wii_steering::wiimote.getButtons()->A || wii_steering::wiimote.getButtons()->B) {
-            // set kinematic relaive to maximum speeds
-            switch (wii_steering::principal_axis) {
-              case 1:
-                if (wii_steering::axis_direction == -1) {
-                  kinematic.x = wii_steering::maxTranslation * wiimoteAcc[2];
-                  kinematic.w_z = wii_steering::maxRotation * wiimoteAcc[0] * ((wiimoteAcc[2] < 0.0f) ? 1.0f : -1.0f);
-                  break;
-                }
-              case 2:
-                if (wii_steering::axis_direction == 1) {
-                  kinematic.x = wii_steering::maxTranslation * wiimoteAcc[1];
-                  kinematic.w_z = wii_steering::maxRotation * wiimoteAcc[0] * ((wiimoteAcc[1] < 0.0f) ? 1.0f : -1.0f);
-                  break;
-                }
-              default:
-                kinematic = {0, 0, 0, 0, 0, 0};
-                break;
-            }
-          } else {
-            kinematic = {0, 0, 0, 0, 0, 0};
-          }
-
-          // set speed
-          global.robot.setTargetSpeed(kinematic);
-        }
-
-        break;
-      }
-    }
-  }
-
-  // stop the robot
-  kinematic = {0, 0, 0, 0, 0, 0};
-  global.robot.setTargetSpeed(kinematic);
-
-  return RDY_OK;
-}
-
-void
-UserThread::setNextState(const UserThread::State state)
-{
-  next_state = state;
-  return;
-}
-
-UserThread::State
-UserThread::getCurrenState() const
-{
-  return current_state;
-}
-
-msg_t
-UserThread::setWiiAddress(const char* address)
-{
-  if (strlen(address) != 17) {
-    return RDY_RESET;
-  }
-  else {
-    strcpy(wii_steering::bt_address, address);
-    return RDY_OK;
-  }
-}
-
-float
-UserThread::setWiiDeadzone(const float deadzone)
-{
-  // check for negative value and limit to zero
-  float dz = (deadzone < 0.0f) ? 0.0f : deadzone;
-
-  // if value is >1, range is assumed to be (0, 100)
-  if (dz > 1.0f) {
-    // limit to 100
-    if (dz > 100.0f) {
-      dz = 100.0f;
-    }
-    dz /= 100.0f;
-  }
-
-  // set value and return it
-  wii_steering::deadzone = dz;
-  return dz;
-}
-
diff --git a/devices/PowerManagement/userthread.h b/devices/PowerManagement/userthread.h
deleted file mode 100644
index 2c2eeba..0000000
--- a/devices/PowerManagement/userthread.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef AMIRO_USERTHREAD_H_
-#define AMIRO_USERTHREAD_H_
-
-#include <ch.hpp>
-#include <amiroosconf.h>
-
-namespace amiro {
-
-class UserThread : public chibios_rt::BaseStaticThread<USER_THREAD_STACK_SIZE>
-{
-public:
-
-  enum State {
-    IDLE,
-    OBSTACLE_AVOIDANCE,
-    WII_STEERING,
-  };
-
-public:
-  explicit UserThread();
-
-  virtual ~UserThread();
-
-  virtual msg_t main();
-
-  void setNextState(const State state);
-
-  State getCurrenState() const;
-
-  msg_t setWiiAddress(const char* address);
-
-  float setWiiDeadzone(const float deadzone);
-};
-
-} // end of namespace amiro
-
-#endif // AMIRO_USERTHREAD_H_
diff --git a/devices/flash.mk b/devices/flash.mk
deleted file mode 100644
index e8cfdb7..0000000
--- a/devices/flash.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-DEVICES := DiWheelDrive PowerManagement LightRing
-
-DiWheelDrive := 1
-PowerManagement := 2
-LightRing := 3
-
-SERIALBOOT ?= $(dir $(abspath $(lastword $(MAKEFILE_LIST))))../../amiro-blt/Host/Source/SerialBoot/build/SerialBoot
-
-ifeq ($(OS),Windows_NT)
-	SERIALBOOT_PORT ?= COM4
-else
-	SERIALBOOT_PORT ?= /dev/ttyUSB0
-#	SERIALBOOT_PORT ?= /dev/rfcomm0
-endif
-SERIALBOOT_BAUDRATE ?= 115200
-#SERIALBOOT_BAUDRATE ?= 921600
-
-#SERIALBOOT_BT_ADDR ?= 00:00:00:00:00:00
-SERIALBOOT_BT_ADDR ?= 00:07:80:44:23:F9
-
-ifdef PROJECT
-	DEVICES :=
-	FLASHFILE = build/$(PROJECT).srec
-	FLASHTRGS = $(FLASHFILE)
-	FLASHARGS =  -T$($(PROJECT)) $(FLASHFILE)
-	FLASHARGSDIRECT = $(FLASHFILE)
-else
-	FLASHTRGS = $(foreach dev,$(DEVICES),$(dev)/build/$(dev).srec)
-	FLASHARGS = $(foreach dev,$(DEVICES),-T$($(dev)) $(dev)/build/$(dev).srec)
-	FLASHARGSDIRECT = $(foreach dev,$(DEVICES),$(dev)/build/$(dev).srec)
-endif
-
-flash: $(DEVICES) $(FLASHTRGS)
-	@echo Flashing
-	$(SERIALBOOT) -d$(SERIALBOOT_PORT) -b$(SERIALBOOT_BAUDRATE) $(FLASHARGS)
-
-flashdirect: $(DEVICES) $(FLASHTRGS)
-	@echo Flashing
-	$(SERIALBOOT) -d$(SERIALBOOT_PORT) -b$(SERIALBOOT_BAUDRATE) $(FLASHARGSDIRECT)
-
-flashbt: $(DEVICES) $(FLASHTRGS)
-	@echo Flashing over Bluetooth to $(SERIALBOOT_BT_ADDR)
-	$(SERIALBOOT) -a$(SERIALBOOT_BT_ADDR) $(FLASHARGS)
-
diff --git a/hal/hal.mk b/hal/hal.mk
deleted file mode 100644
index 266c9c0..0000000
--- a/hal/hal.mk
+++ /dev/null
@@ -1,6 +0,0 @@
-# List of all the ChibiOS/RT HAL files, there is no need to remove the files
-# from this list, you can disable parts of the kernel by editing halconf.h.
-HALSRC += ${AMIRO}/hal/src/qei.c 
-
-# Required include directories
-HALINC += ${AMIRO}/hal/include
diff --git a/hal/include/qei.h b/hal/include/qei.h
deleted file mode 100644
index 998030a..0000000
--- a/hal/include/qei.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * @file    qei.h
- * @brief   QEI Driver macros and structures.
- *
- * @addtogroup QEI
- * @{
- */
-
-#ifndef _QEI_H_
-#define _QEI_H_
-
-#if HAL_USE_QEI || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver constants.                                                         */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver pre-compile time settings.                                         */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Derived constants and error checks.                                       */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver data structures and types.                                         */
-/*===========================================================================*/
-
-/**
- * @brief   Driver state machine possible states.
- */
-typedef enum {
-  QEI_UNINIT = 0,                   /**< Not initialized.                   */
-  QEI_STOP = 1,                     /**< Stopped.                           */
-  QEI_READY = 2,                    /**< Ready.                             */
-  QEI_ACTIVE = 4,                   /**< Active.                            */
-} qeistate_t;
-
-/**
- * @brief   Type of a structure representing an QEI driver.
- */
-typedef struct QEIDriver QEIDriver;
-
-#include "qei_lld.h"
-
-/*===========================================================================*/
-/* Driver macros.                                                            */
-/*===========================================================================*/
-
-/**
- * @name    Macro Functions
- * @{
- */
-/**
- * @brief   Enables the quadrature encoder.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @iclass
- */
-#define qeiEnableI(qeip) qei_lld_enable(qeip)
-
-/**
- * @brief   Disables the quadrature encoder.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @iclass
- */
-#define qeiDisableI(qeip) qei_lld_disable(qeip)
-
-/**
- * @brief   Returns the direction of the last transition.
- * @details The direction is defined as boolean and is
- *          calculated at each transition on any input.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @return              The request direction.
- * @retval FALSE        Position counted up.
- * @retval TRUE         Position counted down.
- * @iclass
- */
-#define qeiGetDirectionI(qeip) qei_lld_get_direction(qeip)
-
-/**
- * @brief   Returns the position of the encoder.
- * @details The position is defined as number of pulses since last reset.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @return              The number of pulses.
- *
- * @iclass
- */
-#define qeiGetPositionI(qeip) qei_lld_get_position(qeip)
-
-/**
- * @brief   Returns the range of the encoder.
- * @details The range is defined as number of maximum pulse count.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @return              The number of pulses.
- *
- * @iclass
- */
-#define qeiGetRangeI(qeip) qei_lld_get_range(qeip)
-/** @} */
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void qeiInit(void);
-  void qeiObjectInit(QEIDriver *qeip);
-  void qeiStart(QEIDriver *qeip, const QEIConfig *config);
-  void qeiStop(QEIDriver *qeip);
-  void qeiEnable(QEIDriver *qeip);
-  void qeiDisable(QEIDriver *qeip);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* HAL_USE_QEI */
-
-#endif /* _QEI_H_ */
-
-/** @} */
diff --git a/hal/platforms/STM32/platform.mk b/hal/platforms/STM32/platform.mk
deleted file mode 100644
index ef40af2..0000000
--- a/hal/platforms/STM32/platform.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-# List of all the STM32F1xx platform files.
-PLATFORMSRC += ${AMIRO}/hal/platforms/STM32/qei_lld.c
-
-# Required include directories
-PLATFORMINC += ${AMIRO}/hal/platforms/STM32
diff --git a/hal/platforms/STM32/qei_lld.c b/hal/platforms/STM32/qei_lld.c
deleted file mode 100644
index 7b543e4..0000000
--- a/hal/platforms/STM32/qei_lld.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/**
- * @file    STM32/qei_lld.c
- * @brief   STM32 QEI subsystem low level driver.
- *
- * @addtogroup QEI
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-
-#include "qei.h"
-
-#if HAL_USE_QEI || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver exported variables.                                                */
-/*===========================================================================*/
-
-/**
- * @brief   QEID1 driver identifier.
- * @note    The driver QEID1 allocates the complex timer TIM1 when enabled.
- */
-#if STM32_QEI_USE_TIM1 || defined(__DOXYGEN__)
-QEIDriver QEID1;
-#endif
-
-/**
- * @brief   QEID2 driver identifier.
- * @note    The driver QEID1 allocates the timer TIM2 when enabled.
- */
-#if STM32_QEI_USE_TIM2 || defined(__DOXYGEN__)
-QEIDriver QEID2;
-#endif
-
-/**
- * @brief   QEID3 driver identifier.
- * @note    The driver QEID1 allocates the timer TIM3 when enabled.
- */
-#if STM32_QEI_USE_TIM3 || defined(__DOXYGEN__)
-QEIDriver QEID3;
-#endif
-
-/**
- * @brief   QEID4 driver identifier.
- * @note    The driver QEID4 allocates the timer TIM4 when enabled.
- */
-#if STM32_QEI_USE_TIM4 || defined(__DOXYGEN__)
-QEIDriver QEID4;
-#endif
-
-/**
- * @brief   QEID5 driver identifier.
- * @note    The driver QEID5 allocates the timer TIM5 when enabled.
- */
-#if STM32_QEI_USE_TIM5 || defined(__DOXYGEN__)
-QEIDriver QEID5;
-#endif
-
-/**
- * @brief   QEID8 driver identifier.
- * @note    The driver QEID8 allocates the timer TIM8 when enabled.
- */
-#if STM32_QEI_USE_TIM8 || defined(__DOXYGEN__)
-QEIDriver QEID8;
-#endif
-
-/*===========================================================================*/
-/* Driver local variables.                                                   */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions.                                                   */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver interrupt handlers.                                                */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions.                                                */
-/*===========================================================================*/
-
-/**
- * @brief   Low level QEI driver initialization.
- *
- * @notapi
- */
-void qei_lld_init(void) {
-
-#if STM32_QEI_USE_TIM1
-  /* Driver initialization.*/
-  qeiObjectInit(&QEID1);
-  QEID1.tim = STM32_TIM1;
-#endif
-
-#if STM32_QEI_USE_TIM2
-  /* Driver initialization.*/
-  qeiObjectInit(&QEID2);
-  QEID2.tim = STM32_TIM2;
-#endif
-
-#if STM32_QEI_USE_TIM3
-  /* Driver initialization.*/
-  qeiObjectInit(&QEID3);
-  QEID3.tim = STM32_TIM3;
-#endif
-
-#if STM32_QEI_USE_TIM4
-  /* Driver initialization.*/
-  qeiObjectInit(&QEID4);
-  QEID4.tim = STM32_TIM4;
-#endif
-
-#if STM32_QEI_USE_TIM5
-  /* Driver initialization.*/
-  qeiObjectInit(&QEID5);
-  QEID5.tim = STM32_TIM5;
-#endif
-
-#if STM32_QEI_USE_TIM8
-  /* Driver initialization.*/
-  qeiObjectInit(&QEID8);
-  QEID8.tim = STM32_TIM8;
-#endif
-}
-
-/**
- * @brief   Configures and activates the QEI peripheral.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @notapi
- */
-void qei_lld_start(QEIDriver *qeip) {
-  uint32_t arr, ccer;
-
-  if (qeip->state == QEI_STOP) {
-    /* Clock activation and timer reset.*/
-#if STM32_QEI_USE_TIM1
-    if (&QEID1 == qeip) {
-      rccEnableTIM1(FALSE);
-      rccResetTIM1();
-    }
-#endif
-#if STM32_QEI_USE_TIM2
-    if (&QEID2 == qeip) {
-      rccEnableTIM2(FALSE);
-      rccResetTIM2();
-    }
-#endif
-#if STM32_QEI_USE_TIM3
-    if (&QEID3 == qeip) {
-      rccEnableTIM3(FALSE);
-      rccResetTIM3();
-    }
-#endif
-#if STM32_QEI_USE_TIM4
-    if (&QEID4 == qeip) {
-      rccEnableTIM4(FALSE);
-      rccResetTIM4();
-    }
-#endif
-
-#if STM32_QEI_USE_TIM5
-    if (&QEID5 == qeip) {
-      rccEnableTIM5(FALSE);
-      rccResetTIM5();
-    }
-#endif
-#if STM32_QEI_USE_TIM8
-    if (&QEID8 == qeip) {
-      rccEnableTIM8(FALSE);
-      rccResetTIM8();
-    }
-#endif
-  }
-  else {
-    /* Driver re-configuration scenario, it must be stopped first.*/
-    qeip->tim->CR1    = 0;                  /* Timer disabled.              */
-    qeip->tim->DIER   = 0;                  /* All IRQs disabled.           */
-    qeip->tim->SR     = 0;                  /* Clear eventual pending IRQs. */
-    qeip->tim->CCR[0] = 0;                  /* Comparator 1 disabled.       */
-    qeip->tim->CCR[1] = 0;                  /* Comparator 2 disabled.       */
-    qeip->tim->CNT    = 0;                  /* Counter reset to zero.       */
-  }
-
-  /* Timer configuration.*/
-  qeip->tim->PSC  = 0;
-  arr = qeip->config->range - 1;
-  chDbgAssert((arr <= 0xFFFF), "qei_lld_start(), #1", "invalid range");
-  qeip->tim->ARR  = arr & 0xFFFF;
-
-  /* CCMR1_CC1S = 01 - CH1 Input on TI1.
-     CCMR1_CC2S = 01 - CH2 Input on TI2.*/
-  qeip->tim->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
-
-  ccer = 0;
-  if (qeip->config->channels[0].mode == QEI_INPUT_INVERTED)
-    ccer |= TIM_CCER_CC1P;
-  if (qeip->config->channels[1].mode == QEI_INPUT_INVERTED)
-    ccer |= TIM_CCER_CC2P;
-  qeip->tim->CCER = ccer;
-
-  if (qeip->config->mode == QEI_COUNT_CH1)
-    qeip->tim->SMCR  = TIM_SMCR_SMS_1;
-  else if (qeip->config->mode == QEI_COUNT_CH2)
-    qeip->tim->SMCR  = TIM_SMCR_SMS_0;
-  else
-    qeip->tim->SMCR  = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
-}
-
-/**
- * @brief   Deactivates the QEI peripheral.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @notapi
- */
-void qei_lld_stop(QEIDriver *qeip) {
-
-  if (qeip->state == QEI_READY) {
-    /* Clock deactivation.*/
-    qeip->tim->CR1  = 0;                    /* Timer disabled.              */
-
-#if STM32_QEI_USE_TIM1
-    if (&QEID1 == qeip) {
-      rccDisableTIM1(FALSE);
-    }
-#endif
-#if STM32_QEI_USE_TIM2
-    if (&QEID2 == qeip) {
-      rccDisableTIM2(FALSE);
-    }
-#endif
-#if STM32_QEI_USE_TIM3
-    if (&QEID3 == qeip) {
-      rccDisableTIM3(FALSE);
-    }
-#endif
-#if STM32_QEI_USE_TIM4
-    if (&QEID4 == qeip) {
-      rccDisableTIM4(FALSE);
-    }
-#endif
-#if STM32_QEI_USE_TIM5
-    if (&QEID5 == qeip) {
-      rccDisableTIM5(FALSE);
-    }
-#endif
-  }
-#if STM32_QEI_USE_TIM8
-    if (&QEID8 == qeip) {
-      rccDisableTIM8(FALSE);
-    }
-#endif
-}
-
-/**
- * @brief   Enables the quadrature encoder.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @notapi
- */
-void qei_lld_enable(QEIDriver *qeip) {
-
-  qeip->tim->CR1  = TIM_CR1_CEN;
-}
-
-/**
- * @brief   Disables the quadrature encoder.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @notapi
- */
-void qei_lld_disable(QEIDriver *qeip) {
-
-  qeip->tim->CR1  = 0;
-}
-
-#endif /* HAL_USE_QEI */
-
-/** @} */
diff --git a/hal/platforms/STM32/qei_lld.h b/hal/platforms/STM32/qei_lld.h
deleted file mode 100644
index a56db69..0000000
--- a/hal/platforms/STM32/qei_lld.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/**
- * @file    STM32/qei_lld.h
- * @brief   STM32 QEI subsystem low level driver header.
- *
- * @addtogroup QEI
- * @{
- */
-
-#ifndef _QEI_LLD_H_
-#define _QEI_LLD_H_
-
-#include "stm32_tim.h"
-
-#if HAL_USE_QEI || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver constants.                                                         */
-/*===========================================================================*/
-
-/**
- * @brief   Number of input channels per QEI driver.
- */
-#define QEI_CHANNELS                            2
-
-/*===========================================================================*/
-/* Driver pre-compile time settings.                                         */
-/*===========================================================================*/
-
-/**
- * @name    Configuration options
- * @{
- */
-/**
- * @brief   QEID1 driver enable switch.
- * @details If set to @p TRUE the support for QEID1 is included.
- * @note    The default is @p TRUE.
- */
-#if !defined(STM32_QEI_USE_TIM1) || defined(__DOXYGEN__)
-#define STM32_QEI_USE_TIM1                  TRUE
-#endif
-
-/**
- * @brief   QEID2 driver enable switch.
- * @details If set to @p TRUE the support for QEID2 is included.
- * @note    The default is @p TRUE.
- */
-#if !defined(STM32_QEI_USE_TIM2) || defined(__DOXYGEN__)
-#define STM32_QEI_USE_TIM2                  TRUE
-#endif
-
-/**
- * @brief   QEID3 driver enable switch.
- * @details If set to @p TRUE the support for QEID3 is included.
- * @note    The default is @p TRUE.
- */
-#if !defined(STM32_QEI_USE_TIM3) || defined(__DOXYGEN__)
-#define STM32_QEI_USE_TIM3                  TRUE
-#endif
-
-/**
- * @brief   QEID4 driver enable switch.
- * @details If set to @p TRUE the support for QEID4 is included.
- * @note    The default is @p TRUE.
- */
-#if !defined(STM32_QEI_USE_TIM4) || defined(__DOXYGEN__)
-#define STM32_QEI_USE_TIM4                  TRUE
-#endif
-
-/**
- * @brief   QEID5 driver enable switch.
- * @details If set to @p TRUE the support for QEID5 is included.
- * @note    The default is @p TRUE.
- */
-#if !defined(STM32_QEI_USE_TIM5) || defined(__DOXYGEN__)
-#define STM32_QEI_USE_TIM5                  TRUE
-#endif
-
-/**
- * @brief   QEID8 driver enable switch.
- * @details If set to @p TRUE the support for QEID8 is included.
- * @note    The default is @p TRUE.
- */
-#if !defined(STM32_QEI_USE_TIM8) || defined(__DOXYGEN__)
-#define STM32_QEI_USE_TIM8                  TRUE
-#endif
-/** @} */
-
-/*===========================================================================*/
-/* Derived constants and error checks.                                       */
-/*===========================================================================*/
-
-#if STM32_QEI_USE_TIM1 && !STM32_HAS_TIM1
-#error "TIM1 not present in the selected device"
-#endif
-
-#if STM32_QEI_USE_TIM2 && !STM32_HAS_TIM2
-#error "TIM2 not present in the selected device"
-#endif
-
-#if STM32_QEI_USE_TIM3 && !STM32_HAS_TIM3
-#error "TIM3 not present in the selected device"
-#endif
-
-#if STM32_QEI_USE_TIM4 && !STM32_HAS_TIM4
-#error "TIM4 not present in the selected device"
-#endif
-
-#if STM32_QEI_USE_TIM5 && !STM32_HAS_TIM5
-#error "TIM5 not present in the selected device"
-#endif
-
-#if STM32_QEI_USE_TIM8 && !STM32_HAS_TIM8
-#error "TIM8 not present in the selected device"
-#endif
-
-#if !STM32_QEI_USE_TIM1 && !STM32_QEI_USE_TIM2 &&                           \
-    !STM32_QEI_USE_TIM3 && !STM32_QEI_USE_TIM4 &&                           \
-    !STM32_QEI_USE_TIM5 && !STM32_QEI_USE_TIM8
-#error "QEI driver activated but no TIM peripheral assigned"
-#endif
-
-/*===========================================================================*/
-/* Driver data structures and types.                                         */
-/*===========================================================================*/
-
-/**
- * @brief QEI driver mode.
- */
-typedef enum {
-  QEI_COUNT_BOTH = 0,
-  QEI_COUNT_CH1 = 1,
-  QEI_COUNT_CH2 = 2,
-} qeimode_t;
-
-/**
- * @brief QEI input mode.
- */
-typedef enum {
-  QEI_INPUT_NONINVERTED = 0, /**< Input channel noninverted.*/
-  QEI_INPUT_INVERTED = 1, /**< Input channel inverted.*/
-} qeiinputmode_t;
-
-/**
- * @brief   QEI count type.
- */
-typedef uint32_t qeicnt_t;
-
-/**
- * @brief   Driver channel configuration structure.
- */
-typedef struct {
-  /**
-   * @brief Channel input logic.
-   */
-  qeiinputmode_t                 mode;
-  /* End of the mandatory fields.*/
-} QEIChannelConfig;
-
-/**
- * @brief   Driver configuration structure.
- */
-typedef struct {
-  /**
-   * @brief   Driver mode.
-   */
-  qeimode_t                 mode;
-  /**
-   * @brief   Channels configurations.
-   */
-  QEIChannelConfig          channels[QEI_CHANNELS];
-  /**
-   * @brief   Range in pulses.
-   */
-  qeicnt_t                  range;
-  /* End of the mandatory fields.*/
-} QEIConfig;
-
-/**
- * @brief   Structure representing an QEI driver.
- */
-struct QEIDriver {
-  /**
-   * @brief Driver state.
-   */
-  qeistate_t                state;
-  /**
-   * @brief Current configuration data.
-   */
-  const QEIConfig           *config;
-#if defined(QEI_DRIVER_EXT_FIELDS)
-  QEI_DRIVER_EXT_FIELDS
-#endif
-  /* End of the mandatory fields.*/
-  /**
-   * @brief Pointer to the TIMx registers block.
-   */
-  stm32_tim_t               *tim;
-};
-
-/*===========================================================================*/
-/* Driver macros.                                                            */
-/*===========================================================================*/
-
-/**
- * @brief   Returns the direction of the last transition.
- * @details The direction is defined as boolean and is
- *          calculated at each transition on any input.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @return              The request direction.
- * @retval FALSE        Position counted up.
- * @retval TRUE         Position counted down.
- *
- * @iclass
- */
-#define qei_lld_get_direction(qeip) !!((qeip)->tim->CR1 & TIM_CR1_DIR)
-
-/**
- * @brief   Returns the position of the encoder.
- * @details The position is defined as number of pulses since last reset.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @return              The number of pulses.
- *
- * @iclass
- */
-#define qei_lld_get_position(qeip) ((qeip)->tim->CNT)
-
-/**
- * @brief   Returns the range of the encoder.
- * @details The range is defined as number of maximum pulse count.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @return              The number of pulses.
- *
- * @iclass
- */
-#define qei_lld_get_range(qeip) ((qeip)->tim->ARR + 1)
-
-/*===========================================================================*/
-/* External declarations.                                                    */
-/*===========================================================================*/
-
-#if STM32_QEI_USE_TIM1 && !defined(__DOXYGEN__)
-extern QEIDriver QEID1;
-#endif
-
-#if STM32_QEI_USE_TIM2 && !defined(__DOXYGEN__)
-extern QEIDriver QEID2;
-#endif
-
-#if STM32_QEI_USE_TIM3 && !defined(__DOXYGEN__)
-extern QEIDriver QEID3;
-#endif
-
-#if STM32_QEI_USE_TIM4 && !defined(__DOXYGEN__)
-extern QEIDriver QEID4;
-#endif
-
-#if STM32_QEI_USE_TIM5 && !defined(__DOXYGEN__)
-extern QEIDriver QEID5;
-#endif
-
-#if STM32_QEI_USE_TIM8 && !defined(__DOXYGEN__)
-extern QEIDriver QEID8;
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-  void qei_lld_init(void);
-  void qei_lld_start(QEIDriver *qeip);
-  void qei_lld_stop(QEIDriver *qeip);
-  void qei_lld_enable(QEIDriver *qeip);
-  void qei_lld_disable(QEIDriver *qeip);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* HAL_USE_QEI */
-
-#endif /* _QEI_LLD_H_ */
-
-/** @} */
diff --git a/hal/src/qei.c b/hal/src/qei.c
deleted file mode 100644
index 9207a0a..0000000
--- a/hal/src/qei.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * @file    qei.c
- * @brief   QEI Driver code.
- *
- * @addtogroup QEI
- * @{
- */
-
-#include "ch.h"
-#include "hal.h"
-#include "qei.h"
-
-#if HAL_USE_QEI || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver local definitions.                                                 */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported variables.                                                */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local variables.                                                   */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions.                                                   */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions.                                                */
-/*===========================================================================*/
-
-/**
- * @brief   QEI Driver initialization.
- * @note    This function is implicitly invoked by @p halInit(), there is
- *          no need to explicitly initialize the driver.
- *
- * @init
- */
-void qeiInit(void) {
-
-  qei_lld_init();
-}
-
-/**
- * @brief   Initializes the standard part of a @p QEIDriver structure.
- *
- * @param[out] qeip     pointer to the @p QEIDriver object
- *
- * @init
- */
-void qeiObjectInit(QEIDriver *qeip) {
-
-  qeip->state  = QEI_STOP;
-  qeip->config = NULL;
-}
-
-/**
- * @brief   Configures and activates the QEI peripheral.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- * @param[in] config    pointer to the @p QEIConfig object
- *
- * @api
- */
-void qeiStart(QEIDriver *qeip, const QEIConfig *config) {
-
-  chDbgCheck((qeip != NULL) && (config != NULL), "qeiStart");
-
-  chSysLock();
-  chDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY),
-              "qeiStart(), #1", "invalid state");
-  qeip->config = config;
-  qei_lld_start(qeip);
-  qeip->state = QEI_READY;
-  chSysUnlock();
-}
-
-/**
- * @brief   Deactivates the QEI peripheral.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @api
- */
-void qeiStop(QEIDriver *qeip) {
-
-  chDbgCheck(qeip != NULL, "qeiStop");
-
-  chSysLock();
-  chDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY),
-              "qeiStop(), #1", "invalid state");
-  qei_lld_stop(qeip);
-  qeip->state = QEI_STOP;
-  chSysUnlock();
-}
-
-/**
- * @brief   Enables the quadrature encoder.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @api
- */
-void qeiEnable(QEIDriver *qeip) {
-
-  chDbgCheck(qeip != NULL, "qeiEnable");
-
-  chSysLock();
-  chDbgAssert(qeip->state == QEI_READY, "qeiEnable(), #1", "invalid state");
-  qei_lld_enable(qeip);
-  qeip->state = QEI_ACTIVE;
-  chSysUnlock();
-}
-
-/**
- * @brief   Disables the quadrature encoder.
- *
- * @param[in] qeip      pointer to the @p QEIDriver object
- *
- * @api
- */
-void qeiDisable(QEIDriver *qeip) {
-
-  chDbgCheck(qeip != NULL, "qeiDisable");
-
-  chSysLock();
-  chDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE),
-              "qeiDisable(), #1", "invalid state");
-  qei_lld_disable(qeip);
-  qeip->state = QEI_READY;
-  chSysUnlock();
-}
-
-#endif /* HAL_USE_QEI */
-
-/** @} */
diff --git a/ide/qtcreator/README.txt b/ide/qtcreator/README.txt
deleted file mode 100644
index 3df7781..0000000
--- a/ide/qtcreator/README.txt
+++ /dev/null
@@ -1,67 +0,0 @@
-SETTING UP AN AMIRO-OS PROJECT FOR QT-CREATOR
-=============================================
-
-1 - Creating the Project Files
-------------------------------
-Run the "setup.sh" script in this directory and follow the instructions.
-  > ./setup.sh
-
-
-
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-! THAT'S IT for the basic setup.                                                     !
-! The next steps are only necessary, if you want to integrate 'make' into QtCreator, !
-! or if QtCreator crashes when opening the projects.                                 !
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-
-
-2 - Setup the AMiRo build environment for QtCreator
----------------------------------------------------
-Launch the QtCreator application, click on
-  Tools -> Options
-and select "Build & Run".
-
-Under the tab "Compilers" add the arm-none-eabi-g++ compiler as another GCC.
-
-Under the tab "Debuggers" add the arm-none-eabi-gdb debugger.
-
-Under the tab "Kits" manually create a new kit:
-  Name: AMiRo
-  Device type: Desktop
-  Sysroot: [gcc-arm-none-eabi include path]
-  Compiler: [the compiler added above]
-  Environment: SERIALBOOT=[absolute path to the SerialBoot binary]
-  Debugger: [the debugger added above]
-  QT version: none
-With everything else empty or default.
-If there is a warning sign shown right beside the new kit, check the setup for errors.
-
-
-
-3 - Open the Project(s) with QtCreator
---------------------------------------
-For convenience, the absolute path to your device (e.g. /home/juser/amiro-os/devices/PowerManagement)
-will be referenced in the following by "MOD_PATH".
-
-In the QtCreator application, click on
-  File -> Open File or Project
-and open the according *.creator file.
-
-Select the project in the "Projects" view and click on the "Projects" icon on the very left.
-Switch to the "Build & Run" tab.
-
-Change the kit to "AMiRo" (right above the "Build" and "Run" buttons).
-
-Add a new build configuration and call it "make".
-  Build directory: MOD_PATH
-  Build Steps: make --directory=MOD_PATH all
-  Clean Steps: make --directory=MOD_PATH clean
-Optionally you can add "-j" to the build setp in order to parallelize the compilation process.
-
-Add another new build configuration by cloning the new "make" configuration and call t "make flash".
-Replace "all" at the end of the Build Step with "flash"
-
-Remove the "Default" build configuration.
-
-Repeat this step for reach further project.
diff --git a/ide/qtcreator/setup.sh b/ide/qtcreator/setup.sh
deleted file mode 100755
index cd2bac9..0000000
--- a/ide/qtcreator/setup.sh
+++ /dev/null
@@ -1,484 +0,0 @@
-#!/bin/bash
-
-############################
-###   HELPER FUNCTIONS   ###
-############################
-
-function absoluteToRelativePath {
-  # both $1 and $2 are absolute paths beginning with /
-  # stores the relative path from $1/START_PATH to $2/TARGET_PATH in $3/RESULT_PATH or echoes it
-
-  START_PATH=$1
-  TARGET_PATH=$2
-
-  # check whether one of both paths ends with / and remove it for now
-  ENDS_WITH_SLASH=false
-  while [ "${START_PATH%"/"}" != "$START_PATH" ]; do
-    START_PATH=${START_PATH::-1}
-    ENDS_WITH_SLASH=true
-  done
-  while [ "${TARGET_PATH%"/"}" != "$TARGET_PATH" ]; do
-    TARGET_PATH=${TARGET_PATH::-1}
-    ENDS_WITH_SLASH=true
-  done
-
-  # initialize the common prefix and the relative path from START_PATH to TARGET_PATH
-  COMMON_PREFIX=$START_PATH
-  RELATIVE_PATH=""
-  while [ "${TARGET_PATH#$COMMON_PREFIX}" == "$TARGET_PATH" ]; do
-    # while the COMMOM_PREFIX is no substring of TARGET_PATH, reduce it
-    COMMON_PREFIX="$(dirname $COMMON_PREFIX)"
-
-    # thereby record the relative path
-    if [ -z $RELATIVE_PATH ]; then
-      RELATIVE_PATH=".."
-    else
-      RELATIVE_PATH="../$RELATIVE_PATH"
-    fi
-  done
-
-  # if the reltiva path is empty, set it as the current directory
-  if [ -z $RELATIVE_PATH ]; then
-    RELATIVE_PATH="."
-  fi
-
-  if [ $COMMON_PREFIX == "/" ]; then
-    # special case if only root is the common path
-    RELATIVE_PATH="$RELATIVE_PATH/"
-  fi
-
-  # compute the unique part of the target path
-  UNIQUE_POSTFIX="${TARGET_PATH#$COMMON_PREFIX}"
-
-  # append the unique postfix to the relative path
-  if [ -n $RELATIVE_PATH ] && [ -n $UNIQUE_POSTFIX ]; then
-    RELATIVE_PATH="$RELATIVE_PATH$UNIQUE_POSTFIX"
-  elif [ -n $UNIQUE_POSTFIX ]; then
-    # remove the slash
-    RELATIVE_PATH="${UNIQUE_POSTFIX:1}"
-  fi
-
-  # remove a prepending slash if any
-  if [ "${RELATIVE_PATH#"/"}" != "$RELATIVE_PATH" ]; then
-    RELATIVE_PATH=${RELATIVE_PATH:1}
-  fi
-
-  # if at least one input ended with a slash, add it to the result as well
-  if [ $ENDS_WITH_SLASH == true ]; then
-    RELATIVE_PATH="${RELATIVE_PATH}/"
-  fi
-
-  # return the result
-  if [ $# -gt 2 ]; then
-    eval $3="$RELATIVE_PATH"
-  else
-    echo $RELATIVE_PATH
-  fi
-
-  # clean up
-  unset START_PATH
-  unset TARGET_PATH
-  unset ENDS_WITH_SLASH
-  unset COMMON_PREFIX
-  unset RELATIVE_PATH
-  unset UNIQUE_POSTFIX
-}
-
-
-function cleanupVariables {
-
-  unset HELP_FLAG
-  unset CLEAN_FLAG
-  unset WIPE_FLAG
-  unset CHOS
-  unset LR
-  unset PM
-  unset DWD
-  unset ARG_LIST
-
-  unset USER_DIR
-  unset SCRIPT_DIR
-
-  unset GCC_ARM_NONE_EABI_INCLUDE_PATH
-  unset PROJECT_ROOT_PATH
-  unset AMIROOS_ROOT_PATH
-  unset CHIBIOS_ROOT_PATH
-
-  unset CHIBIOS_PROJECT_PREFIX
-  unset LIGHTRING_PROJECT_PREFIX
-  unset POWERMANAGEMENT_PROJECT_PREFIX
-  unset DIWHEELDRIVE_PROJECT_PREFIX
-
-  unset PROJECT_ROOT_TO_CHIBIOS
-  unset PROJECT_ROOT_TO_AMIROOS
-}
-
-
-#################
-###   INTRO   ###
-#################
-
-echo "-------------------------------------------------------------------------------"
-echo ""
-echo "Setup to create QtCreator projects"
-echo "=================================="
-echo ""
-
-
-
-##########################
-###   INITIALIZATION   ###
-##########################
-
-# ignore case when comparing strings
-shopt -s nocasematch
-
-# detect what exactly should be done
-HELP_FLAG="HELP"
-CLEAN_FLAG="CLEAN"
-WIPE_FLAG="WIPE"
-CHIBIOS_FLAG="CHOS"
-LIGHTRING_FLAG="LR"
-POWERMANAGEMENT_FLAG="PM"
-DIWHEELDRIVE_FLAG="DWD"
-
-# start with an empty array
-ARG_LIST=()
-if [ $# == 0 ]; then
-  # if no argument was specified, 'help' is considered as default
-  ARG_LIST+=($HELP_FLAG)
-else
-  for ARG in "$@"; do
-    case ${ARG,,} in
-      "help"|"-help"|"--help")
-        ARG_LIST+=($HELP_FLAG)
-        ;;
-      "clean")
-        ARG_LIST+=($CLEAN_FLAG)
-        ;;
-      "wipe")
-        ARG_LIST+=($WIPE_FLAG)
-        ;;
-      "all")
-        ARG_LIST+=($LIGHTRING_FLAG $POWERMANAGEMENT_FLAG $DIWHEELDRIVE_FLAG)
-        ;;
-      "ChibiOS")
-        ArrayContainsElement "${ARG_LIST[@]}" "$CHIBIOS_FLAG"
-        if [ $? != 1 ]; then
-          ARG_LIST+=($CHIBIOS_FLAG)
-        fi
-        ;;
-      "LightRing")
-        ArrayContainsElement "${ARG_LIST[@]}" "$LIGHTRING_FLAG"
-        if [ $? != 1 ]; then
-          ARG_LIST+=($LIGHTRING_FLAG)
-        fi
-        ;;
-      "PowerManagement")
-        ArrayContainsElement "${ARG_LIST[@]}" "$POWERMANAGEMENT_FLAG"
-        if [ $? != 1 ]; then
-          ARG_LIST+=($POWERMANAGEMENT_FLAG)
-        fi
-        ;;
-      "DiWheelDrive")
-        ArrayContainsElement "{$ARG_LIST[@]}" "DIWHEELDRIVE_FLAG"
-        if [ $? != 1 ]; then
-          ARG_LIST+=($DIWHEELDRIVE_FLAG)
-        fi
-        ;;
-    esac
-  done
-fi
-
-
-
-######################
-###   PRINT HELP   ###
-######################
-
-if [[ "${ARG_LIST[@]}" == *"$HELP_FLAG"* ]]; then
-    echo -e "> HELP"
-    echo -e ""
-    echo -e "\tThe following commands are available:"
-    echo -e ""
-    echo -e "\t  help            - Prints this help text."
-    echo -e "\t  clean           - Deletes all files created by this script."
-    echo -e "\t  wipe            - Deletes the .user files, created by QtCreator."
-    echo -e "\t  ChibiOS         - Creates a project for ChibiOS."
-    echo -e "\t  LightRing       - Creates a project for the LightRing module."
-    echo -e "\t  PowerManagement - Creates a project for the PowerManagement module."
-    echo -e "\t  DiWheelDrive    - Creates a project for the DiWheelDrive module."
-    echo -e "\t  all             - Creates all three projects (no ChibiOS project)."
-    echo -e ""
-    echo -e "\tAny of these commands can be combined, e.g."
-    echo -e "\t  $> ./setup.sh PowerManagement ChibiOS"
-    echo -e "\twill create two projects."
-    echo -e ""
-    echo -e "-------------------------------------------------------------------------------"
-
-    cleanupVariables
-    exit
-fi
-
-
-
-#########################
-###   CONFIGURATION   ###
-#########################
-
-USER_DIR=${PWD}
-cd $(dirname ${BASH_SOURCE[0]})
-SCRIPT_DIR=${PWD}
-cd $USER_DIR
-
-### the include path for GCC specific headers
-GCC_ARM_NONE_EABI_INCLUDE_PATH="/opt/gcc-arm-none-eabi-4_8-2014q1/arm-none-eabi/include"
-read -p "gcc_arm_none_eabi include path:     " -i "$GCC_ARM_NONE_EABI_INCLUDE_PATH" -e GCC_ARM_NONE_EABI_INCLUDE_PATH
-# make absolute
-if [ "/$GCC_ARM_NONE_EABI_INCLUDE_PATH" != "$GCC_ARM_NONE_EABI_INCLUDE_PATH" ]; then
-  cd $GCC_ARM_NONE_EABI_INCLUDE_PATH
-  GCC_ARM_NONE_EABI_INCLUDE_PATH=${PWD}
-  cd $USER_DIR
-fi
-# append a slash if required
-if [ "${GCC_ARM_NONE_EABI_INCLUDE_PATH%"/"}" == "$GCC_ARM_NONE_EABI_INCLUDE_PATH" ]; then
-  GCC_ARM_NONE_EABI_INCLUDE_PATH="${GCC_ARM_NONE_EABI_INCLUDE_PATH}/"
-fi
-
-### the relative path where all project files shall be generated
-cd "$SCRIPT_DIR/../../"
-PROJECT_ROOT_PATH=${PWD}
-cd $USER_DIR
-read -p "path where to create project files: " -i "$PROJECT_ROOT_PATH" -e PROJECT_ROOT_PATH
-# make absolute
-if [ "/$PROJECT_ROOT_PATH" != "$PROJECT_ROOT_PATH" ]; then
-  cd $PROJECT_ROOT_PATH
-  PROJECT_ROOT_PATH=${PWD}
-  cd $USER_DIR
-fi
-# append a slash if required
-if [ "${PROJECT_ROOT_PATH%"/"}" == "$PROJECT_ROOT_PATH" ]; then
-  PROJECT_ROOT_PATH="${PROJECT_ROOT_PATH}/"
-fi
-
-# the relative path to the AMiRo-OS root directory
-cd "$SCRIPT_DIR/../../"
-AMIROOS_ROOT_PATH=${PWD}
-cd $USER_DIR
-read -p "AMiRo-OS root path:                 " -i "$AMIROOS_ROOT_PATH" -e AMIROOS_ROOT_PATH
-# make absolute
-if [ "/$AMIROOS_ROOT_PATH" != "$AMIROOS_ROOT_PATH" ]; then
-  cd $AMIROOS_ROOT_PATH
-  AMIROOS_ROOT_PATH=${PWD}
-  cd $USER_DIR
-fi
-# append a slash if required
-if [ "${AMIROOS_ROOT_PATH%"/"}" == "$AMIROOS_ROOT_PATH" ]; then
-  AMIROOS_ROOT_PATH="${AMIROOS_ROOT_PATH}/"
-fi
-
-# the relative path to the ChibiOS root directory
-cd "${AMIROOS_ROOT_PATH}../ChibiOS/"
-CHIBIOS_ROOT_PATH=${PWD}
-cd $USER_DIR
-read -p "ChibiOS root path:                  " -i "$CHIBIOS_ROOT_PATH" -e CHIBIOS_ROOT_PATH
-# make absolute
-if [ "/$CHIBIOS_ROOT_PATH" != "$CHIBIOS_ROOT_PATH" ]; then
-  cd $CHIBIOS_ROOT_PATH
-  CHIBIOS_ROOT_PATH=${PWD}
-  cd $USER_DIR
-fi
-# append a slash if required
-if [ "${CHIBIOS_ROOT_PATH%"/"}" == "$CHIBIOS_ROOT_PATH" ]; then
-  CHIBIOS_ROOT_PATH="${CHIBIOS_ROOT_PATH}/"
-fi
-
-# the prefix names for the projects to be generated
-CHIBIOS_PROJECT_PREFIX="ChibiOS"
-LIGHTRING_PROJECT_PREFIX="LightRing"
-POWERMANAGEMENT_PROJECT_PREFIX="PowerManagement"
-DIWHEELDRIVE_PROJECT_PREFIX="DiWheelDrive"
-
-echo ""
-
-
-
-#############################
-###   ENVIRONMENT SETUP   ###
-#############################
-
-# generate the relative path from the project root to ChibiOS
-absoluteToRelativePath "$PROJECT_ROOT_PATH" "$CHIBIOS_ROOT_PATH" PROJECT_ROOT_TO_CHIBIOS
-# generate the relative path from the project root to AMiRo-OS
-absoluteToRelativePath "$PROJECT_ROOT_PATH" "$AMIROOS_ROOT_PATH" PROJECT_ROOT_TO_AMIROOS
-
-# move back to the project root directory
-cd $PROJECT_ROOT_PATH
-
-
-
-######################
-###   CLEAN STEP   ###
-######################
-
-# clean the project files
-if [[ "${ARG_LIST[@]}" == *"$CLEAN_FLAG"* ]]; then
-  echo -n "removing existing project files..."
-
-  # remove all files
-  rm -f ${CHIBIOS_PROJECT_PREFIX}.includes
-  rm -f ${CHIBIOS_PROJECT_PREFIX}.files
-  rm -f ${CHIBIOS_PROJECT_PREFIX}.config
-  rm -f ${CHIBIOS_PROJECT_PREFIX}.creator
-
-  rm -f ${LIGHTRING_PROJECT_PREFIX}.includes
-  rm -f ${LIGHTRING_PROJECT_PREFIX}.files
-  rm -f ${LIGHTRING_PROJECT_PREFIX}.config
-  rm -f ${LIGHTRING_PROJECT_PREFIX}.creator
-
-  rm -f ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
-  rm -f ${POWERMANAGEMENT_PROJECT_PREFIX}.files
-  rm -f ${POWERMANAGEMENT_PROJECT_PREFIX}.config
-  rm -f ${POWERMANAGEMENT_PROJECT_PREFIX}.creator
-
-  rm -f ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
-  rm -f ${DIWHEELDRIVE_PROJECT_PREFIX}.files
-  rm -f ${DIWHEELDRIVE_PROJECT_PREFIX}.config
-  rm -f ${DIWHEELDRIVE_PROJECT_PREFIX}.creator
-
-  echo -e "\tdone"
-fi
-
-# wipe even the user specific files (created by QtCreator)
-if [[ "${ARG_LIST[@]}" == *"$WIPE_FLAG"* ]]; then
-  echo -n "removing existing user specific project files..."
-
-  # remove all user files
-  rm -f ${CHIBIOS_PROJECT_PREFIX}.creator.user
-  rm -f ${LIGHTRING_PROJECT_PREFIX}.creator.user
-  rm -f ${POWERMANAGEMENT_PROJECT_PREFIX}.creator.user
-  rm -f ${DIWHEELDRIVE_PROJECT_PREFIX}.creator.user
-
-  echo -e "\tdone"
-fi
-
-
-
-#########################
-###   CHIBIOS SETUP   ###
-#########################
-
-if [[ "${ARG_LIST[@]}" == *"$CHIBIOS_FLAG"* ]]; then
-  echo -n "creating project files for ${CHIBIOS_PROJECT_PREFIX}..."
-
-  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-  find $PROJECT_ROOT_TO_CHIBIOS -type d | grep -v /[.][^.] | grep -v /doc/ > ${CHIBIOS_PROJECT_PREFIX}.includes
-  # generate a file that specifies all files
-  find $PROJECT_ROOT_TO_CHIBIOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" | grep -v /[.][^.] | grep -v /doc/ > ${CHIBIOS_PROJECT_PREFIX}.files
-  # generate a default project configuration file if none exists so far
-  if [ ! -f ${CHIBIOS_PROJECT_PREFIX}.config ]; then
-    echo -e "// Add predefined macros for your project here. For example:\n// #define YOUR_CONFIGURATION belongs here\n" > ${CHIBIOS_PROJECT_PREFIX}.config
-  fi
-  # generate a default .creator file if none exists so far
-  if [ ! -f ${CHIBIOS_PROJECT_PREFIX}.creator ]; then
-    echo -e "[general]\n" > ${CHIBIOS_PROJECT_PREFIX}.creator
-  fi
-
-  echo -e "\tdone"
-fi
-
-
-
-###########################
-###   LIGHTRING SETUP   ###
-###########################
-
-if [[ "${ARG_LIST[@]}" == *"$LIGHTRING_FLAG"* ]]; then
-  echo -n "creating project files for ${LIGHTRING_PROJECT_PREFIX}..."
-
-  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-  echo $GCC_ARM_NONE_EABI_INCLUDE_PATH > ${LIGHTRING_PROJECT_PREFIX}.includes
-  find $PROJECT_ROOT_TO_AMIROOS -type d | grep -v /[.][^.] | grep -v /doc/ | grep "devices\|include\|util\|boards\|components\|hal" | grep -iv "PowerManagement" | grep -iv "DiWheelDrive" >> ${LIGHTRING_PROJECT_PREFIX}.includes
-  find $PROJECT_ROOT_TO_CHIBIOS -type d | grep -v /[.][^.] | grep -v /doc/ | grep /os/ >> ${LIGHTRING_PROJECT_PREFIX}.includes
-  # generate a file that specifies all files
-  find $PROJECT_ROOT_TO_AMIROOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" -o -iname "*.tpp" | grep -v /[.][^.] | grep -v /doc/ | grep -iv "PowerManagement" | grep -iv "DiWheelDrive" > ${LIGHTRING_PROJECT_PREFIX}.files
-  find $PROJECT_ROOT_TO_CHIBIOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" | grep -v /[.][^.] | grep -v /doc/ | grep /os/ >> ${LIGHTRING_PROJECT_PREFIX}.files
-  # generate a default project configuration file if none exists so far
-  if [ ! -f ${LIGHTRING_PROJECT_PREFIX}.config ]; then
-    echo -e "// Add predefined macros for your project here. For example:\n//#define YOUR_CONFIGURATION belongs here\n" > ${LIGHTRING_PROJECT_PREFIX}.config
-  fi
-  # generate a default .creator file if none exists so far
-  if [ ! -f ${LIGHTRING_PROJECT_PREFIX}.creator ]; then
-    echo -e "[general]\n" > ${LIGHTRING_PROJECT_PREFIX}.creator
-  fi
-
-  echo -e "\tdone"
-fi
-
-
-
-#################################
-###   POWERMANAGEMENT SETUP   ###
-#################################
-
-if [[ "${ARG_LIST[@]}" == *"$POWERMANAGEMENT_FLAG"* ]]; then
-  echo -n "creating project files for ${POWERMANAGEMENT_PROJECT_PREFIX}..."
-
-  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-  echo $GCC_ARM_NONE_EABI_INCLUDE_PATH > ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
-  find $PROJECT_ROOT_TO_AMIROOS -type d | grep -v /[.][^.] | grep -v /doc/ | grep "devices\|include\|util\|boards\|components\|hal" | grep -iv "LightRing" | grep -iv "DiWheelDrive" >> ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
-  find $PROJECT_ROOT_TO_CHIBIOS -type d | grep -v /[.][^.] | grep -v /doc/ >> ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
-  # generate a file that specifies all files
-  find $PROJECT_ROOT_TO_AMIROOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" -o -iname "*.tpp" | grep -v /[.][^.] | grep -v /doc/ | grep -iv "LightRing" | grep -iv "DiWheelDrive" > ${POWERMANAGEMENT_PROJECT_PREFIX}.files
-  find $PROJECT_ROOT_TO_CHIBIOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" | grep -v /[.][^.] | grep -v /doc/ | grep /os/ >> ${POWERMANAGEMENT_PROJECT_PREFIX}.files
-  # generate a default project configuration file if none exists so far
-  if [ ! -f ${POWERMANAGEMENT_PROJECT_PREFIX}.config ]; then
-    echo -e "// Add predefined macros for your project here. For example:\n//#define YOUR_CONFIGURATION belongs here\n" > ${POWERMANAGEMENT_PROJECT_PREFIX}.config
-  fi
-  # generate a default .creator file if none exists so far
-  if [ ! -f ${POWERMANAGEMENT_PROJECT_PREFIX}.creator ]; then
-    echo -e "[general]\n" > ${POWERMANAGEMENT_PROJECT_PREFIX}.creator
-  fi
-
-  echo -e "\tdone"
-fi
-
-
-
-##############################
-###   DIWHEELDRIVE SETUP   ###
-##############################
-
-if [[ "${ARG_LIST[@]}" == *"$DIWHEELDRIVE_FLAG"* ]]; then
-  echo -n "creating project files for ${DIWHEELDRIVE_PROJECT_PREFIX}..."
-
-  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-  echo $GCC_ARM_NONE_EABI_INCLUDE_PATH > ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
-  find $PROJECT_ROOT_TO_AMIROOS -type d | grep -v /[.][^.] | grep -v /doc/ | grep "devices\|include\|util\|boards\|components\|hal" | grep -iv "LightRing" | grep -iv "PowerManagement" >> ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
-  find $PROJECT_ROOT_TO_CHIBIOS -type d | grep -v /[.][^.] | grep -v /doc/ >> ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
-  # generate a file that specifies all files
-  find $PROJECT_ROOT_TO_AMIROOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" -o -iname "*.tpp" | grep -v /[.][^.] | grep -v /doc/ | grep -iv "LightRing" | grep -iv "PowerManagement" > ${DIWHEELDRIVE_PROJECT_PREFIX}.files
-  find $PROJECT_ROOT_TO_CHIBIOS -type f -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.s" | grep -v /[.][^.] | grep -v /doc/ | grep /os/ >> ${DIWHEELDRIVE_PROJECT_PREFIX}.files
-  # generate a default project configuration file if none exists so far
-  if [ ! -f ${DIWHEELDRIVE_PROJECT_PREFIX}.config ]; then
-    echo -e "// Add predefined macros for your project here. For example:\n//#define YOUR_CONFIGURATION belongs here\n" > ${DIWHEELDRIVE_PROJECT_PREFIX}.config
-  fi
-  # generate a default .creator file if none exists so far
-  if [ ! -f ${DIWHEELDRIVE_PROJECT_PREFIX}.creator ]; then
-    echo -e "[general]\n" > ${DIWHEELDRIVE_PROJECT_PREFIX}.creator
-  fi
-
-  echo -e "\tdone"
-fi
-
-
-
-#################
-###   OUTRO   ###
-#################
-
-cleanupVariables
-
-echo ""
-echo "-------------------------------------------------------------------------------"
-
diff --git a/include/Matrix.h b/include/Matrix.h
deleted file mode 100644
index 818e98c..0000000
--- a/include/Matrix.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef MATRIX_H_
-#define MATRIX_H_
-
-#include <algorithm> // std::fill, std::copy
-
-namespace Matrix {
-
-  typedef unsigned int uint;
-
-  /**
-    * Multiplication of two matrices Z=X*Y
-    *
-    * @param *X Pointer to first element of first matrix
-    * @param Xrows Rows of X
-    * @param Xcols Cols of X
-    * @param *Y Pointer to first element of second matrix
-    * @param Yrows Rows of Y
-    * @param Ycols Cols of Y
-    * @param *Z Pointer to first element of result matrix (needs to be init with 0)
-    * @param Zrows Rows of Z
-    * @param Zcols Cols of Z
-    */
-  template <typename T>
-  void XdotY(T* X,uint Xrows,uint Xcols,T* Y,uint Yrows, uint Ycols,T* Z, uint Zrows,uint Zcols) {
-
-    // Check if the multiplication will work
-//       if (Zrows != Xrows || Zcols != Ycols || Xcols != Yrows) {
-//   return 1;
-//       }
-
-    // Do the multiplication
-    // Z_{i,k} = sum_{n} X_{i,n} * Y_{n,k}
-    for (uint i = 0; i < Zrows; i++) {
-      for (uint k = 0; k < Zcols; k++) {
-  for (uint n = 0; n < Xcols; n++) {
-    Z[i*Zcols+k] += X[i*Xcols+n] * Y[n*Ycols+k];
-  }
-      }
-    }
-//       return 0;
-  };
-
-  /**
-    * Multiplication of two matrices Z=X*Y^{T},
-    * while Y will be transposed during calculation
-    *
-    * @param *X Pointer to first element of first matrix
-    * @param Xrows Rows of X
-    * @param Xcols Cols of X
-    * @param *Y Pointer to first element of second matrix
-    * @param Yrows Rows of Y
-    * @param Ycols Cols of Y
-    * @param *Z Pointer to first element of result matrix (needs to be init with 0)
-    * @param Zrows Rows of Z
-    * @param Zcols Cols of Z
-    */
-  template <typename T>
-  void XdotYtrans(T* X,uint Xrows,uint Xcols,T* Y,uint Yrows, uint Ycols,T* Z, uint Zrows,uint Zcols) {
-
-    // Check if the multiplication will work
-//       if (Zrows != Xrows || Zcols != Yrows || Xcols != Ycols) {
-//   return 1;
-//       }
-
-    // Do the multiplication
-    // Z_{i,k} = sum_{n} X_{i,n} * Y_{k,n}
-    for (uint i = 0; i < Zrows; i++) {
-      for (uint k = 0; k < Zcols; k++) {
-  for (uint n = 0; n < Xcols; n++) {
-    Z[i*Zcols+k] += X[i*Xcols+n] * Y[n+k*Ycols];
-  }
-      }
-    }
-//       return 0;
-  };
-
-/**
-    * Multiplication of two matrices Z=X^{T}*Y,
-    * while X will be transposed during calculation
-    *
-    * @param *X Pointer to first element of first of matrix
-    * @param Xrows Rows of X
-    * @param Xcols Cols of X
-    * @param *Y Pointer to first element of second matrix
-    * @param Yrows Rows of Y
-    * @param Ycols Cols of Y
-    * @param *Z Pointer to first element of result matrix (needs to be init with 0)
-    * @param Zrows Rows of Z
-    * @param Zcols Cols of Z
-    */
-  template <typename T>
-  void XtransDotY(T* X, uint Xrows,uint Xcols,T* Y,uint Yrows, uint Ycols,T* Z, uint Zrows,uint Zcols) {
-
-    // Check if the multiplication will work
-//       if (Zrows != Xrows || Zcols != Yrows || Xcols != Ycols) {
-//   return 1;
-//       }
-
-    // Do the multiplication
-    // Z_{i,k} = sum_{n} X_{n,i} * Y_{k,n}
-    for (uint i = 0; i < Zrows; i++) {
-      for (uint k = 0; k < Zcols; k++) {
-        for (uint n = 0; n < Xcols; n++) {
-          Z[i*Zcols+k] += X[n*Xcols+i] * Y[n+k*Ycols];
-        }
-      }
-    }
-//       return 0;
-  };
-
-    /**
-    * Addition of two matrices Z=X+Y,
-    *
-    * @param *X Pointer to first element of first matrix
-    * @param Xrows Rows of X
-    * @param Xcols Cols of X
-    * @param *Y Pointer to first element of second matrix
-    * @param Yrows Rows of Y
-    * @param Ycols Cols of Y
-    * @param *Z Pointer to first element of result matrix (needs to be init with 0)
-    * @param Zrows Rows of Z
-    * @param Zcols Cols of Z
-    */
-  template <typename T>
-  void XplusY(T* X,uint Xrows,uint Xcols,T* Y,uint Yrows, uint Ycols,T* Z, uint Zrows,uint Zcols) {
-
-    // Check if the multiplication will work
-//       if (Zrows != Xrows || Xrows != Yrows || Zcols != Ycols || Ycols != Xcols {
-//   return 1;
-//       }
-
-    // Do the summation
-  for (uint idx = 0; idx < Xrows*Xcols; idx++) {
-      Z[idx] += X[idx] + Y[idx];
-    }
-//       return 0;
-  };
-
-  /**
-    * Initializing matrix with any element
-    *
-    * @param *X Pointer to first element of first matrix
-    * @param Xrows Rows of X
-    * @param Xcols Cols of X
-    * @param value value of all elements
-    */
-  template <typename T>
-  void init(T* X, uint Xrows, uint Xcols, T value) {
-    std::fill (X,X+Xrows*Xcols,value);
-  };
-
-  /**
-    * Copy a matrix Y=X
-    *
-    * @param *X Pointer to first element of source matrix
-    * @param Xrows Rows of X
-    * @param Xcols Cols of X
-    * @param *Y Pointer to first element of result matrix
-    * @param Yrows Rows of Y
-    * @param Ycols Cols of Y
-    *
-    */
-  template <typename T>
-  void copy(T* X, uint Xrows, uint Xcols, T* Y, uint Yrows, uint Ycols) {
-    // if (Xrows != Yrows || Xcols != Ycols ) {
-//         return 1;
-//       }
-    std::copy (X,X+Xrows*Xcols,Y);
-//       return 0;
-  };
-
-}
-
-#endif /* MATRIX_ */
diff --git a/include/Types.h b/include/Types.h
deleted file mode 100644
index 999c706..0000000
--- a/include/Types.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef TYPES_H_
-#define TYPES_H_
-
-/*! \brief Types to use if you work with the AMiRo platform
- *
- *  This header contains types which has to be used
- *  if they suit the problem.
- *  All physical constants (therefore all values with a
- *  physical unit) are implicitly in µ iff the variable
- *  is of type integer, unless it is explicitly named in
- *  the variable.
- *  All physical constants (therefore all values with a
- *  physical unit) are implicitly without prefix (e.g. µ)
- *  iff the variable is of type float, unless it is
- *  explicitly named in the variable.
- *  For the types, the SI prefix is used, iff the variable
- *  is of type float and therefor in SI units.
- */
-
-namespace types {
-
-  /**
-   * A structure to represent the position and orientation of the robot
-   */
-  struct position {
-    /*@{*/
-    int32_t x;   /**< the x coordinate in µm */
-    int32_t y;   /**< the y coordinate in µm */
-    int32_t z;   /**< the z coordinate in µm */
-    int32_t f_x; /**< the f_x orientation in µrad */
-    int32_t f_y; /**< the f_y orientation in µrad */
-    int32_t f_z; /**< the f_z orientation in µrad */
-    /*@}*/
-  };
-
-  /**
-   * A structure to represent the position and orientation of the robot
-   */
-  struct positionSI {
-    /*@{*/
-    float x;   /**< the x coordinate in m */
-    float y;   /**< the y coordinate in m */
-    float z;   /**< the z coordinate in m */
-    float f_x; /**< the f_x coordinate in rad */
-    float f_y; /**< the f_y coordinate in rad */
-    float f_z; /**< the f_z coordinate in rad */
-    /*@}*/
-  };
-
-  /**
-   * A structure to represent the kinematics of the robot
-   */
-  struct kinematic {
-    /*@{*/
-    int32_t x;   /**< the x velocity in µm/s */
-    int32_t y;   /**< the y velocity in µm/s */
-    int32_t z;   /**< the z velocity in µm/s */
-    int32_t w_x; /**< the w_x angular velocity in µrad/s */
-    int32_t w_y; /**< the w_y angular velocity in µrad/s */
-    int32_t w_z; /**< the w_z angular velocity in µrad/s */
-    /*@}*/
-  };
-
-  /**
-   * A structure to represent the kinematics of the robot
-   */
-  struct kinematicSI {
-    /*@{*/
-    float x;   /**< the x velovity in m/s */
-    float y;   /**< the y velocity in m/s */
-    float z;   /**< the z velocity in m/s */
-    float f_x; /**< the f_x angular velocity in rad/s */
-    float f_y; /**< the f_y angular velocity in rad/s */
-    float f_z; /**< the f_z angular velocity in rad/s */
-    /*@}*/
-  };
-
-  /**
-   * A structure to represent the power status of the robot
-   */
-  struct power_status {
-    /**
-     * @brief A union to encode the current charging status
-     */
-    union ChargingState {
-      uint8_t value = 0;
-      struct {
-        uint8_t powermanagement_plugged_in      : 1;  /**< status flag, whether the PowerManagement board is plugged in (physical plug detected) */
-        uint8_t powermanagement_charging        : 1;  /**< status flag, whether the batteries are currently charged via the PowerManagement board */
-        uint8_t diwheeldrive_enable_power_path  : 1;  /**< a flag to enable/disable charging via the DiWheelDrive board */
-        uint8_t diwheeldrive_charging           : 1;  /**< status flag, whether the batteries are currently charged via the DiWheelDrive board */
-        uint8_t vsys_higher_than_9V             : 1;  /**< status flag, whether vsys is currently higher than 9V */
-        uint8_t rsvd                            : 3;
-      } content;
-    };
-
-    /*@{*/
-    ChargingState charging_flags; /**< charging status */
-    uint8_t state_of_charge;      /**< state of charge of the batteries in percent */
-    uint16_t minutes_remaining;   /**< remaining time until the batteries are fully charged/discharged in minutes*/
-    uint16_t power_consumption;   /**< current power consumption in mW */
-    /*@}*/
-  };
-
-}
-
-#endif /* TYPES_ */
diff --git a/include/amiro/BaseSensor.hpp b/include/amiro/BaseSensor.hpp
deleted file mode 100644
index 850c9ef..0000000
--- a/include/amiro/BaseSensor.hpp
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef AMIRO_BASE_SENSOR_H_
-#define AMIRO_BASE_SENSOR_H_
-
-/* ABOUT THE USED PREPROCESSOR DIRECTIVES IN THIS FILE
- * AMIRO_NCALIBRATION:
- *  If defined, the calibration() function will be ignored for compilation.
- *  Thus, all inheriting classes must use this directive, too.
- * AMIRO_NSELFTEST:
- *  If defined, the selftest() function will be ignored for compilation.
- *  Thus, all inheriting classes must use this directive, too.
- */
-
-namespace amiro {
-
-  /**
-   * This is an interface class, which should be used as a blueprint for all drivers of the AMiRo.
-   */
-  template<typename Init_t = void, typename Calib_t = void>
-  class BaseSensor
-  {
-  public:
-    BaseSensor() {}
-    virtual ~BaseSensor() {}
-
-    /**
-     * Some error codes that should be returned by the implementations of the virtual functions of this class.
-     */
-    enum ErrorCodes {
-      SUCCESS = 0x00u, OK = 0x00u,
-      ERROR = 0x80u, FAIL = 0x80u,
-      NOT_IMPLEMENTED = 0xFFu
-    };
-
-    /**
-     * Initializes the hardware (e.g. sets register values).
-     * This function is optional.
-     *
-     * @param[in,out] driver specific initialization data (should be used for arguments and results); optional
-     * @return an error code
-     */
-    virtual inline msg_t init(Init_t* = NULL)
-    {
-      return NOT_IMPLEMENTED;
-    }
-
-    /**
-     * Reads the most important values from the hardware and stores them in local buffers.
-     *
-     * @return an error code
-     */
-    virtual msg_t update() = 0;
-
-    /**
-     * If required, wakes the hardware from power saving mode into an active state.
-     * (Re)Initializes all local buffers with valid values, thus the update() function should be called.
-     *
-     * @return an error code
-     */
-    virtual msg_t wakeup() = 0;
-
-    /**
-     * Puts the hardware in a power saving mode to reduce energy consumption.
-     * This function is optional.
-     * @return an error code
-     */
-    virtual msg_t hibernate()
-    {
-      return NOT_IMPLEMENTED;
-    }
-
-#ifndef AMIRO_NCALIBRATION
-    /**
-     * Runs a calibration of the hardware.
-     * This function is optional.
-     *
-     * @param[in,out] driver specific calibration data (should be used for arguments and results); optional
-     *
-     * @return an error code
-     */
-    virtual msg_t calibration(Calib_t* = NULL)
-    {
-      return NOT_IMPLEMENTED;
-    }
-#else
-    static uint8_t calibration(Calib_t* = NULL)
-    {
-      return NOT_IMPLEMENTED;
-    }
-#endif
-
-#ifndef AMIRO_NSELFTEST
-    /**
-     * Runs a self-test on the hardware and/or communication.
-     * This function is optional but highly recommended.
-     *
-     * @return an error code
-     */
-    virtual msg_t selftest()
-    {
-      return NOT_IMPLEMENTED;
-    }
-#else
-    static msg_t selftest()
-    {
-      return NOT_IMPLEMENTED;
-    }
-#endif
-
-  };
-
-}
-
-#endif /* AMIRO_BASE_SENSOR_H_ */
diff --git a/include/amiro/Color.h b/include/amiro/Color.h
deleted file mode 100644
index aab533c..0000000
--- a/include/amiro/Color.h
+++ /dev/null
@@ -1,181 +0,0 @@
-#ifndef AMIRO_COLOR_H_
-#define AMIRO_COLOR_H_
-
-namespace amiro {
-
-  class Color {
-  public:
-    enum GlobalColor {
-      ALICEBLUE,
-      ANTIQUEWHITE,
-      AQUA,
-      AQUAMARINE,
-      AZURE,
-      BEIGE,
-      BISQUE,
-      BLACK,
-      BLANCHEDALMOND,
-      BLUE,
-      BLUEVIOLET,
-      BROWN,
-      BURLYWOOD,
-      CADETBLUE,
-      CHARTREUSE,
-      CHOCOLATE,
-      CORAL,
-      CORNFLOWERBLUE,
-      CORNSILK,
-      CRIMSON,
-      CYAN,
-      DARKBLUE,
-      DARKCYAN,
-      DARKGOLDENROD,
-      DARKGRAY,
-      DARKGREEN,
-      DARKGREY,
-      DARKKHAKI,
-      DARKMAGENTA,
-      DARKOLIVEGREEN,
-      DARKORANGE,
-      DARKORCHID,
-      DARKRED,
-      DARKSALMON,
-      DARKSEAGREEN,
-      DARKSLATEBLUE,
-      DARKSLATEGRAY,
-      DARKSLATEGREY,
-      DARKTURQUOISE,
-      DARKVIOLET,
-      DEEPPINK,
-      DEEPSKYBLUE,
-      DIMGRAY,
-      DIMGREY,
-      DODGERBLUE,
-      FIREBRICK,
-      FLORALWHITE,
-      FORESTGREEN,
-      FUCHSIA,
-      GAINSBORO,
-      GHOSTWHITE,
-      GOLD,
-      GOLDENROD,
-      GRAY,
-      GREY,
-      GREEN,
-      GREENYELLOW,
-      HONEYDEW,
-      HOTPINK,
-      INDIANRED,
-      INDIGO,
-      IVORY,
-      KHAKI,
-      LAVENDER,
-      LAVENDERBLUSH,
-      LAWNGREEN,
-      LEMONCHIFFON,
-      LIGHTBLUE,
-      LIGHTCORAL,
-      LIGHTCYAN,
-      LIGHTGOLDENRODYELLOW,
-      LIGHTGRAY,
-      LIGHTGREEN,
-      LIGHTGREY,
-      LIGHTPINK,
-      LIGHTSALMON,
-      LIGHTSEAGREEN,
-      LIGHTSKYBLUE,
-      LIGHTSLATEGRAY,
-      LIGHTSLATEGREY,
-      LIGHTSTEELBLUE,
-      LIGHTYELLOW,
-      LIME,
-      LIMEGREEN,
-      LINEN,
-      MAGENTA,
-      MAROON,
-      MEDIUMAQUAMARINE,
-      MEDIUMBLUE,
-      MEDIUMORCHID,
-      MEDIUMPURPLE,
-      MEDIUMSEAGREEN,
-      MEDIUMSLATEBLUE,
-      MEDIUMSPRINGGREEN,
-      MEDIUMTURQUOISE,
-      MEDIUMVIOLETRED,
-      MIDNIGHTBLUE,
-      MINTCREAM,
-      MISTYROSE,
-      MOCCASIN,
-      NAVAJOWHITE,
-      NAVY,
-      OLDLACE,
-      OLIVE,
-      OLIVEDRAB,
-      ORANGE,
-      ORANGERED,
-      ORCHID,
-      PALEGOLDENROD,
-      PALEGREEN,
-      PALETURQUOISE,
-      PALEVIOLETRED,
-      PAPAYAWHIP,
-      PEACHPUFF,
-      PERU,
-      PINK,
-      PLUM,
-      POWDERBLUE,
-      PURPLE,
-      RED,
-      ROSYBROWN,
-      ROYALBLUE,
-      SADDLEBROWN,
-      SALMON,
-      SANDYBROWN,
-      SEAGREEN,
-      SEASHELL,
-      SIENNA,
-      SILVER,
-      SKYBLUE,
-      SLATEBLUE,
-      SLATEGRAY,
-      SLATEGREY,
-      SNOW,
-      SPRINGGREEN,
-      STEELBLUE,
-      TAN,
-      TEAL,
-      THISTLE,
-      TOMATO,
-      TURQUOISE,
-      VIOLET,
-      WHEAT,
-      WHITE,
-      WHITESMOKE,
-      YELLOW,
-      YELLOWGREEN
-    };
-
-    Color();
-    Color(const Color& color);
-    Color(int r, int g, int b);
-    Color(GlobalColor color);
-    Color darker(int factor);
-    void getRedGreenBlue(int* r, int* g, int* b);
-    int getRed();
-    int getGreen();
-    int getBlue();
-    Color lighter(int factor);
-    void setRedGreenBlue(int r, int g, int b);
-
-    Color& operator=(Color const& color);
-    Color& operator=(GlobalColor color);
-
-  private:
-    unsigned char red;
-    unsigned char green;
-    unsigned char blue;
-  };
-
-}
-
-#endif /* AMIRO_COLOR_H_ */
diff --git a/include/amiro/Constants.h b/include/amiro/Constants.h
deleted file mode 100644
index 3673285..0000000
--- a/include/amiro/Constants.h
+++ /dev/null
@@ -1,237 +0,0 @@
-#ifndef AMIRO_CONSTANTS_H_
-#define AMIRO_CONSTANTS_H_
-
-/*! \brief Constants regarding the AMiRo platform
- *
- *  This header contains constant variables
- *  regarding the AMiRo platform, which means that
- *  these values do not change during runtime.
- *  Constants are e.g. physical ones like seconds per minute
- *  or geometrical ones like the circumference of wheel.
- *  All physical constants (therefore all values with a
- *  physical unit) are implicitly in µ iff the variable
- *  is of type integer, unless it is explicitly named in
- *  the variable.
- *  All physical constants (therefore all values with a
- *  physical unit) are implicitly without prefix (e.g. µ)
- *  iff the variable is of type float, unless it is
- *  explicitly named in the variable. The SI prefix is
- *  used, iff the variable is of type float and therefor
- *  in SI units.
- */
-
-#include <math.h>
-#include <stdint.h>
-
-/* CAN_* defines start */
-
-/** \brief Controller Area Network specific defines
- *
- * These CAN_* defines are used in ControllerAreaNetworkRx.h
- * and ControllerAreaNetworkTx.h
- */
-
-/* CAN_* defines end */
-
-namespace amiro {
-
-namespace CAN {
-
-  const uint32_t UPDATE_PERIOD        = US2ST(62500);  // 16 Hz
-
-  const uint32_t PERIODIC_TIMER_ID         = 1;
-  const uint32_t RECEIVED_ID               = 2;
-
-  const uint32_t BOARD_ID_SHIFT            = 0x00u;
-  const uint32_t BOARD_ID_MASK             = 0x07u;
-  const uint32_t DEVICE_ID_SHIFT           = 0x03u;
-  const uint32_t DEVICE_ID_MASK            = 0xFFu;
-  const uint32_t INDEX_ID_SHIFT            = 0x03u;
-  const uint32_t INDEX_ID_MASK             = 0x07u;
-
-  const uint32_t DI_WHEEL_DRIVE_ID         = 1;
-  const uint32_t POWER_MANAGEMENT_ID       = 2;
-  const uint32_t LIGHT_RING_ID             = 3;
-  const uint32_t COGNITION                 = 4;
-
-  const uint32_t MAGNETOMETER_X_ID         = 0x54;
-  const uint32_t MAGNETOMETER_Y_ID         = 0x55;
-  const uint32_t MAGNETOMETER_Z_ID         = 0x56;
-  const uint32_t GYROSCOPE_ID              = 0x58;
-  const uint32_t PROXIMITY_FLOOR_ID        = 0x51;
-  const uint32_t ODOMETRY_ID               = 0x50;
-  const uint32_t BRIGHTNESS_ID             = 0x40;
-  inline constexpr uint32_t COLOR_ID(uint32_t index)             {return 0x38 | ((index) & 0x7);}
-  inline constexpr uint32_t PROXIMITY_RING_ID(uint32_t index)    {return 0x30 | ((index) & 0x7);}
-  const uint32_t SET_KINEMATIC_CONST_ID    = 0x22;
-  const uint32_t TARGET_POSITION_ID        = 0x21;
-  const uint32_t ACTUAL_SPEED_ID           = 0x20;
-  const uint32_t SET_ODOMETRY_ID           = 0x12;
-  const uint32_t TARGET_RPM_ID             = 0x11;
-  const uint32_t TARGET_SPEED_ID           = 0x10;
-  const uint32_t POWER_STATUS_ID           = 0x60;
-  const uint32_t ROBOT_ID                  = 0x48;
-  inline constexpr uint32_t SHELL_QUERY_ID(uint8_t index)        {return 0x70 | ((index) & 0x7);}
-  inline constexpr uint32_t SHELL_REPLY_ID(uint8_t index)        {return 0x78 | ((index) & 0x7);}
-  const uint32_t BROADCAST_SHUTDOWN        = 0x80u;
-
-  const uint32_t CALIBRATE_PROXIMITY_FLOOR = 0x81u;
-  const uint32_t CALIBRATE_PROXIMITY_RING  = 0x82u;
-
-  const uint32_t SHUTDOWN_MAGIC            = 0xAA55u;
-}
-
-namespace constants {
-
-  /** \brief Amount of seconds per minute */
-  const int32_t secondsPerMinute = 60;
-
-  /** \brief Amount of minutes per hour */
-  const int32_t minutesPerHour = 60;
-
-  /** \brief Amount of milliseconds per second */
-  const int32_t millisecondsPerSecond = 1000;
-
-  /* Several definitions of PI */
-  constexpr float    PI   = float(M_PI);                /**< PI approximated with single precision floating point */
-  constexpr uint32_t PIe9 = (M_PI * 1000000000) + 0.5f; /**< PI approximated with 32-bit integer and multiplied by factor 1e9 */
-  constexpr uint32_t PIe6 = (M_PI * 1000000) + 0.5f;    /**< PI approximated with 32-bit integer and multiplied by factor 1e6 */
-  constexpr uint16_t PIe3 = (M_PI * 1000) + 0.5f;       /**< PI approximated with 16-bit integer and multiplied by factor 1e3 */
-  constexpr uint16_t PIe2 = (M_PI * 100) + 0.5f;        /**< PI approximated with 16-bit integer and multiplied by factor 1e2 */
-  constexpr uint8_t  PIe1 = (M_PI * 10) + 0.5f;         /**< PI approximated with 8-bit integer and multiplied by factor 1e1 */
-  constexpr uint8_t  PIe0 = (M_PI * 1) + 0.5f;          /**< PI approximated with 8-bit integer and multiplied by factor 1e0 */
-
-namespace LightRing {
-
-  /** \brief Index of the top LEDs
-   *
-   * Top view of the AMiRo top LEDs and their indices:
-   *   _______
-   *  / 7 F 0 \
-   * |6       1|
-   * |5       2|
-   *  \_4_B_3_/
-   */
-  enum ledIndex : uint8_t {
-    LED_BL = 4, LED_BACK_LEFT = 4, LED_SSW = 4, LED_SOUTH_SOUTHWEST = 4,
-    LED_LB = 5, LED_LEFT_BACK = 5, LED_WSW = 5, LED_WEST_SOUTHWEST = 5,
-    LED_LF = 6, LED_LEFT_FRONT = 6, LED_WNW = 6, LED_WEST_NORTHWEST = 6,
-    LED_FL = 7, LED_FRONT_LEFT = 7, LED_NNW = 7, LED_NORTH_NORTHWEST = 7,
-    LED_FR = 0, LED_FRONT_RIGHT = 0, LED_NNE = 0, LED_NORTH_NORTHEAST = 0,
-    LED_RF = 1, LED_RIGHT_FRONT = 1, LED_ENE = 1, LED_EAST_NORTHEAST = 1,
-    LED_RB = 2, LED_RIGHT_BACK = 2, LED_ESE = 2, LED_EAST_SOUTHEAST = 2,
-    LED_BR = 3, LED_BACK_RIGHT = 3, LED_SSE = 3, LED_SOUTH_SOUTHEAST = 3
-  };
-}
-
-namespace DiWheelDrive {
-
-  /** \brief Distance between wheels in meter */
-  const float wheelBaseDistanceSI = 0.069f;
-
-  /** \brief Distance between wheels in micrometer */
-  const int32_t wheelBaseDistance = wheelBaseDistanceSI * 1e6;
-
-  /** \brief Wheel diameter in meter */
-  const float wheelDiameterSI = 0.05571f;
-
-  /** \brief Wheel diameter */
-  const int32_t wheelDiameter = wheelDiameterSI * 1e6;
-
-  /** \brief Wheel circumference in meter */
-  const float wheelCircumferenceSI = M_PI * wheelDiameterSI;
-
-  /** \brief Wheel circumference in micrometer */
-  const int32_t wheelCircumference = wheelCircumferenceSI * 1e6;
-
-  /** \brief Wheel error in meter (topview left:0, right:1) */
-  const float wheelErrorSI[2] = {0.1, 0.1};
-
-  /** \brief Wheel error in meter (topview left:0, right:1) */
-  const int32_t wheelError[2] = {(int32_t) (wheelErrorSI[0] * 1e6), (int32_t) (wheelErrorSI[1] * 1e6)};
-
-  /** \brief Motor increments per revolution
-   *
-   *  The increments are produced by 2 channels á 16
-   *  pulses per revolution with respect to the rising
-   *  and falling signal => 2*2*16 pulses/revolution.
-   *  The gearbox is 22:1 => 2*2*16*22 pulses/revolution
-   */
-  const int32_t incrementsPerRevolution = 2 * 2 * 16 * 22;
-
-  /** \brief Index of the proximity sensors
-   *
-   * Bottom view of the AMiRo sensors and their indices (F:Front, B:Back):
-   *  _____
-   * / 0F3 \
-   * |1   2|
-   * \__B__/
-   */
-  enum proximitySensorIdx : uint8_t {
-    PROX_WL = 2, PROX_LW = 2, PROX_WHEEL_LEFT = 2, PROX_LEFT_WHEEL = 2,
-    PROX_FL = 3, PROX_LF = 3, PROX_FRONT_LEFT = 3, PROX_LEFT_FRONT = 3,
-    PROX_FR = 0, PROX_RF = 0, PROX_FRONT_RIGHT = 0, PROX_RIGHT_FRONT = 0,
-    PROX_WR = 1, PROX_RW = 1, PROX_WHEEL_RIGHT = 1, PROX_RIGHT_WHEEL = 1,
-  };
-
-  /** \brief Index of the wheels
-   *
-   * Top view of the AMiRo wheels and their indices (F:Front, B:Back):
-   *   ____
-   * /| F |\
-   * |0   1|
-   * \|_B_|/
-   */
-  enum wheelIdx : uint8_t {
-    WHEEL_L = 0, WHEEL_LEFT = 0, LEFT_WHEEL = 0,
-    WHEEL_R = 1, WHEEL_RIGHT = 1, RIGHT_WHEEL = 1,
-  };
-}
-
-namespace PowerManagement {
-
-  /** \brief Index of the proximity sensors
-   *
-   * Top view of the AMiRo sensors and their indices:
-   *   _______
-   *  / 3 F 4 \
-   * |2       5|
-   * |1       6|
-   *  \_0_B_7_/
-   */
-  enum proximitySensorIdx : uint8_t {
-    PROX_BL = 0, PROX_BACK_LEFT = 0, PROX_SSW = 0, PROX_SOUTH_SOUTHWEST = 0,
-    PROX_LB = 1, PROX_LEFT_BACK = 1, PROX_WSW = 1, PROX_WEST_SOUTHWEST = 1,
-    PROX_LF = 2, PROX_LEFT_FRONT = 2, PROX_WNW = 2, PROX_WEST_NORTHWEST = 2,
-    PROX_FL = 3, PROX_FRONT_LEFT = 3, PROX_NNW = 3, PROX_NORTH_NORTHWEST = 3,
-    PROX_FR = 4, PROX_FRONT_RIGHT = 4, PROX_NNE = 4, PROX_NORTH_NORTHEAST = 4,
-    PROX_RF = 5, PROX_RIGHT_FRONT = 5, PROX_ENE = 5, PROX_EAST_NORTHEAST = 5,
-    PROX_RB = 6, PROX_RIGHT_BACK = 6, PROX_ESE = 6, PROX_EAST_SOUTHEAST = 6,
-    PROX_BR = 7, PROX_BACK_RIGHT = 7, PROX_SSE = 7, PROX_SOUTH_SOUTHEAST = 7
-  };
-
-  /** \brief Index of the batteries.
-   *
-   * The port names are printed on the PCB.
-   */
-  enum batteryPortIdx : uint8_t {
-    BAT_P7 = 0, BAT_A = 0,
-    BAT_P8 = 1, BAT_B = 1
-  };
-
-  /** \brief Index of the power monitors.
-   */
-  enum powerMonitorIdx : uint8_t {
-    INA_VDD = 0,
-    INA_VIO18 = 1,
-    INA_VIO33 = 2,
-    INA_VIO42 = 3,
-    INA_VIO50 = 4
-  };
-}
-
-}
-
-}
-
-#endif /* AMIRO_CONSTANTS_H_ */
diff --git a/include/amiro/ControllerAreaNetworkRx.h b/include/amiro/ControllerAreaNetworkRx.h
deleted file mode 100644
index 4a0aa26..0000000
--- a/include/amiro/ControllerAreaNetworkRx.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef AMIRO_CONTROLLER_AREA_NETWORK_RX_H_
-#define AMIRO_CONTROLLER_AREA_NETWORK_RX_H_
-
-#include <evtimer.h>
-#include <amiro/Color.h>
-#include <Types.h>  // ::kinematic
-
-#include <amiro/Constants.h>  // CAN::* macros
-
-namespace amiro {
-
-  class ControllerAreaNetworkRx : public chibios_rt::BaseStaticThread<128> {
-  public:
-    ControllerAreaNetworkRx(CANDriver *can, const uint8_t boardId);
-    virtual ~ControllerAreaNetworkRx() = 0;
-
-    uint16_t getProximityRingValue(int index);
-    uint16_t getProximityFloorValue(int index);
-    void getActualSpeed(types::kinematic &targetSpeed);
-    types::position getOdometry();
-    types::power_status& getPowerStatus();
-    uint8_t getRobotID();
-    int32_t getMagnetometerValue(int axis);
-    int16_t getGyroscopeValue(int axis);
-
-    void calibrateProximityRingValues();
-    void calibrateProximityFloorValues();
-
-    int rxCmdShell(CANRxFrame *frame);
-
-  protected:
-    virtual msg_t main();
-    virtual msg_t receiveMessage(CANRxFrame *frame);
-
-    int decodeBoardId(CANRxFrame *frame);
-    int decodeDeviceId(CANRxFrame *frame);
-    int decodeIndexId(CANRxFrame *frame);
-
-    int boardId;
-    uint16_t proximityRingValue[8];
-    int actualSpeed[2];
-    uint16_t proximityFloorValue[4];
-    int32_t magnetometerValue[3];
-    int16_t gyroscopeValue[3];
-    types::position robotPosition;
-    types::power_status powerStatus;
-    uint8_t robotId;
-    chibios_rt::EvtListener rxFullCanEvtListener;
-    chibios_rt::EvtSource *rxFullCanEvtSource;
-
-  private:
-    msg_t receiveSensorVal(CANRxFrame *frame);
-
-    CANDriver *canDriver;
-    CANConfig canConfig;
-
-  };
-
-}
-
-#endif /* AMIRO_CONTROLLER_AREA_NETWORK_RX_H_ */
-
diff --git a/include/amiro/ControllerAreaNetworkTx.h b/include/amiro/ControllerAreaNetworkTx.h
deleted file mode 100644
index bc576b4..0000000
--- a/include/amiro/ControllerAreaNetworkTx.h
+++ /dev/null
@@ -1,106 +0,0 @@
-#ifndef AMIRO_CONTROLLER_AREA_NETWORK_TX_H_
-#define AMIRO_CONTROLLER_AREA_NETWORK_TX_H_
-
-#include <evtimer.h>
-#include <amiro/Color.h>
-#include <Types.h>  // ::kinematic
-
-#include <amiro/Constants.h>  // CAN::* macros
-
-namespace amiro {
-
-  class ControllerAreaNetworkTx : public chibios_rt::BaseStaticThread<128> {
-  public:
-    ControllerAreaNetworkTx(CANDriver *can, const uint8_t boardId);
-    virtual ~ControllerAreaNetworkTx() = 0;
-
-    /**
-     * \brief Setting the brightness of the light ring
-     *
-     * @param brightness Brightness level 0 .. 200
-     */
-    void setLightBrightness(int brightness);
-
-    /**
-     * \brief Setting the color of the LED with the given index
-     *
-     * @param index Index of the LED
-     * @param color Color of the LED
-     */
-    void setLightColor(int index, Color color);
-
-    /**
-     * \brief Setting the desired speed in as kinematic struct
-     *
-     * @param targetSpeed Desired speed of the robot
-     */
-    void setTargetSpeed(types::kinematic &targetSpeed);
-
-    /**
-     * \brief Setting the desired speed in µ rounds per minute
-     *
-     * @param leftURpm Desired speed of the left wheel
-     * @param rightURpm Desired speed of the right wheel
-     */
-    void setTargetSpeed(int32_t leftURpm, int32_t rightURpm);
-
-    /**
-     * \brief Setting odometry for the Euler-Collatz algorithm on the DiWheelDrive board
-     *
-     * \notice Only bits 31..8 of robotPosition.x and robotPosition.y will be sent,
-     * i.e. values are divided by 1024 before being sent.
-     * Only bits 23..8 of orientation vector f_z be sent, i.e.
-     * f_z is devided by 1024 and clamped to int16_t.
-     * To avoid buffer overflow, only values between between [0, 2 * pi * 1e6] are valid.
-     * This is due to size constraints of CAN message frames.
-     *
-     * @param robotPosition Desired robot position.
-     */
-    void setOdometry(types::position robotPosition);
-
-    /**
-     * \brief Setting target position of current robot
-     *        local frame
-     *
-     * @param targetPosition Desired robot position
-     * @param targetTime Desired time reaching this position
-     */
-    void setTargetPosition(types::position &targetPosition, uint32_t targetTime);
-
-    /**
-     * \brief Setting correction ratios of the differential kinematic
-     *
-     * @param Ed Diameter ratio
-     * @param Eb Base width ratio
-     */
-    void setKinematicConstants(float Ed, float Eb);
-
-    void txQueryShell(uint8_t toBoardId, char *textdata, uint16_t size);
-    void txReplyShell(uint8_t toBoardId, char *textdata, uint16_t size);
-
-    void broadcastShutdown();
-
-  protected:
-    virtual msg_t main();
-    virtual msg_t updateSensorVal();
-    void transmitMessage(CANTxFrame *frame);
-    virtual void periodicBroadcast() = 0;
-
-    void encodeBoardId(CANTxFrame *frame, int board);
-    void encodeDeviceId(CANTxFrame *frame, int device);
-    void encodeIndexId(CANTxFrame *frame, int index);
-
-    int boardId;
-    chibios_rt::EvtListener eventTimerEvtListener;
-    chibios_rt::EvtSource *eventTimerEvtSource;
-
-  private:
-    EvTimer evtimer;
-    CANDriver *canDriver;
-    CANConfig canConfig;
-
-  };
-
-}
-
-#endif /* AMIRO_CONTROLLER_AREA_NETWORK_TX_H_ */
diff --git a/include/amiro/DistControl.h b/include/amiro/DistControl.h
deleted file mode 100644
index 97f37e4..0000000
--- a/include/amiro/DistControl.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef AMIRO_MOTOR_DISTCONTROL_H_
-#define AMIRO_MOTOR_DISTCONTROL_H_
-
-#include <amiro/MotorIncrements.h>
-#include <amiro/MotorControl.h>
-#include <amiro/Constants.h>
-#include <Types.h>
-
-#include <chprintf.h>
-
-namespace amiro {
-
-  class DistControl : public chibios_rt::BaseStaticThread<256> {
-  public:
-    /**
-     * Constructor
-     *
-     * @param mc object for retrieving the motors
-     * @param mi object for retrieving the motor increments of the qei
-     */
-    DistControl(MotorControl* mc, MotorIncrements* mi);
-
-    /**
-     * Get the current target distance in um.
-     *
-     * @return target distance in um
-     */
-    int getCurrentTargetDist(void);
-
-    /**
-     * Get the current target angle in urad.
-     *
-     * @return target distance in urad
-     */
-    int getCurrentTargetAngle(void);
-
-    /**
-     * Sets the target position.
-     *
-     * @param distance Distance to drive in um
-     * @param angle Angle to turn in urad
-     * @param time Given time to drive in ms
-     */
-    void setTargetPosition(int32_t distance, int32_t angle, uint16_t time);
-
-    /**
-     * Gives if the distance controller is active.
-     *
-     * @return true if active, false if inactive
-     */
-    bool isActive(void);
-
-    /**
-     * Deactivates the controller.
-     * The motor velocities won't be set in any way!
-     */
-    void deactivateController(void);
-
-
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-    /**
-     * Calculates the velocities by using the error distance and error angle.
-     */
-    void calcVelocities(void);
-
-    MotorControl* motorControl;
-    MotorIncrements* motorIncrements;
-    bool controllerActive, drivingForward, turningLeft, newVelocities;
-    const uint32_t period;
-    int32_t increment[2];
-    float incrementDifference[2];
-    float actualDistance[2]; // m
-    int32_t fullDistance[2]; // um
-    int32_t realDistance; // um
-    int32_t realAngle; // urad
-    int32_t targetDistance; // um
-    int32_t targetAngle; // urad
-    int32_t errorDistance; // um
-    int32_t errorAngle; // urad
-    uint32_t restTime; // us
-    types::kinematic maxVelocity;
-    types::kinematic targetVelocity;
-    types::kinematic minVelocity;
-  };
-}
-
-#endif /* AMIRO_MOTOR_DISTCONTROL_H_ */
diff --git a/include/amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp b/include/amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp
deleted file mode 100644
index 20ed4e0..0000000
--- a/include/amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-#ifndef AMIRO_FSIODIWHEELDRIVE_H_
-#define AMIRO_FSIODIWHEELDRIVE_H_
-
-/*! \brief memory layout for the eeproms
- *
- * This header defines the memory layout of the
- * at24c01 on the CiWheelDrive board.
- */
-
-#include <amiro/eeprom/at24.hpp>
-#include <amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp>
-
-// using namespace chibios_rt;
-
-namespace amiro {
-namespace fileSystemIo {
-
-class FSIODiWheelDrive : public FileSystemIoBase {
-  private:
-
-    /** \brief Layout for FSIODiWheelDrive with BSMV 1 and bsmv 1*/
-    struct DiWheelDrive_1_1 {
-      uint8_t  reserved_0x00_0x14[20];
-      uint16_t vcnl4020offset[4];       // U [12, 13, 15, 16]
-      uint8_t  generalPurpose[96];      // 1Cx_7Cx
-      uint8_t  reserved_0x7D_0x80[4];
-    };
-
-    /** \brief Layout for FSIODiWheelDrive with BSMV 1 and bsmv 2*/
-    struct DiWheelDrive_1_2 {
-      uint8_t  reserved_0x00_0x14[28];
-      float    Ed;
-      float    Eb;
-      uint8_t  generalPurpose[88];      // 24x_7Cx
-      uint8_t  reserved_0x7D_0x80[4];
-    };
-
-    /** \brief Layout for FSIODiWheelDrive with BSMV 1 and bsmv 3*/
-    struct DiWheelDrive_1_3 {
-      uint8_t  reserved_0x00_0x14[36];
-      float wheelfactor;
-      float igain;
-      int pgain;
-      float dgain;
-      uint8_t  generalPurpose[72];      // 24x_7Cx
-      uint8_t  reserved_0x7D_0x80[4];
-    };
-
-  public:
-    FSIODiWheelDrive(AT24 &at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : FileSystemIoBase(at24c01, BSMV, bsmv, HMV, hmv) {}
-
-    /**
-     * \brief Read the VCNL4020 offset from memory
-     * @param buffer Content to write in from the memory
-     * @param idx Index of the VCNL4020 sensor
-     * @return FSIO return types
-     */
-    msg_t getVcnl4020Offset (uint16_t *buffer, uint8_t idx);
-
-    /**
-     * \brief Write new data to the VCNL4020 offset
-     * @param buffer Content to write to the memory
-     * @param idx Index of the VCNL4020 sensor
-     * @return FSIO return types
-     */
-    msg_t setVcnl4020Offset (uint16_t buffer, uint8_t idx);
-
-    /**
-     * \brief Read the Ed ratio from memory
-     * @return FSIO return types
-     */
-    msg_t getEd (float *buffer);
-
-    /**
-     * \brief Write new data to the Ed ratio value
-     * @param buffer Content to write to the memory
-     * @return FSIO return types
-     */
-    msg_t setEd (float buffer);
-
-    /**
-     * \brief Read the Eb ratio from memory
-     * @return FSIO return types
-     */
-    msg_t getEb (float *buffer);
-
-    /**
-     * \brief Write new data to the Eb ratio value
-     * @param buffer Content to write to the memory
-     * @return FSIO return types
-     */
-    msg_t setEb (float buffer);
-
-    msg_t setwheelfactor (float buffer);
-    msg_t getWheelFactor (float *buffer);
-
-    msg_t setiGain (float buffer);
-    msg_t getiGain (float *buffer);
-
-    msg_t setdGain (float buffer);
-    msg_t getdGain (float *buffer);
-
-    msg_t setpGain (int buffer);
-    msg_t getpGain (int *buffer);
-};
-
-}
-}
-
-#endif /* AMIRO_FSIODIWHEELDRIVE_H_ */
diff --git a/include/amiro/FileSystemInputOutput/FSIOLightRing.hpp b/include/amiro/FileSystemInputOutput/FSIOLightRing.hpp
deleted file mode 100644
index 3be1edf..0000000
--- a/include/amiro/FileSystemInputOutput/FSIOLightRing.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef AMIRO_FSIOLIGHTRING_H_
-#define AMIRO_FSIOLIGHTRING_H_
-
-/*! \brief memory layout for the eeproms
- *
- * This header defines the memory layout of the
- * at24c01 on the LightRing board.
- */
-
-#include <amiro/eeprom/at24.hpp>
-#include <amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp>
-
-namespace amiro {
-namespace fileSystemIo {
-
-class FSIOLightRing : public FileSystemIoBase {
-  private:
-
-    /** \brief Layout for FSIOLightRing with BSMV 1 and bsmv 1*/
-    struct LightRing_1_1 {
-      uint8_t  reserved_0x00_0x14[20];
-      uint8_t  generalPurpose[104];      // 15x_7Cx
-      uint8_t  reserved_0x7D_0x80[4];
-    };
-
-  public:
-    FSIOLightRing(AT24 &at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : FileSystemIoBase(at24c01, BSMV, bsmv, HMV, hmv) {
-
-    }
-};
-
-}
-}
-
-#endif /* AMIRO_FSIOLIGHTRING_H_ */
diff --git a/include/amiro/FileSystemInputOutput/FSIOPowerManagement.hpp b/include/amiro/FileSystemInputOutput/FSIOPowerManagement.hpp
deleted file mode 100644
index 440079a..0000000
--- a/include/amiro/FileSystemInputOutput/FSIOPowerManagement.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef AMIRO_FSIOPOWERMANAGEMENT_H_
-#define AMIRO_FSIOPOWERMANAGEMENT_H_
-
-/*! \brief memory layout for the eeproms
- *
- * This header defines the memory layout of the
- * at24c01 on the PowerManagement board.
- */
-
-#include <amiro/eeprom/at24.hpp>
-#include <amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp>
-
-using namespace chibios_rt;
-
-namespace amiro {
-namespace fileSystemIo {
-
-class FSIOPowerManagement : public FileSystemIoBase {
-  private:
-
-    /** \brief Layout for FSIOPowerManagement with BSMV 1 and bsmv 1*/
-    struct PowerManagement_1_1 {
-      uint8_t  reserved_0x00_0x14[20];
-      uint16_t vcnl4020offset[8];        // U1.Proximity [11, 21, 31, 41, 12, 22, 32, 42]
-      uint8_t  generalPurpose[88];       // 24x_7Cx
-      uint8_t  reserved_0x7D_0x80[4];
-    };
-
-  public:
-    FSIOPowerManagement(AT24 &at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : FileSystemIoBase(at24c01, BSMV, bsmv, HMV, hmv) {}
-
-    /**
-     * \brief Read the VCNL4020 offset from memory
-     * @param buffer Content to write in from the memory
-     * @param idx Index of the VCNL4020 sensor
-     * @return FSIO return types
-     */
-    msg_t getVcnl4020Offset (uint16_t *buffer, uint8_t idx);
-
-    /**
-     * \brief Write new data to the VCNL4020 offset
-     * @param buffer Content to write to the memory
-     * @param idx Index of the VCNL4020 sensor
-     * @return FSIO return types
-     */
-    msg_t setVcnl4020Offset (uint16_t buffer, uint8_t idx);
-};
-
-}
-}
-
-#endif /* AMIRO_FSIOPOWERMANAGEMENT_H_ */
diff --git a/include/amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp b/include/amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp
deleted file mode 100644
index a156228..0000000
--- a/include/amiro/FileSystemInputOutput/FileSystemInputOutputBase.hpp
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifndef AMIRO_FILESYSTEMIO_H_
-#define AMIRO_FILESYSTEMIO_H_
-
-/*! \brief memory layouts for the eeproms
- *
- * This header defines the memory layout.
- * Every memory layout starts with a preamble
- * of 3 byte. The first one is a magic byte
- * for checking purpose. The second one declares
- * the byte structure major version (BSMV) and the third
- * the byte structure minor version (bsmv) of the subsequently
- * bytes in the memory. With different major versions, the
- * layout of the memory may totaly change, so one should
- * not read from such a different layout if the version
- * differs from the expected one. With greater minor
- * versions the old memory layout may not change, but
- * new elements emerge.
- */
-
-#include <amiro/eeprom/at24.hpp>
-
-namespace amiro {
-namespace fileSystemIo {
-
-class FileSystemIoBase {
-
-  public:
-    AT24 &at24c01;
-    const uint8_t BSMV;
-    const uint8_t bsmv;
-    const uint8_t HMV;
-    const uint8_t hmv;
-    static constexpr uint8_t magicByteValue() { return 0xAAu;}
-
-    // TODO implement CRC check at 0x7D to 0x80
-    /** \brief Global memory structure */
-    struct preamble_1_1 {
-      uint8_t magicByte;
-      uint8_t byteStructureMajorVersion;
-      uint8_t byteStructureMinorVersion;
-      uint8_t hardwareMajorVersion;
-      uint8_t hardwareMinorVersion;
-      uint8_t reserved_0x05_0x14[15];
-    };
-
-    struct preamble_1_2 {
-      uint8_t reserved_0x00_0x04[5];
-      uint8_t boardId;
-      uint8_t reserved_0x06_0x14[14];
-    };
-
-    /** \brief FSIO return types */
-    enum{
-      OK                    = 0x00u,
-      NOT_IMPLEMENTED       = 0x01u,
-      WRONG_BSMV            = 0x02u,
-      WRONG_bsmv            = 0x04u,
-      IO_ERROR              = 0x08u,
-      WRONG_MAGICBYTE_VALUE = 0x10u,
-      WRONG_INDEX           = 0x20u,
-      WRONG_HMV             = 0x40u,
-      WRONG_hmv             = 0x80u,
-    };
-
-  public:
-
-    FileSystemIoBase(AT24 &at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : at24c01(at24c01),
-        BSMV(BSMV),
-        bsmv(bsmv),
-        HMV(HMV),
-        hmv(hmv) {
-     }
-
-    /**
-     * \brief Checks the values stored in the memory and compares the set version numbers and the version numbers found.
-     *        If the magic byte is incorrect WRONG_MAGICBYTE_VALUE is returned.
-     *        If the BMSVs are not equal WRONG_BSMV is returned.
-     *        If the bmsv found in the memory is smaller, the missing elements are initialized with default values and WRONG_bsmv is returned.
-     *        If the bmsv found in the memory is equal or greater OK is returned.
-     *        If the HMVs are not equal WRONG_HMV is returned.
-     *        If the mmvs are not equal WRONG_hmv is returned.
-     * @return FSIO return types
-     */
-    msg_t init();
-
-    /**
-     * \brief Check the memory structure
-     * @return FSIO return types
-     */
-    msg_t getCheck();
-
-    /**
-     * @brief Initializes the memory of the given preamble with default values.
-     * @param[in] BSMV The Byte Structure Major Version to initialize.
-     * @param[in] bsvm The Byte Structure Minor Version to initialize.
-     * @param[in] strict Specifies whether all (true) or only new (false) values are written to the memory.
-     * @return FSIO return types
-     */
-    msg_t initPreamble(const uint8_t BSMV, const uint8_t bsmv, const bool strict = true);
-
-    /**
-     * \brief Initializes the memory with the given structure
-     * @return FSIO return types
-     */
-    msg_t resetMemory();
-
-    /**
-     * \brief Writes the board id to the eeprom
-     * @return FSIO return types
-     */
-    msg_t setBoardId (uint8_t buffer);
-
-    /**
-     * \brief Reads the board id from the eeprom
-     * @return FSIO return types
-     */
-    msg_t getBoardId (uint8_t *buffer);
-
-};
-
-}
-}
-
-#endif /* AMIRO_FILESYSTEMIO_H_ */
diff --git a/include/amiro/Lidar.h b/include/amiro/Lidar.h
deleted file mode 100644
index c11895f..0000000
--- a/include/amiro/Lidar.h
+++ /dev/null
@@ -1,261 +0,0 @@
-#ifndef LIDAR_H_
-#define LIDAR_H_
-
-// Top view
-/*                                                 __________
-//                                               /     |     \
-//                                              /      O      \
-//                                             /  H O K U Y O  \
-//                                             |                |
-//                                             |                |
-//                                              \    U R G     /
-// scannedData[NUMBER_OF_STEPS] = END_STEP       \/          \/   STARTING_STEP = scannedData[0]
-//                                                \__________/
-*/
-
-#include <string.h> // memcpy
-#include <stdlib.h>
-
-#include <amiro/bus/spi/HWSPIDriver.hpp>
-#include <amiro/Constants.h> // CAN::LIGHT_RING_ID
-#include <ch.hpp>
-#include <hal.h>
-#include <chprintf.h>
-#include <evtimer.h>
-
-// DO CONFIGURATION HERE : START
-// Important: SD_SPEED_PREFIX + SD_SPEED has to have 6 characters: e.g. 019200 or 115200
-#define SD_SPEED_PREFIX   // Prefix < 0     | 0     |        |        |        |        >
-#define SD_SPEED 250000 // Baudrate < 19200 | 57600 | 115200 | 250000 | 500000 | 750000 >
-#define UPDATE_LIDAR_PERIOD_MSEC MS2ST(1000)  // Periodic sensor value fetch in ms
-// Scan acquire message : START
-// Uncomment the specific character decoding to make it available
-#define USE_2CHAR_CODE
-// #define USE_3CHAR_CODE  // TODO Not implemented yet
-#define DATA_ACQ_2CHAR_CODE "MS"
-#define DATA_ACQ_3CHAR_CODE "MD"
-// Important: STARTING_STEP_PREFIX + STARTING_STEP has to have 4 characters: e.g. 0005 0044 0320
-#define STARTING_STEP_PREFIX 00
-#define STARTING_STEP 44
-// Important: END_STEP_PREFIX + END_STEP has to have 4 characters: e.g. 0005 0725 0320
-#define END_STEP_PREFIX 0
-#define END_STEP 725
-#define CLUSTER_COUNT 00
-#define SCAN_INTERVALL 0
-#define NUMBER_OF_INTERVALL 01
-// Scan acquire message : END
-// DO CONFIGURATION HERE : END
-
-// Internal calculations and definitions
-#if defined(USE_2CHAR_CODE) && defined(USE_3CHAR_CODE)
-#  error("USE_2CHAR_CODE and USE_3CHAR_CODE are defined. Only one of them is allowed!")
-#elif !defined(USE_2CHAR_CODE) && !defined(USE_3CHAR_CODE)
-#  error("USE_2CHAR_CODE and USE_3CHAR_CODE are not defined. Define one of them!")
-#elif defined(USE_2CHAR_CODE)
-#  define DATA_ACQ_CODE DATA_ACQ_2CHAR_CODE
-#  define NUMBER_OF_CHARACTERS (END_STEP - STARTING_STEP + 1) * 2
-#elif defined(USE_3CHAR_CODE)
-#  define DATA_ACQ_CODE DATA_ACQ_3CHAR_CODE
-#  define NUMBER_OF_CHARACTERS (END_STEP - STARTING_STEP + 1) * 3
-#endif
-#define NUMBER_OF_STEPS (END_STEP - STARTING_STEP + 1)
-
-#define STR_HELPER(x) #x
-#define STR(x) STR_HELPER(x)
-
-#define LF "\n"
-
-namespace amiro {
-
-  class Lidar : public chibios_rt::BaseStaticThread<256> {
-  public:
-    /**
-    * Possible setups for the LIDAR: POWER_ONLY (The LIDAR will be powererd, but no serial IO is performed [Need for USB IO]); SERIAL_IO (Power and serial communication via lidar driver)
-    */
-    enum SETUP {POWER_ONLY, SERIAL_IO};
-
-    /**
-    * Writes the last scan into the given array
-    *
-    * @param scanData Array of size NUMBER_OF_STEPS which will be override
-    *                 with the scanned data
-    *
-    * @return True if scanData holds the current data, False if no data have been copied
-    */
-    bool_t getScan(uint16_t (&scanData)[NUMBER_OF_STEPS]);
-
-    /**
-    * Returns the value NUMBER_OF_STEPS which is the amount of datapoints per scan
-    *
-    * @return Amount of data in one scan
-    */
-    uint16_t getNumberOfValues();
-
-  protected:
-    virtual msg_t main();
-
-    /**
-    * Do a scan and update the datapoints in scanData
-    */
-    msg_t updateSensorVal();
-
-    /**
-    * Print received data until "\n\n" was received
-    */
-    void printData();
-
-    /**
-    * Receive data until "\n\n" and compare it to the given string
-    * Note: If the command did not work, use printData() instead
-    *       and compare the reply with chapter "9. Response to Invalid Commands"
-    *
-    * @param compareString String to compare with
-    *
-    * @return True if string was equal, false if not
-    */
-    bool_t checkDataString(const char compareString[]);
-    /**
-    *  Send the command which let the LIDAR send its details
-    */
-    void printDetails();
-
-    /**
-    *  Send the command which let the LIDAR send its specifications
-    */
-    void printSpecification();
-
-    /**
-    *  Send the command which let the LIDAR send its information
-    */
-    void printInformation();
-
-    /**
-    *  Tells you, if the sensor is ready for work
-    *
-    *  @return True for operability, False if not
-    */
-    inline bool_t getIsReady();
-
-    /**
-    *  Do the two character encoding after the manual
-    *
-    *  @param char1 High character
-    *  @param char2 Low character
-    *
-    *  @return Encoded data
-    */
-    inline uint16_t twoCharacterEncoding(uint8_t &char1, uint8_t &char2);
-
-    /**
-    *  Blocking function which writes the received character to the given variable
-    *
-    *  @param data Container for the variable
-    *  @param timeoutMs Timeout in millisecond
-    *
-    *  @return True if data was received, False if timed out (NOTE timeoutMs should by much smaller than UPDATE_LIDAR_PERIOD_MSEC)
-    */
-    bool_t getData(uint8_t &data, uint32_t timeoutMs);
-
-    /**
-    * Container for the scanned data
-    *
-    * @brief The "+1" character is for holding the last sum which is transmitted
-    *        by the LIDAR. It is not used, but it makes the algorithm much easier
-    *        we we do not care about it
-    */
-    static uint8_t scannedData[NUMBER_OF_CHARACTERS + 1];
-
-    /**
-    *  Flushes the input queue of the SD2 serial device
-    */
-    inline void flushSD2InputQueue();
-
-    /**
-    * Possible states for the receiver state machine
-    */
-    enum STATE {SEND_SCAN_CMD, DATA_VALID_CHECK, DATA_START_CHECK, DATA_RECORD, DATA_DECODE, DATA_SHOW, FAIL, FINISH};
-
-    /**
-    * Current state of the machine
-    */
-    STATE step = SEND_SCAN_CMD;
-
-    /**
-    * This is the status which comes after the command echo "\n99b\n"
-    */
-    const uint8_t validScanTag[5] =  {10,57,57,98,10};
-
-    /**
-    * Index for the received status
-    */
-    uint8_t checkStatusIdx = 0;
-
-    /**
-    * Index for the received status
-    */
-
-    /**
-    * Hold the board id
-    */
-    uint8_t boardId;
-
-    /**
-    * Hold the setup configuration for the lidar
-    */
-    SETUP setup;
-
-    /**
-    * Holds the current input
-    */
-    uint8_t newInput = 0xFF;
-
-    /**
-    * Holds the last input
-    */
-    uint8_t lastInput = 0xFF;
-
-    /**
-    * Counter for the received characters of the data points
-    */
-    uint16_t dataIdx = 0;
-
-    /**
-    * Temporary variable which hold the amount of receved bytes
-    */
-    uint32_t dataCounter = 0;
-
-    /**
-    * Holds the information, if scannedData holds the last sensor scan
-    */
-    bool_t isReady = false;
-
-    /**
-    * Holds the information, if the datachunk was not transmitted completely
-    */
-    bool_t isFail = false;
-
-  private:
-
-    EvTimer evtimer;
-
-  public:
-  /**
-    * Constructor
-    *
-    * @param boardId Board ID which can be found in ControllerAreaNetwork.h.
-    *                It is used to setup the LIDAR for exactly this board
-    */
-    Lidar(const uint8_t boardId, Lidar::SETUP setup);
-
-    /**
-    * Constructor
-    *
-    * Disable the LIDAR
-    * TODO Why "virtual ~Lidar() = 0;"
-    */
-    ~Lidar();
-
-  };
-
-}
-#endif /* LIDAR_H_ */
diff --git a/include/amiro/MotorControl.h b/include/amiro/MotorControl.h
deleted file mode 100644
index f9b36c6..0000000
--- a/include/amiro/MotorControl.h
+++ /dev/null
@@ -1,278 +0,0 @@
-#ifndef AMIRO_MOTOR_CONTROL_H_
-#define AMIRO_MOTOR_CONTROL_H_
-
-#include <amiro/MotorIncrements.h>
-#include <amiro/Constants.h>
-#include <Types.h>
-#include <amiro/FileSystemInputOutput/FSIODiWheelDrive.hpp>
-
-namespace amiro {
-
-  class MotorControl : public chibios_rt::BaseStaticThread<512> {
-  public:
-    /**
-     * Constructor
-     *
-     * @param pwm pulse width modulation driver (pwmd)
-     *            Can be any free PWMDx in 'ChibiOS-RT/os/hal/platforms/STM32/TIMv1/pwm_lld.h'
-     * @param mi object for retrieving the motor increments of the qei
-     * @param port GPIO port for motor control (should be the macro 'GPIOB')
-     * @param pad GPIO command for motor control (should be the macro 'GPIOB_POWER_EN' for enable)
-     * @param memory Memory interface to load/store parameters
-     */
-    MotorControl(PWMDriver* pwm, MotorIncrements* mi, GPIO_TypeDef* port, int pad, fileSystemIo::FSIODiWheelDrive *memory);
-
-    /**
-     * Get the current speed of the left wheel in rounds/min
-     *
-     * @return speed of left wheel in rounds/min
-     */
-    int getCurrentRPMLeft();
-
-    /**
-     * Get the current speed of the right wheel in rounds/min
-     *
-     * @return speed of right wheel in rounds/min
-     */
-    int getCurrentRPMRight();
-
-    chibios_rt::EvtSource* getEventSource();
-
-    /**
-     * Sets the target velocity
-     *
-     * @param targetVelocity Kartesian kinematic vector
-     */
-    void setTargetSpeed(const types::kinematic &targetVelocity);
-
-    /**
-     * Sets the target velocity in µ rounds per minute for every wheel
-     *
-     * @param targetURpmLeft Rounds per minute in µ1/min of the left wheel
-     * @param targetURpmLeft Rounds per minute in µ1/min of the right wheel
-     */
-    void setTargetRPM(int32_t targetURpmLeft, int32_t targetURpmRight);
-
-    /**
-     * Get the current velocitiy as a kinematic struct
-     *
-     * @return Current velocity
-     */
-    types::kinematic getCurrentVelocity();
-
-    /**
-     * Sets the correction factor for the wheel diameter.
-     * The factor Ed is the ratio of the wheel diameters
-     * <Ed = wheelDiameterRight / wheelDiameterLeft> as
-     * introduced in eq. 3 by J. Borenstein (Correction of
-     * Systematic Odometry Errors in Mobile Robots). This
-     * function calculates then the correction factors for every
-     * wheel by eq. 17a and 17b.
-     *
-     * @param Ed Wheel diameter ratio
-     * @param storeEbToMemory Do override Ed in the memory with the given value
-     * @return Return value of the memory interface
-     */
-    msg_t setWheelDiameterCorrectionFactor(float Ed = 1.0f, bool_t storeEdToMemory = false);
-
-    /**
-     * Sets the correction factor for the wheel base width.
-     * The factor Eb is the ratio of the actual and nominal
-     * base width <Eb = bActual / bNominal> as introduced
-     * in eq. 3 by J. Borenstein (Correction of
-     * Systematic Odometry Errors in Mobile Robots). This
-     * function calculates then the actual base width of the
-     * robot using eq. 4.
-     *
-     * @param Eb Base width ratio
-     * @param storeEbToMemory Do override Eb in the memory with the given value
-     * @return Return value of the memory interface
-     */
-    msg_t setActualWheelBaseDistance(float Eb = 1.0f, bool_t storeEbToMemory = false);
-
-    /**
-     * Calculate the current increments of both wheels and
-     * update oldIncrement and incrementsDifference,
-     * which is the corrected difference between the current increments
-     * and the old ones.
-     * The corrected difference is the original difference between the old
-     * increments and new increments, multiplied with the wheelDiameterCorrectionFactor.
-     * The incremennt source is given by motorIncrements.
-     *
-     * @param motorIncrements Increment source
-     * @param oldIncrement Old increments, which are updated
-     * @param incrementDifference Corrected difference between old and current increments
-     * @return Return value of the memory interface
-     */
-    static void updateIncrements(MotorIncrements* motorIncrements, int32_t (&oldIncrement)[2], float (&incrementDifference)[2]);
-
-    /**
-     * Calculate the current speed of both wheels and
-     * updates actualSpeed.
-     *
-     * @param incrementDifference Difference between old and current increments
-     * @param actualSpeed Actual speed of both wheels
-     * @param Update period
-     */
-    static void updateSpeed(const float (&incrementDifference)[2], int32_t (&actualSpeed)[2], const uint32_t period);
-
-    /**
-     * Calculate the current driven distance of both wheels and
-     * updates actualDistance.
-     *
-     * @param incrementDifference Difference between old and current increments
-     * @param actualDistance Actual distance driven
-     */
-    static void updateDistance(const float (&incrementDifference)[2], float (&actualDistance)[2]);
-
-    /**
-     * Prints Control Gains
-     */
-    void printGains();
-
-    /**
-     * @brief Resets control gains.
-     */
-    void resetGains();
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-
-    /**
-     * Calculate the velocitiy in the robot frame
-     * and saves it to this->currentVelocity
-     */
-    void calcVelocity();
-
-    /**
-     * PID Controller that works directly on the forward velocity v of the robots center and its
-     * angular velocity w around its z axis. The methods setLeftWheelSpeed() and setRightWheelSpeed()
-     * are used to set the final pwm values.
-     */
-    void PIDController();
-
-    /**
-     * Deletes the oldest entry in lastVelocitiesV[] and lastVelocitiesW[], pushes the other values up and saves the currentVelocity.x(w_z) in the last entry.
-     */
-    void updateDerivativeLastVelocities();
-
-
-    ////////////////////////////////////////////////
-    /////////////////Calibration////////////////////
-    ////////////////////////////////////////////////
-    /**
-     * Finds a prefactor for the stronger motor to match its power level to the weaker motor.
-     */
-    void calibrate();
-
-    /**
-     * Finds the P, I and D gains for the PID Controller using the Nichols-Ziegler Method.
-     */
-    void calibrateZiegler();
-
-    /**
-     * Counts the number of sign changes from the last 30 velocities.
-     */
-    int getNumberofSignChanges();
-
-    /**
-     * Update the past lastVelocitiesV array.
-     */
-    void updatePastVelocities();
-
-
-    /**
-     * Sets wheel speed according to the output of the PID Controller
-     */
-    void setLeftWheelSpeed(int diffv, int diffw);
-    /**
-     * Sets wheel speed according to the output of the PID Controller
-     */
-    void setRightWheelSpeed(int diffv, int diffw);
-
-    int getLeftWheelSpeed();
-    int getRightWheelSpeed();
-
-
-    /**
-     * Write the duty cicle from this->pwmPercentage
-     * to the PWM driver
-     */
-    void writePulseWidthModulation();
-
-    /**
-     * Control logic to save space in main loop
-     */
-    void controllerAndCalibrationLogic();
-
-
-
-    PWMDriver* pwmDriver;
-    PWMConfig pwmConfig;
-    MotorIncrements* motorIncrements;
-    GPIO_TypeDef *powerEnablePort;
-    const int powerEnablePad;
-    chibios_rt::EvtSource eventSource;
-    //const uint32_t period;
-    uint32_t period;
-    fileSystemIo::FSIODiWheelDrive *memory;
-    int32_t actualSpeed[2];
-    float actualDistance[2];
-    float errorSum[2];
-    int32_t increment[2];
-    float incrementDifference[2];
-    int pwmPercentage[2];
-    types::kinematic targetVelocity;
-    types::kinematic currentVelocity;
-    types::kinematic lastVelocity;
-    float errorSumDiff;
-    bool newTargetVelocities;
-    int delay = 0;
-    float Ed;
-    float Eb;
-
-    int pGain = 1000;
-
-    float iGain = 0.08;
-    int antiWindupV = 7100000;
-    int antiWindupW = 200000000;
-    int accumulatedErrorV =0; // accumulated velocity error
-    int accumulatedErrorW =0; // accumulated omega error
-
-    float dGain =0.01;
-    int lastVelocitiesV[6];
-    int lastVelocitiesW[6];
-
-    //motor calibration variables
-    int numberOfLastVelocitiesV = 30;
-    int lastVelocitiesVBig[30];
-    int rightWValues[3];
-    int leftWValues[3];
-    float motorCalibrationFactor =1.0;
-    //ziegler calibration variables
-    int zieglerHelp= 1;
-    int zieglerHelp2 = 0;
-    bool ziegler= true;
-    bool ziegler2 = true;
-    float zieglerPeriod;
-    int zieglerCalibrationTime = 0;
-    int wheelCalibrationTime = 0;
-    bool startedZieglerCalibration = false;
-    bool startedWheelCalibration = false;
-    bool motorCalibration = true;
-
-
-
-
-  public:
-    bool isCalibrating = false;
-    static float wheelDiameterCorrectionFactor[2];
-    static float actualWheelBaseDistanceSI;
-
-
-  };
-}
-
-#endif /* AMIRO_MOTOR_CONTROL_H_ */
diff --git a/include/amiro/MotorIncrements.h b/include/amiro/MotorIncrements.h
deleted file mode 100644
index ef73f1c..0000000
--- a/include/amiro/MotorIncrements.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef AMIRO_MOTOR_INCREMENTS_H_
-#define AMIRO_MOTOR_INCREMENTS_H_
-
-namespace amiro {
-
-  class MotorIncrements {
-
-    public:
-    /**
-     * Constructor
-     * This only creates the config. To start the qei driver, one needs to call
-     * qeiInit() after halInit() in the main process first. Then run this->start().
-     *
-     * @param qei0 quadrature encoder for left wheel from 'amiro-os/hal/include/qei.h'
-     * @param qei0 quadrature encoder for right wheel from 'amiro-os/hal/include/qei.h'
-     */
-    MotorIncrements(QEIDriver* qei0, QEIDriver* qei1);
-
-    /**
-     * Get the encoder position
-     *
-     * @return position of the encode
-     */
-    int qeiGetPosition(int idxQei);
-
-    /**
-     * Get the range of the qei config
-     *
-     * @return value of the range of the qei
-     */
-    int getQeiConfigRange();
-
-    /**
-     * Starts the qei driver (First run qeiInit() in the main process)
-     */
-    void start();
-
-  private:
-    QEIDriver* qeiDriver[2];
-    QEIConfig qeiConfig;
-  };
-
-}
-
-#endif /* AMIRO_MOTOR_INCREMENTS_H_ */
diff --git a/include/amiro/Odometry.h b/include/amiro/Odometry.h
deleted file mode 100644
index af4a513..0000000
--- a/include/amiro/Odometry.h
+++ /dev/null
@@ -1,99 +0,0 @@
-#ifndef AMIRO_ODOMETRY_H_
-#define AMIRO_ODOMETRY_H_
-
-#include <amiro/MotorControl.h>
-#include <amiro/gyro/l3g4200d.hpp>
-
-#include <Types.h> // types::position
-
-namespace amiro {
-
-  class Odometry : public chibios_rt::BaseStaticThread<512> {
-  public:
-    /**
-     * Constructor
-     *
-     * @param mi object for retrieving the motor increments of the qei
-     * @param gyro object for retrieving the gyroscope data
-     * @param mc object for retrieving calibration parameters
-     */
-    Odometry(MotorIncrements* mi, L3G4200D* gyroscope);
-
-    /**
-     * Set the position of the roboter
-     *
-     * @param pX Position x in meter
-     * @param pY Position y in meter
-     * @param pPhi Orientation phi in radiant
-     */
-    void setPosition(float pX, float pY, float pPhi);
-
-    /**
-     * Reset the position to [0,0,0]
-     */
-    void resetPosition();
-
-    /**
-     * Set the position of the roboter
-     *
-     * @param *Cp
-     */
-    void setError(float* Cp);
-
-    /**
-     * Reset the error to [0,0,0;0,0,0;0,0,0]
-     */
-    void resetError();
-
-    /**
-     * Updates the wheelBaseDistance variable,
-     * because it may change after an calibration.
-     */
-    void updateWheelBaseDistance();
-
-    /**
-     * Get the current position
-     * @return position
-     */
-    types::position getPosition();
-
-    chibios_rt::EvtSource* getEventSource();
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-
-    /**
-     * Calculate the actual distance of both wheels
-     */
-    void updateDistance();
-
-    /**
-     * This is th PID controller for controling
-     * the speed. It gets the new duty cicle for the pwm
-     * and saves it to this->pwmPercentage to reach the
-     * target speed this->targetSpeed
-     */
-    void updateOdometry();
-
-    MotorIncrements* motorIncrements; // QEI driver
-    L3G4200D* gyro;  // Gyroscope driver
-    chibios_rt::EvtSource eventSource;
-    const unsigned int period;
-    int incrementsPerRevolution;
-    int updatesPerMinute;
-    float wheelCircumference; // wheel circumference in meter
-    float wheelBaseDistanceSI; // Base width in meter
-    float distance[2]; // Moved distance per wheel in meter left:0 right:1
-    float wheelError[2]; // error for left:0 and right:1 wheel
-    float pX, pY; // Position in meter
-    float pPhi; // Orientation in Rad
-    float Cp3x3[9];  // Covariance (position error) (3x3 matrix)
-    int32_t increment[2]; // Absolute number of difference since last update
-    float incrementDifference[2]; // Difference between old and current absolute increments
-  };
-
-}
-
-#endif /* AMIRO_ODOMETRY_ */
diff --git a/include/amiro/accel/lis331dlh.hpp b/include/amiro/accel/lis331dlh.hpp
deleted file mode 100644
index 2604d34..0000000
--- a/include/amiro/accel/lis331dlh.hpp
+++ /dev/null
@@ -1,275 +0,0 @@
-#ifndef LIS331DLH_HPP_
-#define LIS331DLH_HPP_
-
-#include <ch.hpp>
-
-namespace amiro {
-
-  class HWSPIDriver;
-
-  class LIS331DLH : public chibios_rt::BaseStaticThread<256> {
-
-  public:
-
-  struct InterruptConfig {
-
-    uint8_t config;
-    uint8_t ths;
-    uint8_t duration;
-
-  } __attribute__((packed));
-
-  struct LIS331DLHConfig {
-    uint8_t         ctrl1;
-    uint8_t         ctrl2;
-    uint8_t         ctrl3;
-    uint8_t         ctrl4;
-    uint8_t         ctrl5;
-    InterruptConfig int1_cfg;
-    InterruptConfig int2_cfg;
-  };
-
-  enum {
-    AOI_OR_INT  = 0x00u,
-    AOI_6MOVE   = 0x40u,
-    AOI_AND_INT = 0x80u,
-    AOI_6POS    = 0xC0u,
-    ZHIE        = 0x20u,
-    ZLIE        = 0x10u,
-    YHIE        = 0x08u,
-    YLIE        = 0x04u,
-    XHIE        = 0x02u,
-    XLIE        = 0x01u,
-  };
-
-  enum {
-    IA          = 0x40u,
-    ZH          = 0x20u,
-    ZL          = 0x10u,
-    YH          = 0x08u,
-    YL          = 0x04u,
-    XH          = 0x02u,
-    XL          = 0x01u,
-  };
-
-  enum {
-    THS_MASK      = 0x7Fu,
-  };
-
-  enum {
-    DURATION_MASK = 0x7Fu,
-  };
-
-  enum {
-    PM_OFF          = 0x00u,
-    PM_ODR          = 0x20u,
-    PM_0_5_HZ       = 0x40u,
-    PM_1_HZ         = 0x60u,
-    PM_2_HZ         = 0x80u,
-    PM_5_HZ         = 0xA0u,
-    PM_10_HZ        = 0xC0u,
-    DR_50HZ_37LP    = 0x00u,
-    DR_100HZ_74LP   = 0x08u,
-    DR_400HZ_292LP  = 0x10u,
-    DR_1000HZ_780LP = 0x18u,
-    ZEN             = 0x04u,
-    YEN             = 0x02u,
-    XEN             = 0x01u,
-  };
-
-  enum {
-    BOOT_REBOOT  = 0x80u,
-    HPM_NORMAL0  = 0x00u,
-    HPM_REF      = 0x20u,
-    HPM_NORMAL1  = 0x40u,
-    FDS_FILTER   = 0x10u,
-    HPEN_INT2    = 0x08u,
-    HPEN_INT1    = 0x04u,
-    HPCF_8       = 0x00u,
-    HPCF_16      = 0x01u,
-    HPCF_32      = 0x02u,
-    HPCF_64      = 0x03u,
-  };
-
-  enum {
-    INT_HIGH     = 0x00u,
-    INT_LOW      = 0x80u,
-    PUSH_PULL    = 0x00u,
-    OPEN_DRAIN   = 0x40u,
-    LIR2_LATCH   = 0x20u,
-    I2_CFG_I2    = 0x00u,
-    I2_CFG_I1_I2 = 0x08u,
-    I2_CFG_DRY   = 0x10u,
-    I2_CFG_BOOT  = 0x18u,
-    LIR1_LATCH   = 0x04u,
-    I1_CFG_I1    = 0x00u,
-    I1_CFG_I1_I2 = 0x01u,
-    I1_CFG_DRY   = 0x02u,
-    I1_CFG_BOOT  = 0x03u,
-  };
-
-  enum {
-    BDU_CONT = 0x00u,
-    BDU_STOP = 0x80u,
-    BLE_LE   = 0x00u,
-    BLE_BE   = 0x40u,
-    FS_2G    = 0x00u,
-    FS_4G    = 0x10u,
-    FS_8G    = 0x30u,
-    STSIGN_POS = 0x00u,
-    STSIGN_NEG = 0x08u,
-    ST_DISABLE = 0x00u,
-    ST_ENABLE  = 0x02u,
-    SIM_4WI    = 0x00u,
-    SIM_3WI    = 0x01u,
-  };
-
-  enum {
-    SLEEP_TO_WAKE_OFF = 0x00u,
-    SLEEP_TO_WAKE_ON  = 0x03u,
-  };
-
-  /**
-   * Return types of getCheck()
-   */
-  enum {
-    CHECK_OK   = 0x00,
-    CHECK_FAIL = 0x01,
-  };
-
-  /**
-  * Top view of the AMiRo with charger in the back (F:Front, B:Back).
-  * Z is pointing into the ground (Apply right-hand-rule):
-  *    ___________
-  *   /    F      \
-  *  /     X       \
-  * |      |        |
-  * |      Z---Y    |
-  * |               |
-  *  \             /
-  *   \____B______/
-  */
-  enum {
-    AXIS_X   = 0x00u,
-    AXIS_Y   = 0x01u,
-    AXIS_Z   = 0x02u,
-  };
-
-  //private:
-
-  struct registers {
-    uint8_t  reserved_0x00_0x0E[0x0Fu];
-    uint8_t  who_am_i;
-    uint8_t  reserved_0x10_0x1F[0x10u];
-    uint8_t  ctrl_reg1;
-    uint8_t  ctrl_reg2;
-    uint8_t  ctrl_reg3;
-    uint8_t  ctrl_reg4;
-    uint8_t  ctrl_reg5;
-    uint8_t  hp_filter_reset;
-    uint8_t  reference;
-    uint8_t  status_reg;
-    uint16_t out_x; /* LE */
-    uint16_t out_y; /* LE */
-    uint16_t out_z; /* LE */
-    uint8_t  reserved_0x2E_0x2F[0x02u];
-    uint8_t  int1_cfg;
-    uint8_t  int1_src;
-    uint8_t  int1_ths;
-    uint8_t  int1_duration;
-    uint8_t  int2_cfg;
-    uint8_t  int2_src;
-    uint8_t  int2_ths;
-    uint8_t  int2_duration;
-    uint8_t  reserved_0x38_0x3F[0x08u];
-  } __attribute__((packed));
-
-  enum {
-    LIS331DLH_ID = 0x32u
-  };
-
-  enum {
-    ZYXOR = 0x80,
-    ZOR   = 0x40,
-    YOR   = 0x20,
-    XOR   = 0x10,
-    ZYXDA = 0x08,
-    ZDA   = 0x04,
-    YDA   = 0x02,
-    XDA   = 0x01,
-  };
-
-  enum {
-    SPI_MULT  = 0x40u,
-    SPI_READ  = 0x80u,
-    SPI_WRITE = 0x00u,
-  };
-
-  public:
-    LIS331DLH(HWSPIDriver* driver);
-    virtual ~LIS331DLH();
-
-    chibios_rt::EvtSource* getEventSource();
-    msg_t configure(LIS331DLHConfig* config);
-
-    /**
-    * Return the accelaration in LSB for the given axis.
-    *
-    * @param axis can be one of the axis [AXIS_X | AXIS_Y | AXIS_Z]
-    *
-    * @return Measured accelaration in in LSB for the given axis
-    */
-    int16_t getAcceleration(const uint8_t axis);
-
-    /**
-    * Return the accelaration in milli g for the given axis
-    *
-    * @param axis can be one of the axis [AXIS_X | AXIS_Y | AXIS_Z]
-    *
-    * @return Measured accelaration in in milli g for the given axis
-    */
-    int16_t getAccelerationForce(const uint8_t axis);
-
-    /**
-     * Check the presence of the accelerometer by reading
-     * the identifier register and comparing it to the standard
-     * value
-     *
-     * @return [CHECK_OK | CHECK_FAIL]
-     */
-    uint8_t getCheck();
-
-    /**
-     * Do the build in self-test of the device by applying
-     * an electrostatic force and measuring the amplitude.
-     * The result is then checked against the standard values
-     * of the manual
-     * TODO Check if it works correct
-     *
-     * @param config A working config as template (if NULL, predefined config is taken)
-     */
-    void printSelfTest(LIS331DLHConfig* config);
-
-  protected:
-    virtual msg_t main();
-
-  private:
-    inline void updateSensorData();
-
-  private:
-
-    HWSPIDriver* driver;
-    chibios_rt::EvtSource eventSource;
-    int16_t accelerations[AXIS_Z - AXIS_X + 1];
-    /**
-    * Stores the configuration [FS_2G | FS_4G | FS_8G] of
-    * the current setup
-    */
-    uint8_t currentFullScaleConfiguration;
-
-
-  };
-
-} /* amiro */
-
-#endif /* LIS331DLH_HPP_ */
diff --git a/include/amiro/bluetooth/bluetooth-connector.hpp b/include/amiro/bluetooth/bluetooth-connector.hpp
deleted file mode 100644
index 6bda6eb..0000000
--- a/include/amiro/bluetooth/bluetooth-connector.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _BLUETOOTH_CONNECTOR_H_
-#define _BLUETOOTH_CONNECTOR_H_
-
-#include <amiro/bluetooth/bluetooth.hpp>
-
-namespace amiro {
-
-  class BluetoothConnector {
-  public:
-    BluetoothConnector(BLUETOOTH *bluetooth, void *bluetoothDev, const char *typeConn);
-
-    void bluetoothConnectorListen(const char *addr);
-    void bluetoothConnectorConnect(const char *addr);
-    void bluetoothConnectorDisconnect(const char *addr);
-
-  private:
-    void bluetoothConnectorActivate(uint8_t linkid);
-    void bluetoothConnectorDeactivate();
-
-    BluetoothIwrap *iwrap;
-    void * objDev;
-    const char *typeDev;
-  };
-}
-
-#endif /* _BLUETOOTH_CONNECTOR_H_ */
diff --git a/include/amiro/bluetooth/bluetooth-descriptor.hpp b/include/amiro/bluetooth/bluetooth-descriptor.hpp
deleted file mode 100644
index fb4aeb0..0000000
--- a/include/amiro/bluetooth/bluetooth-descriptor.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _BLUETOOTH_DESCRIPTOR_H_
-#define _BLUETOOTH_DESCRIPTOR_H_
-
-#include <string.h>
-
-#define BLUETOOTH_DESCRIPTOR_BUFFER_SIZE 64
-
-namespace amiro {
-
-  class BluetoothDescriptor {
-
-  public:
-    BluetoothDescriptor();
-
-    void bluetoothDescriptorSetLinkId(uint8_t linkId);
-    void bluetoothDescriptorSetPayloadLength(size_t length);
-
-    uint8_t bluetoothDescriptorGetLinkId();
-    size_t bluetoothDescriptorGetBufferLength();
-    size_t bluetoothDescriptorGetPayloadLength();
-
-    uint8_t *bluetoothDescriptorGetBuffer();
-    uint8_t *bluetoothDescriptorGetPayload();
-
-  private:
-//    unsigned char flags;
-    uint8_t linkId;
-    size_t length;
-    uint8_t buffer[BLUETOOTH_DESCRIPTOR_BUFFER_SIZE];
-
-  };
-}
-
-#endif /* _BLUETOOTH_DESCRIPTOR_H_ */
diff --git a/include/amiro/bluetooth/bluetooth-iwrap.hpp b/include/amiro/bluetooth/bluetooth-iwrap.hpp
deleted file mode 100644
index e564a0d..0000000
--- a/include/amiro/bluetooth/bluetooth-iwrap.hpp
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _BLUETOOTH_IWRAP_H_
-#define _BLUETOOTH_IWRAP_H_
-
-#include <amiro/bluetooth/bluetooth-transport.hpp>
-#include <amiro/bluetooth/bluetooth-profile.hpp>
-
-#if !CH_USE_QUEUES || !CH_USE_EVENTS
-#error "Bluetooth Serial Port Profile requires CH_USE_QUEUES, CH_USE_EVENTS"
-#endif
-
-#define BLUETOOTH_IWRAP_MAILBOX_SIZE  5
-
-#define HOST_IWRAP_PLAIN_LINKID       0xFF
-
-namespace amiro {
-
-  class BluetoothIwrap : public chibios_rt::BaseStaticThread<128> {
-  public:
-    BluetoothIwrap(UARTDriver* uart);
-
-    void bluetoothIwrapSendCommand(const char* cmd);
-    msg_t iwrapTransmit(uint8_t linkid, const uint8_t* txdata, size_t length);
-
-    BluetoothTransport transport;
-
-    BluetoothProfile profiles[8];
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-    msg_t iwrapReceive();
-
-    chibios_rt::Mailbox mailbox;
-    msg_t mailboxBuffer[BLUETOOTH_IWRAP_MAILBOX_SIZE];
-
-    char connAddr[17];
-    int iwrapblock;
-  };
-}
-
-#endif /* _BLUETOOTH_IWRAP_H_ */
diff --git a/include/amiro/bluetooth/bluetooth-profile.hpp b/include/amiro/bluetooth/bluetooth-profile.hpp
deleted file mode 100644
index f5de805..0000000
--- a/include/amiro/bluetooth/bluetooth-profile.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef _BLUETOOTH_PROFILE_H_
-#define _BLUETOOTH_PROFILE_H_
-
-#define NO_RX_TX  0
-#define TX_ONLY   1
-#define RX_ONLY   2
-#define RX_TX     3
-
-namespace amiro {
-
-  class BluetoothConnector;
-
-  class BluetoothProfile {
-  public:
-    BluetoothProfile() {};
-
-    const char *addr;
-    void *connector;
-    void (BluetoothConnector::*connect) (uint8_t linkid);
-    void (BluetoothConnector::*disconnect) ();
-    uint8_t linkid;
-  };
-}
-
-#endif /* _BLUETOOTH_PROFILE_H_ */
diff --git a/include/amiro/bluetooth/bluetooth-serial.hpp b/include/amiro/bluetooth/bluetooth-serial.hpp
deleted file mode 100644
index 7e7e3cb..0000000
--- a/include/amiro/bluetooth/bluetooth-serial.hpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef _BLUETOOTH_SERIAL_H_
-#define _BLUETOOTH_SERIAL_H_
-
-#include <amiro/bluetooth/bluetooth-connector.hpp>
-
-#define BLUETOOTH_SERIAL_MAILBOX_SIZE 5
-
-#define SERIAL_START_EVENT  1
-#define SERIAL_STOP_EVENT   2
-
-namespace amiro {
-  class BluetoothSerial : public chibios_rt::BaseStaticThread<128> {
-  public:
-    BluetoothSerial(BLUETOOTH *bluetooth, uint8_t rxtx);
-
-    void bluetoothSerialStart(uint8_t linkid);
-    void bluetoothSerialStop();
-    bool bluetoothSerialIsConnected();
-
-    void bluetoothSerialListen(const char *addr);
-    void bluetoothSerialConnect(const char *addr);
-    void bluetoothSerialDisconnect(const char *addr);
-
-    msg_t serialTransmit(const uint8_t* serialdata, size_t length);
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-    msg_t serialReceive();
-
-    BluetoothConnector serialConn;
-    uint8_t rx_tx;
-
-    chibios_rt::Mailbox mailbox;
-    msg_t mailboxBuffer[BLUETOOTH_SERIAL_MAILBOX_SIZE];
-
-    BluetoothIwrap *iwrap;
-    uint8_t linkId;
-    uint8_t stopflag;
-  };
-}
-#endif /* _BLUETOOTH_SERIAL_H_ */
diff --git a/include/amiro/bluetooth/bluetooth-transport.hpp b/include/amiro/bluetooth/bluetooth-transport.hpp
deleted file mode 100644
index 7968708..0000000
--- a/include/amiro/bluetooth/bluetooth-transport.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef _BLUETOOTH_TRANSPORT_H_
-#define _BLUETOOTH_TRANSPORT_H_
-
-#include <amiro/bluetooth/bluetooth-descriptor.hpp>
-
-#define BLUETOOTH_TRANSPORT_STORAGE_MAILBOX_SIZE   10
-#define BLUETOOTH_TRANSPORT_TRANSMIT_MAILBOX_SIZE   5
-
-#define TRANSMIT_COMPLETED_EVENT  1
-
-#define FRAME_HEADER_SIZE    4
-#define FRAME_TRAILER_SIZE   1
-
-namespace amiro {
-
-  class BluetoothTransport : public chibios_rt::BaseStaticThread<128>, protected UARTConfig {
-  public:
-    BluetoothTransport(UARTDriver* uart);
-
-    chibios_rt::Mailbox* bluetoothTransportGetStorageMailbox();
-    chibios_rt::Mailbox* bluetoothTransportGetTransmitMailbox();
-
-    void bluetoothTransportSetReceiveMailbox(uint8_t linkId, chibios_rt::Mailbox* mailbox);
-    void bluetoothTransportResetState();
-    bool bluetoothTransportIsMuxMode();
-
-  protected:
-    virtual msg_t main(void);
-
-    virtual void bluetoothTransportTransmitCompleted();
-    virtual void bluetoothTransportCharacterReceived(uint16_t c);
-    virtual void bluetoothTransportReceiveCompleted();
-
-  private:
-    static void bluetoothTransportTransmitCompleted_cb(UARTDriver *uart);
-    static void bluetoothTransportCharacterReceived_cb(UARTDriver *uart, uint16_t c);
-    static void bluetoothTransportReceiveCompleted_cb(UARTDriver *uart);
-
-    UARTDriver *uart;
-
-    chibios_rt::Mailbox* receiveMailbox[10];
-    chibios_rt::Mailbox storageMailbox;
-    chibios_rt::Mailbox transmitMailbox;
-
-    msg_t storageMailboxBuffer[BLUETOOTH_TRANSPORT_STORAGE_MAILBOX_SIZE];
-    msg_t transmitMailboxBuffer[BLUETOOTH_TRANSPORT_TRANSMIT_MAILBOX_SIZE];
-
-    enum BluetoothTransportState {
-      BLUETOOTH_TRANSPORT_PLAIN   = 0,
-      BLUETOOTH_TRANSPORT_HEADER  = 1,
-      BLUETOOTH_TRANSPORT_DECODE  = 2,
-      BLUETOOTH_TRANSPORT_PAYLOAD = 3,
-      BLUETOOTH_TRANSPORT_TRAILER = 4,
-      BLUETOOTH_TRANSPORT_IDLE    = 5
-    }transmitState, receiveState;
-
-    BluetoothDescriptor descriptor[BLUETOOTH_TRANSPORT_STORAGE_MAILBOX_SIZE];
-    BluetoothDescriptor *receive;
-    BluetoothDescriptor *transmit;
-
-    size_t rcvlength;
-
-    /* These arrays Contain header and trailer */
-    uint8_t receiveFrameBuffer[5];
-    uint8_t transmitFrameBuffer[5];
-
-    void postReceiveDescriptorI();
-    void postTransmitDescriptorI();
-
-    uint8_t* getEncodeHeader();
-    uint8_t* getEncodeTailer();
-    int decodeHeader();
-  };
-}
-
-#endif /* _BLUETOOTH_TRANSPORT_H_ */
diff --git a/include/amiro/bluetooth/bluetooth-wiimote.hpp b/include/amiro/bluetooth/bluetooth-wiimote.hpp
deleted file mode 100644
index b1d312d..0000000
--- a/include/amiro/bluetooth/bluetooth-wiimote.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef _BLUETOOTH_WIIMOTE_H_
-#define _BLUETOOTH_WIIMOTE_H_
-
-#include <amiro/bluetooth/bluetooth-connector.hpp>
-
-#define BLUETOOTH_WIIMOTE_MAILBOX_SIZE 5
-
-#define WIIMOTE_START_EVENT  1
-#define WIIMOTE_STOP_EVENT   2
-
-namespace amiro {
-  class BluetoothWiimote : public chibios_rt::BaseStaticThread<128> {
-  public:
-    BluetoothWiimote(BLUETOOTH *bluetooth, uint8_t rxtx);
-
-    void bluetoothWiimoteStart(uint8_t linkid);
-    void bluetoothWiimoteStop();
-    bool bluetoothWiimoteIsConnected();
-
-    void bluetoothWiimoteListen(const char *addr);
-    void bluetoothWiimoteConnect(const char *addr);
-    void bluetoothWiimoteDisconnect(const char *addr);
-
-    msg_t wiimoteTransmit(const uint8_t* wiimotecmd, size_t length);
-    void bluetoothWiimoteLedVibrate(uint8_t ledid_flag, uint8_t vibrate_flag);
-    void bluetoothWiimoteStatusInfo();
-    void bluetoothWiimoteDataBtn();
-    void bluetoothWiimoteDataBtnAcc();
-
-    class Accelerometer {
-    public:
-      int16_t x_axis, y_axis, z_axis;
-    };
-    Accelerometer *getAccelerometer();
-
-    struct Buttons {
-      uint16_t left : 1;
-      uint16_t right : 1;
-      uint16_t down : 1;
-      uint16_t up : 1;
-      uint16_t plus : 1;
-      uint16_t two : 1;
-      uint16_t one : 1;
-      uint16_t B : 1;
-      uint16_t A : 1;
-      uint16_t minus : 1;
-      uint16_t home : 1;
-    };
-    Buttons* getButtons();
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-    msg_t wiimoteReceive();
-
-    BluetoothConnector wiimoteConn;
-    uint8_t rx_tx;
-
-    chibios_rt::Mailbox mailbox;
-    msg_t mailboxBuffer[BLUETOOTH_WIIMOTE_MAILBOX_SIZE];
-
-    BluetoothIwrap *iwrap;
-    uint8_t linkId;
-    uint8_t stopflag;
-
-    Accelerometer accelerometer;
-    Buttons buttons;
-  };
-}
-
-#endif /* _BLUETOOTH_WIIMOTE_H_ */
diff --git a/include/amiro/bluetooth/bluetooth.hpp b/include/amiro/bluetooth/bluetooth.hpp
deleted file mode 100644
index 8b1a21d..0000000
--- a/include/amiro/bluetooth/bluetooth.hpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef AMIRO_BLUETOOTH_H_
-#define AMIRO_BLUETOOTH_H_
-
-#include <amiro/bluetooth/bluetooth-iwrap.hpp>
-
-namespace amiro {
-
-  class BLUETOOTH {
-  public:
-    BLUETOOTH(UARTDriver* uart);
-
-    void bluetoothStart();
-    void bluetoothReset();
-    void bluetoothEnableMux();
-    void bluetoothDisableMux();
-    void bluetoothDiscoverDevices();
-    void bluetoothListAllConnections();
-    void bluetoothSetName(const char *name);
-    void bluetoothSetPin(const char *pin);
-    void bluetoothCloseConnection(uint8_t linkid);
-    void bluetoothSendCommand(const char *cmd);
-    bool bluetoothIsMuxMode();
-
-    BluetoothIwrap iwrap;
-  };
-}
-
-#endif /* BLUETOOTH_H_ */
diff --git a/include/amiro/bluetooth/checkutility.hpp b/include/amiro/bluetooth/checkutility.hpp
deleted file mode 100644
index a52b794..0000000
--- a/include/amiro/bluetooth/checkutility.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef AMIRO_WT12_CHECKUTILITY_H_
-#define AMIRO_WT12_CHECKUTILITY_H_
-
-#include <ch.hpp>
-
-namespace amiro {
-
-  class WT12CheckUtility
-  {
-  public:
-    enum Constants {
-      MUX_StartOfFrame = 0xBFu
-    };
-
-  private:
-    struct Message {
-      struct Head {
-        uint8_t start_of_frame;
-        uint8_t link_id;
-        uint8_t flags;
-        uint16_t length;
-      };
-
-      Head head;
-      char* message;
-      uint8_t n_link;
-    };
-
-  public:
-    explicit WT12CheckUtility();
-    ~WT12CheckUtility();
-
-    void reset();
-    bool waitForReady(const bool print = false);
-    uint8_t selftest();
-    void msgPrint(const char* message, const uint16_t length);
-    void msgPrintMulti(const char* message_buf, const uint16_t* length_buf, const uint16_t num_messages);
-    void sendMessage(char* message, uint8_t link_id = 0xFF);
-    void sendMessageRaw(const char* message);
-    uint16_t receiveMessage(char* message, const uint16_t max_length);
-    uint16_t receiveMessages(char* message_buf, const uint16_t msg_buf_size, uint16_t* length_buf, const uint16_t len_buf_size, const char* last_msg, const char* filter_in = "", const char* filter_out = NULL);
-
-    void receiveRaw(uint8_t* buffer, uint16_t num_bytes, const bool print = false);
-    void receiveRawLine(const bool print = true);
-    void clearMessageBuffer(const bool print = false);
-
-  };
-}
-
-#endif // AMIRO_WT12_CHECKUTILITY_H_
diff --git a/include/amiro/bus/i2c/HWI2CDriver.hpp b/include/amiro/bus/i2c/HWI2CDriver.hpp
deleted file mode 100644
index 62d04fe..0000000
--- a/include/amiro/bus/i2c/HWI2CDriver.hpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * HWI2CDriver.hpp
- *
- *  Created on: Jun 6, 2014
- *      Author: Robert ABEL
- */
-
-#ifndef HWI2CDRIVER_HPP_
-#define HWI2CDRIVER_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-
-/**
- * @brief   AMiRo
- */
-namespace amiro {
-
-  struct I2CTxParams;
-  struct I2CRxParams;
-
-  /**
-   * @brief   I²C HW Driver Abstraction
-   */
-  class HWI2CDriver : public I2CDriver {
-
-  public:
-
-    HWI2CDriver(::I2CDriver *d);
-    virtual ~HWI2CDriver() {};
-
-    virtual void start(const ::I2CConfig *config);
-    virtual void stop();
-    virtual i2cflags_t getErrors();
-    virtual msg_t masterTransmit(const I2CTxParams *params, systime_t timeout = TIME_INFINITE);
-    virtual msg_t masterReceive(const I2CRxParams *params, systime_t timeout = TIME_INFINITE);
-    virtual void acquireBus();
-    virtual void releaseBus();
-
-  private:
-
-    ::I2CDriver *driver;
-
-  };
-
-} /* amiro */
-
-#endif /* HWI2CDRIVER_HPP_ */
diff --git a/include/amiro/bus/i2c/I2CDriver.hpp b/include/amiro/bus/i2c/I2CDriver.hpp
deleted file mode 100644
index 794711f..0000000
--- a/include/amiro/bus/i2c/I2CDriver.hpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * AI2CDriver.hpp
- *
- *  Created on: Jun 6, 2014
- *      Author: Robert ABEL
- */
-
-#ifndef AI2CDRIVER_HPP_
-#define AI2CDRIVER_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-
-/**
- * @brief   AMiRo
- */
-namespace amiro {
-
-  struct I2CTxParams;
-  struct I2CRxParams;
-
-  /**
-   * @brief   I²C Driver Interface
-   */
-  class I2CDriver {
-
-  public:
-
-    I2CDriver() {};
-    virtual ~I2CDriver() {};
-
-    virtual void start(const ::I2CConfig *config) = 0;
-    virtual void stop() = 0;
-    virtual i2cflags_t getErrors() = 0;
-    virtual msg_t masterTransmit(const I2CTxParams *params, systime_t timeout = TIME_INFINITE) = 0;
-    virtual msg_t masterReceive(const I2CRxParams *params, systime_t timeout = TIME_INFINITE) = 0;
-
-    virtual void acquireBus() = 0;
-    virtual void releaseBus() = 0;
-
-  };
-
-} /* amiro */
-
-#endif /* AI2CDRIVER_HPP_ */
diff --git a/include/amiro/bus/i2c/I2CMultiplexer.hpp b/include/amiro/bus/i2c/I2CMultiplexer.hpp
deleted file mode 100644
index a0f8956..0000000
--- a/include/amiro/bus/i2c/I2CMultiplexer.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef AI2CMULTIPLEXER
-#define AI2CMULTIPLEXER
-
-#include <ch.hpp>
-#include <hal.h>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-
-/**
- * @brief   AMiRo
- */
-namespace amiro {
-
-  /**
-   * @brief   I²C Bus Multiplexer
-   */
-  class I2CMultiplexer {
-
-  public:
-
-    I2CMultiplexer(I2CDriver *driver);
-    virtual ~I2CMultiplexer() = 0;
-
-    virtual i2cflags_t getErrors();
-    virtual msg_t masterTransmit(const I2CTxParams *params, systime_t timeout = TIME_INFINITE);
-    virtual msg_t masterReceive(const I2CRxParams *params, systime_t timeout = TIME_INFINITE);
-
-    virtual void acquireBus();
-    virtual void releaseBus();
-
-    virtual msg_t select(const uint8_t bus_id) = 0;
-    virtual msg_t deselect() = 0;
-
-  private:
-
-    I2CDriver *driver;
-
-#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
-#if CH_USE_MUTEXES || defined(__DOXYGEN__)
-    /**
-    * @brief   Mutex protecting the bus.
-    */
-    ::Mutex                     mutex;
-#elif CH_USE_SEMAPHORES
-    ::Semaphore                 semaphore;
-#endif
-#endif /* I2C_USE_MUTUAL_EXCLUSION */
-
-  };
-
-} /* amiro */
-
-#endif /* AI2CMULTIPLEXER */
diff --git a/include/amiro/bus/i2c/I2CParams.hpp b/include/amiro/bus/i2c/I2CParams.hpp
deleted file mode 100644
index 60f021b..0000000
--- a/include/amiro/bus/i2c/I2CParams.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * I2CParams.hpp
- *
- *  Created on: Jun 10, 2014
- *      Author: Robert ABEL
- */
-
-#ifndef I2CPARAMS_HPP_
-#define I2CPARAMS_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-
-namespace amiro {
-
-struct I2CTxParams {
-
-  i2caddr_t      addr;
-  const uint8_t *txbuf;
-  size_t         txbytes;
-  uint8_t       *rxbuf;
-  size_t         rxbytes;
-
-};
-
-struct I2CRxParams {
-
-  i2caddr_t      addr;
-  uint8_t       *rxbuf;
-  size_t         rxbytes;
-
-};
-
-} /* amiro */
-
-#endif /* I2CPARAMS_HPP_ */
diff --git a/include/amiro/bus/i2c/VI2CDriver.hpp b/include/amiro/bus/i2c/VI2CDriver.hpp
deleted file mode 100644
index 36a589d..0000000
--- a/include/amiro/bus/i2c/VI2CDriver.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef MUXEDI2CDRIVER_HPP_
-#define MUXEDI2CDRIVER_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-
-/**
- * @brief   AMiRo
- */
-namespace amiro {
-
-  struct I2CTxParams;
-  struct I2CRxParams;
-
-  class I2CMultiplexer;
-
-  /**
-   * @brief   Virtual I²C Driver
-   */
-  class VI2CDriver : public I2CDriver {
-
-  public:
-
-    VI2CDriver(I2CMultiplexer *driver, const uint8_t bus_id);
-    virtual ~VI2CDriver() {}
-    virtual void start(const ::I2CConfig *config);
-    virtual void stop();
-    virtual i2cflags_t getErrors();
-    virtual msg_t masterTransmit(const I2CTxParams *params, systime_t timeout = TIME_INFINITE);
-    virtual msg_t masterReceive(const I2CRxParams *params, systime_t timeout = TIME_INFINITE);
-
-    virtual void acquireBus();
-    virtual void releaseBus();
-
-  private:
-
-    I2CMultiplexer *driver;
-    uint8_t id;
-
-#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
-#if CH_USE_MUTEXES || defined(__DOXYGEN__)
-    /**
-    * @brief   Mutex protecting the bus.
-    */
-    ::Mutex                     mutex;
-#elif CH_USE_SEMAPHORES
-    ::Semaphore                 semaphore;
-#endif
-#endif /* I2C_USE_MUTUAL_EXCLUSION */
-
-  };
-
-} /* amiro */
-
-#endif /* MUXEDI2CDRIVER_HPP_ */
diff --git a/include/amiro/bus/i2c/mux/pca9544.hpp b/include/amiro/bus/i2c/mux/pca9544.hpp
deleted file mode 100644
index 9b697d9..0000000
--- a/include/amiro/bus/i2c/mux/pca9544.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * pca9544.hpp
- *
- *  Created on: Jun 6, 2014
- *      Author: Robert ABEL
- */
-
-#ifndef AMIRO_PCA9544_HPP_
-#define AMIRO_PCA9544_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-#include <amiro/bus/i2c/I2CParams.hpp>
-#include <amiro/bus/i2c/I2CMultiplexer.hpp>
-
-/**
- * @brief   AMiRo
- */
-namespace amiro {
-
-  class I2CDriver;
-
-  /**
-   * @brief   Input/Output driver class
-   */
-  template <bool ignore_deselect>
-  class PCA9544 : public I2CMultiplexer {
-
-    enum { SLA = 0x70u };
-    enum { BUS_OFF = 0x00u, BUS_ON = 0x04u };
-
-  public:
-
-    PCA9544(I2CDriver *driver, const uint8_t master_id);
-    virtual ~PCA9544() {}
-
-    virtual msg_t select(const uint8_t bus_id);
-    virtual msg_t deselect();
-
-    uint8_t getInterruptSource();
-
-    /**
-     * Return types of getCheck()
-     */
-    enum {
-      CHECK_OK   = 0x00u,
-      CHECK_FAIL = 0x01u,
-    };
-
-    /**
-     * Checks the multiplexer by writing all possible bit
-     * combinations into the MUX register and directly
-     * reading from it.
-     * TODO Check possible register write corruption if vcnl4020 is running in parallel
-     *
-     * @return [CHECK_OK | CHECK_FAIL]
-     */
-    uint8_t getCheck(void);
-
-  private:
-
-    uint8_t master_id;
-    I2CTxParams tx_params;
-    I2CRxParams rx_params;
-    uint8_t selected;
-
-  };
-
-} /* amiro */
-
-#include <components/bus/i2c/mux/pca9544.tpp>
-
-#endif /* AMIRO_PCA9544_HPP_ */
diff --git a/include/amiro/bus/spi/HWSPIDriver.hpp b/include/amiro/bus/spi/HWSPIDriver.hpp
deleted file mode 100644
index 6ad0920..0000000
--- a/include/amiro/bus/spi/HWSPIDriver.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef HWSPIDRIVER_HPP_
-#define HWSPIDRIVER_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-
-/**
- * @brief   AMiRo
- */
-namespace amiro {
-
-  /**
-  * @brief   Input/Output driver class
-  */
-  class HWSPIDriver {
-  public:
-    HWSPIDriver(::SPIDriver *driver, const ::SPIConfig *config);
-    virtual ~HWSPIDriver();
-    void exchange(uint8_t *readData, const uint8_t *writeData, size_t length);
-    void read(uint8_t *data, size_t length);
-    void write(const uint8_t *data, size_t length);
-
-  private:
-    ::SPIDriver *driver;
-    const ::SPIConfig *config;
-  };
-
-} /* amiro */
-
-#endif /* HWSPIDRIVER_HPP_ */
diff --git a/include/amiro/debug.h b/include/amiro/debug.h
deleted file mode 100644
index d5db40c..0000000
--- a/include/amiro/debug.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef AMIRO_DEBUG_H_
-#define AMIRO_DEBUG_H
-
-#include <amiroosconf.h>
-#include <chprintf.h>
-#include <chdebug.h>
-
-
-
-/**
- * @brief Simple message printing macro
- *
- * @param[in] fmt     the string message to print
- * @param[in] args... the optional list of arguments to insert in the message
- *
- * @todo Make output stream adjustable
- */
-#define amiroPrintf(fmt, args...) {                   \
-  chprintf((BaseSequentialStream*)&SD1, fmt, ##args); \
-}
-
-#if AMIRO_DBG || defined(__DOXYGEN__)
-
-/**
- * @brief Macro to print an error
- *
- * @param[in] c       the condition to be verified to be true
- * @param[in] msg     the string message to print
- * @param[in] args... the optional list of arguments to insert in the message
- */
-#define amiroDbgError(c, msg, args...) {                                     \
-  if (!(c))                                                                  \
-    amiroPrintf("ERROR: " msg "\tAT %s:%s()\n", ##args, __FILE__, __func__); \
-}
-
-/**
- * @brief Macro to print a warning
- *
- * @param[in] c       the condition to be verified to be true
- * @param[in] msg     the text message
- * @param[in] args... the optional list of arguments to insert in the message
- */
-#define amiroDbgWarning(c, msg, args...) {                                      \
-  if (!(c))                                                                     \
-    amiroPrintf("WARNING: " msg "\tAT: %s:%s()\n", ##args, __FILE__, __func__); \
-}
-
-/**
- * @brief Macro to print a note
- *
- * @param[in] msg     the text message
- * @param[in] args... the optional list of arguments to insert in the message
- */
-#define amiroDbgNote(msg, args...) {                                       \
-  amiroPrintf("NOTE: " msg "\tAT: %s:%s()\n", ##args, __FILE__, __func__); \
-}
-
-/**
- * @brief Macro to print a todo
- *
- * @param[in] msg     the text message
- * @param[in] args... the optional list of arguments to insert in the message
- */
-#define amiroDbgTodo(msg, args...) {                                       \
-  amiroPrintf("TODO: " msg "\tAT: %s:%s()\n", ##args, __FILE__, __func__); \
-}
-
-#else
-
-/*
- * empty macro definitions, if AMIRO_DBG is FALSE
- */
-#define amiroDbgError(c, msg, args...)
-#define amiroDbgWarning(c, msg, args...)
-#define amiroDbgNote(msg, args...)
-#define amiroDbgTodo(msg, args...)
-
-#endif
-
-
-#endif // AMIRO_DEBUG_H_
-
diff --git a/include/amiro/eeprom/at24.hpp b/include/amiro/eeprom/at24.hpp
deleted file mode 100644
index 5004a31..0000000
--- a/include/amiro/eeprom/at24.hpp
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef AT24_HPP_
-#define AT24_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/eeprom/eeprom.hpp>
-
-namespace amiro {
-
-class I2CDriver;
-
-class AT24 : public EEPROM {
-
-  enum {
-    AT24_SLA = 0x50u,
-  };
-
-  enum {
-    AT24_MAX_PAGE_SIZE = 8,
-  };
-
-  public:
-
-  /**
-    * Return types of getCheck()
-    */
-   enum {
-     CHECK_OK          = 0x00u,
-     CHECK_READ_FAIL   = 0x01u,
-     CHECK_WRITE_FAIL  = 0x02u,
-     CHECK_CHKSUM_FAIL = 0x03u,
-   };
-
-    AT24(size_t size, uint8_t page_size, uint16_t max_t_wr, I2CDriver* i2c_driver);
-    ~AT24();
-
-    static msg_t poll_ack(void* instance);
-    static size_t write(void* instance, const uint8_t* bp, size_t n);
-    static size_t read(void* instance, uint8_t* bp, size_t n);
-    static uint32_t close(void* instance);
-
-};
-
-} /* amiro */
-
-#endif /* AT24_HPP_ */
diff --git a/include/amiro/eeprom/eeprom.hpp b/include/amiro/eeprom/eeprom.hpp
deleted file mode 100644
index 92687ac..0000000
--- a/include/amiro/eeprom/eeprom.hpp
+++ /dev/null
@@ -1,92 +0,0 @@
-#ifndef EEPROM_HPP_
-#define EEPROM_HPP_
-
-#include <ch.hpp>
-#include <hal.h>
-
-#include <amiro/bus/i2c/I2CParams.hpp>
-
-namespace amiro {
-
-class I2CDriver;
-class HWSPIDriver;
-
-class EEPROM {
-
-  public:
-    /**
-     * Base File Stream
-     * eepromInit initializes this member.
-     */
-    BaseFileStream bfs;
-
-    msg_t error;
-    fileoffset_t position;
-
-    size_t size;
-    uint8_t page_size;
-
-    /**
-     * Maximum Write Cycle time
-     * Expressed in multiples of 10 µs.
-     */
-    uint16_t max_t_wr;
-
-    union {
-
-#if HAL_USE_I2C
-      struct {
-        I2CDriver* i2c_driver;
-        I2CTxParams i2c_txparams;
-      };
-#endif /* HAL_USE_I2C */
-
-#if HAL_USE_SPI
-      struct {
-        HWSPIDriver* spi_driver;
-      };
-#endif /* HAL_USE_SPI */
-
-    }; /* union */
-
-#if CH_USE_MUTEXES
-    /**
-     * Mutex Lock
-     */
-    Mutex mutex;
-#elif CH_USE_SEMAPHORES
-    /**
-     * Semaphore
-     */
-    Semaphore semaphore;
-#endif
-
-    enum {
-      EEPROM_ERROR_NONE = 0x00u,
-    };
-
-  protected:
-
-#if HAL_USE_I2C
-    EEPROM(const struct BaseFileStreamVMT* vmt, size_t size, uint8_t page_size, uint16_t max_t_wr, uint8_t sla, I2CDriver* i2c_driver);
-#endif /* HAL_USE_I2C */
-#if HAL_USE_SPI
-    EEPROM(const struct BaseFileStreamVMT* vmt, size_t size, uint8_t page_size, uint16_t max_t_wr, HWSPIDriver* spi_driver);
-#endif /* HAL_USE_SPI */
-    ~EEPROM();
-
-  public:
-
-    void acquire();
-    void release();
-
-    static int geterror(void* instance);
-    static fileoffset_t getsize(void* instance);
-    static fileoffset_t getposition(void* instance);
-    static fileoffset_t lseek(void *instance, fileoffset_t offset);
-
-};
-
-} /* amiro */
-
-#endif /* EEPROM_HPP_ */
diff --git a/include/amiro/gyro/l3g4200d.hpp b/include/amiro/gyro/l3g4200d.hpp
deleted file mode 100644
index 4910d90..0000000
--- a/include/amiro/gyro/l3g4200d.hpp
+++ /dev/null
@@ -1,269 +0,0 @@
-#ifndef L3G4200D_HPP_
-#define L3G4200D_HPP_
-
-#include <ch.hpp>
-
-namespace amiro {
-
-class HWSPIDriver;
-
-class L3G4200D : public chibios_rt::BaseStaticThread<256> {
-
- public:
-  enum {
-    DR_100_HZ   = 0x00,
-    DR_200_HZ   = 0x40,
-    DR_400_HZ   = 0x80,
-    DR_800_HZ   = 0xC0,
-    DR_MASK     = 0xC0,
-  };
-  enum {
-    BW_12_5  = 0x00,
-    BW_20    = 0x00,
-    BW_25    = 0x10,
-    BW_30    = 0x00,
-    BW_35    = 0x10,
-    BW_50    = 0x20,
-    BW_70    = 0x30,
-    BW_110   = 0x30,
-    BW_MASK  = 0x30,
-  };
-  enum {
-    PD       = 0x08,
-    ZEN      = 0x04,
-    YEN      = 0x02,
-    XEN      = 0x01,
-    EN_MASK  = 0x0F,
-  };
-  enum {
-    HPM_NORMAL_RST = 0x00,
-    HPM_REFERENCE  = 0x10,
-    HPM_NORMAL     = 0x20,
-    HPM_AUTO_RST   = 0x30,
-  };
-  enum {
-    HPCF_2    = 0x00,
-    HPCF_4    = 0x01,
-    HPCF_8    = 0x02,
-    HPCF_16   = 0x03,
-    HPCF_32   = 0x04,
-    HPCF_64   = 0x05,
-    HPCF_128  = 0x06,
-    HPCF_256  = 0x07,
-    HPCF_512  = 0x08,
-    HPCF_1024 = 0x09,
-  };
-  enum {
-    I1_INT1   = 0x80,
-    I1_BOOT   = 0x40,
-    H_IACTIVE = 0x20,
-    PP_OD     = 0x10,
-    I2_DRDY   = 0x08,
-    I2_WTM    = 0x04,
-    I2_ORUN   = 0x02,
-    I2_EMPTY  = 0x01,
-  };
-  enum {
-    BDU_CONT    = 0x00,
-    BDU_SINGLE  = 0x80,
-    BLE_MSB     = 0x40,
-    BLE_LSB     = 0x00,
-    FS_250_DPS  = 0x00,
-    FS_500_DPS  = 0x10,
-    FS_2000_DPS = 0x20,
-    ST_SIGN_M   = 0x04,
-    ST_SIGN_P   = 0x00,
-    ST_EN       = 0x02,
-    SIM_3W      = 0x01,
-    SIM_4W      = 0x00,
-    FS_MASK     = 0x20,
-  };
-  enum {
-    BOOT          = 0x80,
-    FIFO_EN       = 0x40,
-    HP_EN         = 0x10,
-    INT1_SEL_NOHP = 0x00,
-    INT1_SEL_HP   = 0x04,
-    INT1_SEL_LP   = 0x08,
-    OUT_SEL_NOHP  = 0x00,
-    OUT_SEL_HP    = 0x01,
-    OUT_SEL_LP    = 0x02,
-  };
-  enum {
-    ZYXOR = 0x80,
-    ZOR   = 0x40,
-    YOR   = 0x20,
-    XOR   = 0x10,
-    ZYXDA = 0x08,
-    ZDA   = 0x04,
-    YDA   = 0x02,
-    XDA   = 0x01,
-  };
-  enum {
-    FM_BYPASS        = 0x00,
-    FM_FMMODE        = 0x20,
-    FM_STREAM        = 0x40,
-    FM_STREAM2FIFO   = 0x60,
-    FM_BYPASS2STREAM = 0x80,
-    WTM_MASK         = 0x1F,
-  };
-  enum {
-    WTM      = 0x80,
-    OVRN     = 0x40,
-    EMPTY    = 0x20,
-    FSS_MASK = 0x1F,
-  };
-  enum {
-    ANDOR = 0x80,
-    LIR   = 0x40,
-    ZHIE  = 0x20,
-    ZLIE  = 0x10,
-    YHIE  = 0x08,
-    YLIE  = 0x04,
-    XHIE  = 0x02,
-    XLIE  = 0x01,
-  };
-  enum {
-    IA = 0x40,
-    ZH = 0x20,
-    ZL = 0x10,
-    YH = 0x08,
-    YL = 0x04,
-    XH = 0x02,
-    XL = 0x01,
-  };
-  enum {
-    THS_L_MASK = 0x7F
-  };
-  enum {
-    INT1_WAIT          = 0x80,
-    INT1_DURATION_MASK = 0x7F,
-  };
-
-  /**
-   * Return types of getCheck()
-   */
-  enum {
-    CHECK_OK = 0x00u,
-    CHECK_FAIL = 0x01u,
-  };
-
-  /**
-   * Top view of the AMiRo with charger in the back (F:Front, B:Back).
-   * Z is pointing into the ground (Apply right-hand-rule):
-   *    ___________
-   *   /    F      \
-   *  /     X       \
-   * |      |        |
-   * |      Z---Y    |
-   * |               |
-   *  \             /
-   *   \____B______/
-   */
-  enum {
-    AXIS_X = 0x00u,
-    AXIS_Y = 0x01u,
-    AXIS_Z = 0x02u,
-  };
-
-  //private:
-
-  struct registers {
-    uint8_t RESERVED_0x00_0x0E[0x0Fu];
-    uint8_t WHO_AM_I;
-    uint8_t RESERVED_0x10_0x1F[0x10u];
-    uint8_t CTRL_REG1;
-    uint8_t CTRL_REG2;
-    uint8_t CTRL_REG3;
-    uint8_t CTRL_REG4;
-    uint8_t CTRL_REG5;
-    uint8_t REFERENCE;
-
-    uint8_t OUT_TEMP;
-
-    uint8_t STATUS_REG;
-
-    uint16_t OUT_X; /* LE */
-    uint16_t OUT_Y; /* LE */
-    uint16_t OUT_Z; /* LE */
-
-    uint8_t FIFO_CTRL_REG;
-    uint8_t FIFO_SRC_REG;
-
-    uint8_t INT1_CFG;
-    uint8_t INT1_SRC;
-    uint8_t INT1_THS_XH;
-    uint8_t INT1_THS_XL;
-    uint8_t INT1_THS_YH;
-    uint8_t INT1_THS_YL;
-    uint8_t INT1_THS_ZH;
-    uint8_t INT1_THS_ZL;
-    uint8_t INT1_DURATION;
-    uint8_t RESERVED_0x38_0x3F[0x08u];
-  }__attribute__((packed));
-
-  enum {
-    L3G4200D_ID = 0xD3u
-  };
-
-  enum {
-    SPI_MULT = 0x40u,
-    SPI_READ = 0x80u,
-    SPI_WRITE = 0x00u,
-  };
-
- public:
-
-  struct L3G4200DConfig {
-    uint8_t         ctrl1;
-    uint8_t         ctrl2;
-    uint8_t         ctrl3;
-    uint8_t         ctrl4;
-    uint8_t         ctrl5;
-  };
-
-  L3G4200D(HWSPIDriver* driver);
-  virtual ~L3G4200D();
-
-  chibios_rt::EvtSource* getEventSource();
-  msg_t configure(const L3G4200DConfig* config);
-  int16_t angularRate[AXIS_Z - AXIS_X + 1];
-  int32_t angular[AXIS_Z - AXIS_X + 1];
-
-  int16_t getAngularRate(const uint8_t axis);
-  
-  int32_t getAngularRate_udps(const uint8_t axis);
-  int32_t getAngular(const uint8_t axis);
-  int32_t getAngular_ud(const uint8_t axis);
-  void angularReset();
-
-
-  /**
-   * Check the presence of the accelerometer by reading
-   * the identifier register and comparing it to the standard
-   * value
-   */
-  uint8_t getCheck();
-
- protected:
-  virtual msg_t main();
-
- private:
-  inline void updateSensorData();
-  inline void calcAngular();
-
- private:
-
-  HWSPIDriver* driver;
-  chibios_rt::EvtSource eventSource;
-  uint32_t integrationTic;
-  uint32_t udpsPerTic; // Resolution: Micro-degree-per-second per digit
-  uint32_t period_us;
-  uint32_t period_ms;
-  systime_t period_st;
-
-};
-
-} /* amiro */
-
-#endif /* L3G4200D_HPP_ */
diff --git a/include/amiro/input/mpr121.hpp b/include/amiro/input/mpr121.hpp
deleted file mode 100644
index f860cc4..0000000
--- a/include/amiro/input/mpr121.hpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#ifndef MPR121_HPP_
-#define MPR121_HPP_
-
-#include <ch.hpp>
-#include <amiro/bus/i2c/I2CParams.hpp>
-
-namespace amiro {
-
-  class I2CDriver;
-
-  class MPR121 : public chibios_rt::BaseStaticThread<256>{
-
-  enum { SLA = 0x5Au };
-
-  struct thresholds {
-
-    uint8_t touch_threshold;
-    uint8_t release_threshold;
-
-  } __attribute__((packed));
-
-  struct charge_time {
-
-    uint8_t cdt0 :3;
-    uint8_t res0 :1;
-    uint8_t cdt1 :3;
-    uint8_t res1 :1;
-
-  }__attribute__((packed));
-
-  struct registers {
-
-    uint16_t           touch_status;
-    uint16_t           oor_status;
-    uint16_t           ele_filt_data[13]; /* LE */
-    uint8_t            ele_baseline[13];
-    uint8_t            mhd_rising;
-    uint8_t            nhd_amt_rising;
-    uint8_t            ncl_rising;
-    uint8_t            fdl_rising;
-    uint8_t            mhd_falling;
-    uint8_t            nhd_amt_falling;
-    uint8_t            ncl_falling;
-    uint8_t            fdl_falling;
-    uint8_t            ndh_amt_touched;
-    uint8_t            ncl_touched;
-    uint8_t            fdl_touched;
-    uint8_t            eleprox_mhd_rising;
-    uint8_t            eleprox_nhd_amt_rising;
-    uint8_t            eleprox_ncl_rising;
-    uint8_t            eleprox_fdl_rising;
-    uint8_t            eleprox_mhd_falling;
-    uint8_t            eleprox_nhd_amt_falling;
-    uint8_t            eleprox_ncl_falling;
-    uint8_t            eleprox_fdl_falling;
-    uint8_t            eleprox_nhd_amt_touched;
-    uint8_t            eleprox_ncl_touched;
-    uint8_t            eleprox_fdl_touched;
-    struct thresholds  ele_thresholds[13];
-    uint8_t            debounce;
-    uint8_t            cdc_config;
-    uint8_t            cdt_config;
-    uint8_t            ele_config;
-    uint8_t            ele_current[13];
-    struct charge_time ele_charge_time[(13 + 1)/2];
-    uint16_t           gpio_ctrl;
-    uint8_t            gpio_data;
-    uint8_t            gpio_ddr;
-    uint8_t            gpio_en;
-    uint8_t            gpio_set;
-    uint8_t            gpio_clear;
-    uint8_t            gpio_toggle;
-    uint16_t           auto_cfg_ctrl;
-    uint8_t            auto_cfg_usl;
-    uint8_t            auto_cfg_lsl;
-    uint8_t            auto_cfg_target;
-    uint8_t            soft_reset;
-
-  } __attribute__((packed));
-
-  public:
-
-  struct MPR121Config {
-
-    uint16_t global_config;
-    uint8_t  ele_config;
-    uint16_t auto_config;
-    uint8_t  up_side_limit;
-    uint8_t  low_side_limit;
-    uint8_t  target_level;
-
-  };
-
-  enum {
-
-    FFI_6     = 0x0000u,
-    FFI_10    = 0x0040u,
-    FFI_18    = 0x0080u,
-    FFI_34    = 0x00C0u,
-
-    CDT_OFF   = 0x0000u,
-    CDT_0_5   = 0x2000u,
-    CDT_1     = 0x4000u,
-    CDT_2     = 0x6000u,
-    CDT_4     = 0x8000u,
-    CDT_8     = 0xA000u,
-    CDT_16    = 0xC000u,
-    CDT_32    = 0xE000u,
-    SFI_4     = 0x0000u,
-    SFI_6     = 0x0800u,
-    SFI_10    = 0x1000u,
-    SFI_18    = 0x1800u,
-    ESI_1     = 0x0000u,
-    ESI_2     = 0x0100u,
-    ESI_4     = 0x0200u,
-    ESI_8     = 0x0300u,
-    ESI_16    = 0x0400u,
-    ESI_32    = 0x0500u,
-    ESI_64    = 0x0600u,
-    ESI_128   = 0x0700u,
-  };
-
-  enum {
-
-    CL_ON_CURRENT  = 0x00u,
-    CL_OFF         = 0x40u,
-    CL_ON_HIGH5    = 0x80u,
-    CL_ON_ALL      = 0xC0u,
-    ELEPROX_0      = 0x00u,
-    ELEPROX_2      = 0x10u,
-    ELEPROX_4      = 0x20u,
-    ELEPROX_12     = 0x30u,
-
-  };
-
-  enum {
-
-    AC_ENABLE              = 0x0001u,
-    AC_RECONF_EN           = 0x0002u,
-    BVA_ON_CURRENT         = 0x0000u,
-    BVA_OFF                = 0x0004u,
-    BVA_ON_HIGH5           = 0x0008u,
-    BVA_ON_ALL             = 0x000Cu,
-    RETRY_OFF              = 0x0000u,
-    RETRY_2                = 0x0010u,
-    RETRY_4                = 0x0020u,
-    RETRY_8                = 0x0030u,
-    /* skip FFI */
-    AC_FAIL_INT_EN         = 0x0100u,
-    AC_RECONF_FAIL_INT_EN  = 0x0200u,
-    AC_OUT_OF_RANGE_INT_EN = 0x0400u,
-    AC_SKIP_CHRG_TIME_SRCH = 0x8000u,
-
-  };
-
-  enum {
-
-    SOFT_RST_MAGIC = 0x63u,
-
-  };
-
-  public:
-
-    MPR121(I2CDriver *driver, const uint8_t master_id);
-    virtual ~MPR121();
-
-    chibios_rt::EvtSource* getEventSource();
-    uint16_t getButtonStatus();
-    uint8_t getButtonStatus(uint8_t ix);
-    uint16_t getElectrodeData(uint8_t ix);
-    uint8_t getBaselineData(uint8_t ix);
-    msg_t configure(const MPR121Config *cfg);
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-
-    inline msg_t softReset();
-    inline msg_t writeConfig(const MPR121Config *cfg);
-    inline msg_t updateButtonData();
-
-  private:
-
-    I2CDriver *driver;
-    uint8_t master_id;
-    chibios_rt::EvtSource eventSource;
-
-    uint16_t button_state;
-    uint16_t electrode_data[13];
-    uint8_t baseline_data[13];
-    I2CTxParams tx_params;
-
-};
-
-
-} /* amiro */
-
-#endif /* MPR121_HPP_ */
diff --git a/include/amiro/leds/tlc5947.hpp b/include/amiro/leds/tlc5947.hpp
deleted file mode 100644
index 08f953d..0000000
--- a/include/amiro/leds/tlc5947.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef AMIRO_TLC5947_H_
-#define AMIRO_TLC5947_H_
-
-#include <amiro/Color.h>
-
-namespace amiro {
-
-  class HWSPIDriver;
-
-  class TLC5947 : public chibios_rt::BaseStaticThread<192> {
-  public:
-    TLC5947(HWSPIDriver *spi, ioportid_t blankPort, int blankPad);
-    virtual ~TLC5947();
-    void disable();
-    void enable();
-    void setBrightness(int brightness);
-    void setColor(int index, Color color);
-    void update();
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-    int caluclateRedGrayscale(Color color, int brightness) const;
-    int caluclateGreenGrayscale(Color color, int brightness) const;
-    int caluclateBlueGrayscale(Color color, int brightness) const;
-
-    HWSPIDriver *spi;
-    ioportid_t blankPort;
-    int blankPad;
-    Color colors[8];
-    int brightness;
-  };
-
-}
-
-#endif /* AMIRO_TLC5947_H_ */
diff --git a/include/amiro/magneto/hmc5883l.hpp b/include/amiro/magneto/hmc5883l.hpp
deleted file mode 100644
index 55d1e9a..0000000
--- a/include/amiro/magneto/hmc5883l.hpp
+++ /dev/null
@@ -1,196 +0,0 @@
-#ifndef HMC5883L_H_
-#define HMC5883L_H_
-
-#include <amiro/bus/i2c/I2CParams.hpp>
-
-namespace amiro {
-
-class I2CDriver;
-
-/**
- * HMC5883L Magnetometer
- * \todo Interrupt Support, self-test
- */
-class HMC5883L : public chibios_rt::BaseStaticThread<256> {
-
- public:
-
-  struct registers {
-    uint8_t ctrlA;
-    uint8_t ctrlB;
-    uint8_t mode;
-    uint8_t xMsb;
-    uint8_t xLsb;
-    uint8_t zMsb;
-    uint8_t zLsb;
-    uint8_t yMsb;
-    uint8_t yLsb;
-    uint8_t status;
-    uint8_t idA;
-    uint8_t idB;
-    uint8_t idC;
-  }__attribute__((packed));
-
-  struct HMC5883LConfig {
-    uint8_t ctrlA;
-    uint8_t ctrlB;
-    uint8_t mode;
-  };
-
-  enum {
-    SLA = 0x1E
-  };
-
-  enum {
-    MA_AVG1 = 0x00,
-    MA_AVG2 = 0x20,
-    MA_AVG4 = 0x40,
-    MA_AVG8 = 0x60,
-  };
-
-  enum {
-    DO_0_5_HZ = 0x00,
-    DO_1_HZ = 0x04,
-    DO_2_HZ = 0x08,
-    DO_5_HZ = 0x0C,
-    DO_10_HZ = 0x10,
-    DO_20_HZ = 0x14,
-    DO_50_HZ = 0x18,
-  };
-
-  enum {
-    MS_NORMAL = 0x00,
-    MS_BIASPOS = 0x01,
-    MS_BIASNEG = 0x02,
-  };
-
-  enum {
-    GN_0_GA = 0x00,
-    GN_1_GA = 0x20,
-    GN_2_GA = 0x40,
-    GN_3_GA = 0x60,
-    GN_4_GA = 0x80,
-    GN_5_GA = 0xA0,
-    GN_6_GA = 0xC0,
-    GN_7_GA = 0xE0,
-  };
-
-  enum {
-    MD_CONTCV = 0x00,
-    MD_SINGCV = 0x01,
-    MD_IDLE = 0x02,
-    MD_SLEEP = 0x03,
-  };
-
-  enum {
-    HS_DISABLE = 0x00,
-    HS_ENABLE = 0x80,
-  };
-
-  enum {
-    SR_REN = 0x04,
-    SR_LOCK = 0x02,
-    SR_RDY = 0x01,
-  };
-
-  enum {
-    ID_IRA = 'H',
-    ID_IRB = '4',
-    ID_IRC = '3',
-  };
-
-  enum {
-    MAGNETO_AVG = 10
-  };
-
-  /**
-   * Return types of getCheck()
-   */
-  enum {
-    CHECK_OK = 0x00u,
-    CHECK_FAIL = 0x01u,
-  };
-
- public:
-  HMC5883L(I2CDriver *driver, const HMC5883LConfig *config);
-  virtual ~HMC5883L();
-
-  msg_t configure(HMC5883LConfig* config);
-
-  chibios_rt::EvtSource* getEventSource();
-
-  /**
-   * Check the presence of the magnetometer by reading
-   * the identifier register and comparing it to the standard
-   * value
-   */
-  uint8_t getCheck();
-
-  /**
-   * Top view of the AMiRo with charger in the back (F:Front, B:Back).
-   * Z is pointing into the ground (Apply right-hand-rule):
-   *    ___________
-   *   /    F      \
-   *  /     X       \
-   * |      |        |
-   * |      Z---Y    |
-   * |               |
-   *  \             /
-   *   \____B______/
-   */
-  enum {
-    AXIS_X = 0x00u,
-    AXIS_Y = 0x02u,
-    AXIS_Z = 0x01u,
-  };
-
-  /**
-   * Return the magnetization in LSB for the given axis.
-   *
-   * @param axis can be one of the axis [AXIS_X | AXIS_Y | AXIS_Z]
-   *
-   * @return Measured magnetization in in LSB for the given axis
-   */
-  int16_t getMagnetization(const uint8_t axis);
-
-  /**
-   * Return the magnetization in µGauss for the given axis.
-   *
-   * @param axis can be one of the axis [AXIS_X | AXIS_Y | AXIS_Z]
-   *
-   * @return Measured magnetization in µGauss for the given axis
-   */
-  int32_t getMagnetizationGauss(const uint8_t axis);
-
- protected:
-  virtual msg_t main(void);
-
- private:
-
-  /**
-   * Update the sensor values by reading accessing
-   * the sensor over I2C
-   */
-  inline void updateSensorData();
-
-  /**
-   * Writes the config to the HMC5883L
-   *
-   * @return I2C write return message
-   */
-  msg_t writeConf();
-
-  /**
-   * Stores the three orientations x,z,y in LSB
-   */
-  int16_t data[3];
-
-  I2CDriver *driver;
-  const HMC5883LConfig *config;
-  chibios_rt::EvtSource eventSource;
-  I2CTxParams txParams;
-};
-
-}
-
-#endif /* HMC5883L_H_ */
diff --git a/include/amiro/memoryLayout.h b/include/amiro/memoryLayout.h
deleted file mode 100644
index 3695785..0000000
--- a/include/amiro/memoryLayout.h
+++ /dev/null
@@ -1,297 +0,0 @@
-#ifndef AMIRO_FILESYSTEMIO_H_
-#define AMIRO_FILESYSTEMIO_H_
-
-/*! \brief memory layouts for the eeproms
- *
- * This header defines the memory layout.
- * Every memory layout starts with a preamble
- * of 3 byte. The first one is a magic byte
- * for checking purpose. The second one declares
- * the byte structure major version (BSMV) and the third
- * the byte structure minor version (bsmv) of the subsequently
- * bytes in the memory. With different major versions, the
- * layout of the memory may totaly change, so one should
- * not read from such a different layout if the version
- * differs from the expected one. With greater minor
- * versions the old memory layout may not change, but
- * new elements emerge.
- */
-
-#include <amiro/eeprom/at24.hpp>
-#include <chprintf.h>
-
-namespace amiro {
-namespace fileSystemIo {
-
-  class FileSystemIoBase {
-
-  public:
-    AT24 *at24c01;
-    const uint8_t BSMV;
-    const uint8_t bsmv;
-    const uint8_t HMV;
-    const uint8_t hmv;
-    const uint8_t magicByteValue = 0xAAu;
-
-    // TODO implement CRC check
-    struct preamble {
-      uint8_t magicByte;
-      uint8_t byteStructureMajorVersion;
-      uint8_t byteStructureMinorVersion;
-      uint8_t hardwareMajorVersion;
-      uint8_t hardwareMinorVersion;
-      uint8_t reserved_0x04_0x14[15];
-    };
-
-    enum{
-      OK                    = 0x00u,
-      NOT_IMPLEMENTED       = 0x01u,
-      WRONG_BSMV            = 0x02u,
-      WRONG_bsmv            = 0x03u,
-      IO_ERROR              = 0x04u,
-      WRONG_MAGICBYTE_VALUE = 0x05u,
-      WRONG_INDEX           = 0x06u,
-      WRONG_HMV             = 0x07u,
-      WRONG_hmv             = 0x08u,
-    };
-
-  public:
-
-    FileSystemIoBase(AT24 *at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : at24c01(at24c01),
-        BSMV(BSMV),
-        bsmv(bsmv),
-        HMV(HMV),
-        hmv(hmv) {
-     }
-
-    msg_t getCheck(){
-
-      // Get the preamble
-      const uint8_t bufferSize = sizeof(FileSystemIoBase::preamble);
-      uint8_t buffer[bufferSize];
-      chFileStreamSeek((BaseFileStream*)at24c01, offsetof(FileSystemIoBase::preamble, magicByte));
-      msg_t bytesWritten = chSequentialStreamRead((BaseFileStream*)at24c01, (uint8_t*) buffer, sizeof(FileSystemIoBase::preamble));
-
-      if (bytesWritten != bufferSize) {
-        return IO_ERROR;
-      } else if (buffer[offsetof(FileSystemIoBase::preamble, magicByte)] != magicByteValue) {
-        return WRONG_MAGICBYTE_VALUE;
-      } else if (buffer[offsetof(FileSystemIoBase::preamble, byteStructureMajorVersion)] != BSMV) {
-        return WRONG_BSMV;
-      } else if (buffer[offsetof(FileSystemIoBase::preamble, byteStructureMinorVersion)] < bsmv) {
-        return WRONG_bsmv;
-      } else if (buffer[offsetof(FileSystemIoBase::preamble, hardwareMajorVersion)] != HMV) {
-        return WRONG_HMV;
-      } else if (buffer[offsetof(FileSystemIoBase::preamble, hardwareMinorVersion)] < hmv) {
-        return WRONG_hmv;
-      } else {
-        return OK;
-      }
-    }
-
-    msg_t initMemory(){
-
-      // Get the preamble
-      const uint8_t bufferSize = offsetof(FileSystemIoBase::preamble, hardwareMinorVersion) + 1;
-      uint8_t buffer[bufferSize];
-
-      chFileStreamSeek((BaseFileStream*)at24c01, offsetof(FileSystemIoBase::preamble, magicByte));
-
-      buffer[offsetof(FileSystemIoBase::preamble, magicByte)]                 = magicByteValue;
-      buffer[offsetof(FileSystemIoBase::preamble, byteStructureMajorVersion)] = BSMV;
-      buffer[offsetof(FileSystemIoBase::preamble, byteStructureMinorVersion)] = bsmv;
-      buffer[offsetof(FileSystemIoBase::preamble, hardwareMajorVersion)]      = HMV;
-      buffer[offsetof(FileSystemIoBase::preamble, hardwareMinorVersion)]      = hmv;
-
-      msg_t bytesWritten = chSequentialStreamWrite((BaseFileStream*)at24c01, (uint8_t*) buffer, bufferSize);
-
-      if (bytesWritten != bufferSize) {
-        return IO_ERROR;
-      } else {
-        return OK;
-      }
-    }
-
-
-
-};
-
-
-class DiWheelDriveFSIO : public FileSystemIoBase {
-  private:
-
-    /** \brief Layout for DiWheelDriveFSIO with BSMV 1 and bsmv 1*/
-    struct DiWheelDrive_1_1 {
-      uint8_t  reserved_0x00_0x14[20];
-      uint16_t vcnl4020offset[4];       // U [12, 13, 15, 16]
-      uint8_t  generalPurpose[96];      // 1Cx_7Cx
-      uint8_t  reserved_0x7D_0x80[4];   // TODO CRC
-    };
-
-  public:
-    DiWheelDriveFSIO(AT24 *at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : FileSystemIoBase(at24c01, BSMV, bsmv, HMV, hmv) {
-
-    }
-
-    msg_t getVcnl4020Offset (uint16_t *buffer, uint8_t idx) {
-
-      msg_t bytesWritten;
-      const uint8_t bufferSize = sizeof(uint16_t);
-
-      // Check if the vcnl index is in a valid range
-      if (idx >= sizeof(DiWheelDrive_1_1::vcnl4020offset)) {
-        return WRONG_INDEX;
-      }
-
-      // Get the data out of the memory
-      switch (this->BSMV) {
-        case 0x01u:
-          // Set the pointer to the address
-          chFileStreamSeek((BaseFileStream*)at24c01, offsetof(DiWheelDriveFSIO::DiWheelDrive_1_1, vcnl4020offset[idx]));
-          switch (this->bsmv) {
-            default:
-              bytesWritten = chSequentialStreamRead((BaseFileStream*)at24c01, (uint8_t*) buffer, bufferSize);
-              break;
-          }
-          break;
-        }
-
-        if (bytesWritten != bufferSize) {
-          return IO_ERROR;
-        } else {
-          return OK;
-        }
-    }
-
-    msg_t setVcnl4020Offset (uint16_t *buffer, uint8_t idx) {
-
-      msg_t bytesWritten;
-      const uint8_t bufferSize = sizeof(uint16_t);
-
-      // Check if the vcnl index is in a valid range
-      if (idx >= sizeof(DiWheelDrive_1_1::vcnl4020offset)) {
-        return WRONG_INDEX;
-      }
-
-      // Get the data out of the memory
-      switch (this->BSMV) {
-        case 0x01u:
-          // Set the pointer to the address
-          chFileStreamSeek((BaseFileStream*)at24c01, offsetof(DiWheelDriveFSIO::DiWheelDrive_1_1, vcnl4020offset[idx]));
-          switch (this->bsmv) {
-            default:
-              bytesWritten = chSequentialStreamWrite((BaseFileStream*)at24c01, (const uint8_t*) buffer, bufferSize);
-              break;
-          }
-          break;
-        }
-
-        if (bytesWritten != bufferSize) {
-          return IO_ERROR;
-        } else {
-          return OK;
-        }
-    }
-};
-
-class PowerBoardFSIO : public FileSystemIoBase {
-  private:
-
-    /** \brief Layout for PowerBoardFSIO with BSMV 1 and bsmv 1*/
-    struct PowerBoard_1_1 {
-      uint8_t  reserved_0x00_0x14[20];
-      uint16_t vcnl4020offset[8];        // U1.Proximity [11, 21, 31, 41, 12, 22, 32, 42]
-      uint8_t  generalPurpose[88];       // 24x_7Cx
-      uint8_t  reserved_0x7D_0x80[4];    // TODO CRC
-    };
-
-  public:
-    PowerBoardFSIO(AT24 *at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : FileSystemIoBase(at24c01, BSMV, bsmv, HMV, hmv) {
-
-    }
-
-    msg_t getVcnl4020Offset (uint16_t *buffer, uint8_t idx) {
-
-      msg_t bytesWritten;
-      const uint8_t bufferSize = sizeof(uint16_t);
-
-      // Check if the vcnl index is in a valid range
-      if (idx >= sizeof(PowerBoard_1_1::vcnl4020offset)) {
-        return WRONG_INDEX;
-      }
-
-      // Get the data out of the memory
-      switch (this->BSMV) {
-        case 0x01u:
-          // Set the pointer to the address
-          chFileStreamSeek((BaseFileStream*)at24c01, offsetof(PowerBoardFSIO::PowerBoard_1_1, vcnl4020offset[idx]));
-          switch (this->bsmv) {
-            default:
-              bytesWritten = chSequentialStreamRead((BaseFileStream*)at24c01, (uint8_t*) buffer, bufferSize);
-              break;
-          }
-          break;
-        }
-
-        if (bytesWritten != bufferSize) {
-          return IO_ERROR;
-        } else {
-          return OK;
-        }
-    }
-
-    msg_t setVcnl4020Offset (uint16_t *buffer, uint8_t idx) {
-
-      msg_t bytesWritten;
-      const uint8_t bufferSize = sizeof(uint16_t);
-
-      // Check if the vcnl index is in a valid range
-      if (idx >= sizeof(PowerBoard_1_1::vcnl4020offset)) {
-        return WRONG_INDEX;
-      }
-
-      // Get the data out of the memory
-      switch (this->BSMV) {
-        case 0x01u:
-          // Set the pointer to the address
-          chFileStreamSeek((BaseFileStream*)at24c01, offsetof(PowerBoardFSIO::PowerBoard_1_1, vcnl4020offset[idx]));
-          switch (this->bsmv) {
-            default:
-              bytesWritten = chSequentialStreamWrite((BaseFileStream*)at24c01, (const uint8_t*) buffer, bufferSize);
-              break;
-          }
-          break;
-        }
-
-        if (bytesWritten != bufferSize) {
-          return IO_ERROR;
-        } else {
-          return OK;
-        }
-    }
-};
-
-class LightRingFSIO : public FileSystemIoBase {
-  private:
-
-    /** \brief Layout for LightRingFSIO with BSMV 1 and bsmv 1*/
-    struct LightRing_1_1 {
-      uint8_t  reserved_0x00_0x14[20];
-      uint8_t  generalPurpose[104];      // 15x_80x
-      uint8_t  reserved_0x7D_0x80[4];    // TODO CRC
-    };
-
-  public:
-    LightRingFSIO(AT24 *at24c01, uint8_t BSMV, uint8_t bsmv, uint8_t HMV, uint8_t hmv)
-      : FileSystemIoBase(at24c01, BSMV, bsmv, HMV, hmv) {
-
-    }
-};
-
-}
-}
-
-#endif /* AMIRO_FILESYSTEMIO_H_ */
diff --git a/include/amiro/power/adconverter.hpp b/include/amiro/power/adconverter.hpp
deleted file mode 100644
index 5f7b684..0000000
--- a/include/amiro/power/adconverter.hpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * ADC for monitoring the system voltage and handling the charger logic
- */
-
-#ifndef AMIRO_ADCONVERTER_HPP
-#define AMIRO_ADCONVERTER_HPP
-
-#include <ch.hpp>
-#include <hal.h>
-#include <evtimer.h>
-
-namespace amiro {
-
-class ADConverter : public chibios_rt::BaseStaticThread<256>
-{
-public:
-  enum Events {
-    EVT_WATCHDOG = 0x00,
-    EVT_TIMER = 0x01
-  };
-
-  static uint16_t uV2Adc(const uint32_t uV);
-  static uint32_t adc2uV(const uint16_t adc);
-
-private:
-  ADCDriver& driver;
-  ADCConversionGroup& conversion_group;
-  uint32_t watchdog_threshold_uV;
-  chibios_rt::EvtListener evt_listener;
-  chibios_rt::EvtSource* evt_source;
-  EvTimer evt_timer;
-
-public:
-  ADConverter(ADCDriver &adcdrv, ADCConversionGroup& adccgrp, const uint32_t threshold_uV);
-  virtual ~ADConverter();
-
-  ADCConversionGroup& getConversionGroup() {return this->conversion_group;}
-  const ADCConversionGroup& getConversionGroup() const {return this->conversion_group;}
-
-protected:
-  virtual msg_t main(void);
-
-private:
-  void enableWatchdog(const bool enable = true);
-
-};
-
-}
-
-#endif // AMIRO_ADCONVERTER_HPP
-
diff --git a/include/amiro/power/bq24103a.hpp b/include/amiro/power/bq24103a.hpp
deleted file mode 100644
index 6c40902..0000000
--- a/include/amiro/power/bq24103a.hpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * BQ24103A - Battery Charger
- */
-
-#ifndef AMIRO_BQ24103A_H_
-#define AMIRO_BQ24103A_H_
-
-namespace amiro {
-
-class BaseBQ24103A
-{
-public:
-  BaseBQ24103A()
-  {}
-
-  virtual ~BaseBQ24103A()
-  {}
-
-  virtual void enable(const bool en = true) = 0;
-
-  virtual bool isEnabled() const = 0;
-
-  virtual bool isCharging() const = 0;
-};
-
-template <uintptr_t EN_PadGrp, uint32_t EN_Pad, uintptr_t STAT_PadGrp, uint32_t STAT_Pad>
-class BQ24103A : public BaseBQ24103A
-{
-private:
-  bool is_enabled;
-
-public:
-  BQ24103A(const bool enable = false) :
-    is_enabled(enable)
-  {
-    this->enable(enable);
-  }
-
-  virtual ~BQ24103A()
-  {}
-
-  void enable(const bool enable = true)
-  {
-    // writing to a port is not atomic, thus the system must be locked
-    chSysLock();
-    palWritePad((GPIO_TypeDef*)EN_PadGrp, EN_Pad, (enable? PAL_LOW : PAL_HIGH));
-    this->is_enabled = enable;
-    chSysUnlock();
-    return;
-  }
-
-  bool isEnabled() const
-  {
-    return this->is_enabled;
-  }
-
-  bool isCharging() const
-  {
-    return (palReadPad((GPIO_TypeDef*)STAT_PadGrp, STAT_Pad) == PAL_LOW);
-  }
-};
-
-}
-
-#endif /* AMIRO_BQ24103A_H_ */
diff --git a/include/amiro/power/bq27500.hpp b/include/amiro/power/bq27500.hpp
deleted file mode 100644
index f174056..0000000
--- a/include/amiro/power/bq27500.hpp
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * BQ27500 - Fuel Gauge
- */
-
-#ifndef AMIRO_BQ27500_H_
-#define AMIRO_BQ27500_H_
-
-#include <ch.hpp>
-#include <amiro/bus/i2c/I2CParams.hpp>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-
-#include <amiro/BaseSensor.hpp>
-
-namespace amiro {
-
-  namespace BQ27500 {
-
-    struct InitData {};
-
-    struct CalibData
-    {
-      struct Configuration
-      {
-        struct Safety {
-          enum SubclassID {SUB_ID = 2};
-          const int16_t ot_chg = 450; // 0.1°C
-          const uint8_t ot_chg_time = 2; // seconds
-          const int16_t ot_chg_recovery = 400; // 0.1°C
-          const int16_t ot_dsg = 600; // 0.1°C
-          const uint8_t ot_dsg_time = 2; // seconds
-          const int16_t ot_dsg_recovery = 500; // 0.1°C
-          enum Offset {
-            OFFSET_OtChg = 0,
-            OFFSET_OtChgTime = 2,
-            OFFSET_OtChgRecovery = 3,
-            OFFSET_OtDsg = 5,
-            OFFSET_OtDsgTime = 7,
-            OFFSET_OtDsgRecovery = 8
-          };
-        } safety;
-
-        struct ChargeInhibitConfig {
-          enum SubclassID {SUB_ID = 32};
-          const int16_t charge_inhibit_temp_low = 0; // 0.1°C
-          const int16_t charge_inhibit_temp_high = 450; // 0.1°C
-          const int16_t temp_hys = 50; // 0.1°C
-          enum Offset {
-            OFFSET_ChargeInhibitTempLow = 0,
-            OFFSET_ChargeInhibitTempHigh = 2,
-            OFFSET_TempHys = 4
-          };
-        } charge_inhibit_config;
-
-        struct Charge {
-          enum SubclassID {SUB_ID = 34};
-          const int16_t charging_voltage = 4200; // mV
-          const int16_t delta_temperature = 50; // 0.1°C
-          const int16_t suspend_temperature_low = -200; // 0.1°C
-          const int16_t suspend_temperature_high = 600; // 0.1°C
-          enum Offset {
-            OFFSET_ChargingVoltage = 2,
-            OFFSET_DeltaTemperature = 4,
-            OFFSET_SuspendTemperatureLow = 6,
-            OFFSET_SuspendTemperatureHigh = 8
-          };
-        } charge;
-
-        struct ChargeTermination {
-          enum SubclassID {SUB_ID = 36};
-          const int16_t taper_current = 100; // mA
-          const int16_t minimum_taper_charge = 25; // 0.01mAh
-          const int16_t taper_voltage = 100; // mV
-          const uint16_t current_taper_window = 40; // seconds
-          enum Offset {
-            OFFSET_TaperCurrent = 2,
-            OFFSET_MinimumTaperCharge = 4,
-            OFFSET_TaperVoltage = 6,
-            OFFSET_CurrentTaperWindow = 8
-          };
-        } charge_termination;
-
-        struct Data {
-          enum SubclassID {SUB_ID = 48};
-          const int8_t initial_standby_current = -10; // mA
-          const int16_t initial_max_load_current = -500; // mA
-          const int16_t cc_threshold = 900; // mAh
-          const int16_t design_capacity = 1950; // mAh
-          const char device_name[8] = "bq27500";
-          enum Offset {
-            OFFSET_InitialStandbyCurrent = 4,
-            OFFSET_InitialMaxLoadCurrent = 5,
-            OFFSET_CCThreshold = 7,
-            OFFSET_DesignCapacity = 10,
-            OFFSET_DeviceName = 12
-          };
-        } data;
-
-        struct Discharge {
-          enum SublcassID {SUB_ID = 49};
-          const uint8_t soc1_set_threshold = 150; // mAh
-          const uint8_t soc1_clear_threshold = 175; // mAh
-          const uint8_t socf_set_threshold = 75; // mAh
-          const uint8_t socf_clear_threshold = 100; // mAh
-          enum Offset {
-            OFFSET_Soc1SetThreshold = 0,
-            OFFSET_Soc1ClearThreshold = 1,
-            OFFSET_SocfSetThreshold = 2,
-            OFFSET_SocfClearThreshold = 3
-          };
-        } discharge;
-
-        struct Registers {
-          enum SubclassID {SUB_ID = 64};
-          union OperationConfiguration {
-            const uint16_t value = 0x0979u;
-            struct {
-              uint16_t temps : 1;
-              uint16_t rsvd_1 : 1;
-              uint16_t batg_pol : 1;
-              uint16_t batl_pol : 1;
-              uint16_t rmfcc : 1;
-              uint16_t sleep : 1;
-              uint16_t idselen : 1;
-              uint16_t rsvd_7 : 1;
-              uint16_t rsns : 2;
-              uint16_t iwake : 1;
-              uint16_t pfc : 2;
-              uint16_t rsvd_13 : 1;
-              uint16_t batg_ovr : 1;
-              uint16_t rescap : 1;
-            } content;
-          } operation_configuration;
-          enum Offset {
-            OFFSET_OperationConfiguration = 0
-          };
-        } registers;
-
-        struct Power {
-          enum SubclassID {SUB_ID = 68};
-          const int16_t flash_update_ok_voltage = 2800; // mV
-          const int16_t sleep_current = 10; // mA
-          const uint16_t hibernate_current = 8; // mA
-          const uint16_t hibernate_voltage = 2550; // mV
-          enum Offset {
-            OFFSET_FlashUpdateOkVoltage = 0,
-            OFFSET_SleepCurrent = 7,
-            OFFSET_HibernateCurrent = 16,
-            OFFSET_HibernateVoltage = 18
-          };
-        } power;
-      } configuration;
-
-      struct SystemData
-      {
-        struct ManufacturerInfo {
-          enum SubclassID {SUB_ID = 57};
-          // the very first byte is reserved as magic byte (0xAA)
-          uint8_t version_major = 1;
-          uint8_t version_minor = 0;
-          enum Offset {
-            OFFSET_VersionMajor = 1,
-            OFFSET_VersionMinor = 2
-          };
-        } manufacturer_info;
-      } system_data;
-
-      struct FuelGauging
-      {
-        struct ITConfig {
-          enum SubclassID {SUB_ID = 80};
-          const uint8_t load_select = 1;
-          const uint8_t load_mode = 0;
-          const int16_t terminate_voltage = 3000; // mV
-          const int16_t user_rate_mA = 0; // mA
-          const int16_t user_rate_mW = 0; // mW
-          const int16_t reserve_cap_mAh = 0; // mAh
-          const int16_t reserve_cap_mWh = 0; // mWh
-          enum Offset {
-            OFFSET_LoadSelect = 0,
-            OFFSET_LoadMode = 1,
-            OFFSET_TerminateVoltage = 48,
-            OFFSET_UserRate_mA = 53,
-            OFFSET_UserRate_mW = 55,
-            OFFSET_ReserveCap_mAh = 57,
-            OFFSET_ReserveCap_mWh = 59
-          };
-        } it_config;
-
-        struct CurrentThresholds {
-          enum SubclassID {SUB_ID = 81};
-          const int16_t dsg_current_threshold = 60; // mA
-          const int16_t chg_current_threshold = 75; // mA
-          const int16_t quit_current = 40; // mA
-          const uint16_t dsg_relax_time = 60; // seconds
-          const uint16_t chg_relax_time = 60; // seconds
-          const uint8_t quit_relax_time = 1; // seconds
-          enum Offset {
-            OFFSET_DsgCurrentThreshold = 0,
-            OFFSET_ChgCurrentThreshold = 2,
-            OFFSET_QuitCurrent = 4,
-            OFFSET_DsgRelaxTime = 6,
-            OFFSET_ChgRelaxTime = 8,
-            OFFSET_QuitRelaxTime = 10
-          };
-        } current_thresholds;
-
-        struct State {
-          enum SubclassID {SUB_ID = 82};
-          const uint8_t it_enable = 0x00;
-          const uint8_t application_status = 0x00;
-          const int16_t qmax_0 = 1950; // mAh
-          const uint16_t cycle_count_0 = 0;
-          const uint8_t update_status_0 = 0x00;
-          const int16_t qmax_1 = 1950; // mAh
-          const uint16_t cycle_count_1 = 0;
-          const uint8_t update_status_1 = 0x00;
-          const int16_t avg_I_last_run = -299; // mA
-          const int16_t avg_P_last_run = -1131; // mAh
-          enum Offset {
-            OFFSET_ItEnable = 0,
-            OFFSET_ApplicationStatus = 1,
-            OFFSET_Qmax0 = 2,
-            OFFSET_CycleCount0 = 4,
-            OFFSET_UpdateStatus0 = 6,
-            OFFSET_Qmax1 = 7,
-            OFFSET_CycleCount1 = 9,
-            OFFSET_UpdateStatus1 = 11,
-            OFFSET_AvgILastRun = 16,
-            OFFSET_AvgPLastRun = 18
-          };
-        } state;
-      } fuel_gauging;
-
-      struct Security
-      {
-        struct Codes {
-          enum SubclassID {SUB_ID = 112};
-          const uint16_t unseal_key_0 = 0x3672;
-          const uint16_t unseal_key_1 = 0x0414;
-          const uint16_t full_access_key_0 = 0xFFFF;
-          const uint16_t full_access_key_1 = 0xFFFF;
-          enum Offset {
-            OFFSET_UnsealKey0 = 0,
-            OFFSET_UnsealKey1 = 2,
-            OFFSET_FullAccessKey0 = 4,
-            OFFSET_FullAccessKey1 = 6
-          };
-        } codes;
-      } security;
-
-    };
-
-    class Driver : public BaseSensor<InitData,CalibData>, public chibios_rt::BaseStaticThread<256>
-    {
-    public:
-      enum StandardCommand {
-                                                                            //  unit    |      access
-                                                                            //          | sealed  | unsealed
-                                                                            // ---------+---------+----------
-        STD_CMD_Control = 0x00u, STD_CMD_CNTL = 0x00u,                      // N/A      | R/W     | R/W
-        STD_CMD_AtRate = 0x02u, STD_CMD_AR = 0x02u,                         // mA       | R/W     | R/W
-        STD_CMD_AtRateTimeToEmpty = 0x04u, STD_CMD_ARTTE = 0x04u,           // minutes  | R       | R/W
-        STD_CMD_Temperatur = 0x06u, STD_CMD_TEMP = 0x06u,                   // 0.1 K    | R       | R/W
-        STD_CMD_Voltage = 0x08u, STD_CMD_VOLT = 0x08u,                      // mV       | R       | R/W
-        STD_CMD_Flags = 0x0Au, STD_CMD_FLAGS = 0x0Au,                       // N/A      | R       | R/W
-        STD_CMD_NominalAvailableCapacity = 0x0Cu, STD_CMD_NAC = 0x0Cu,      // mAh      | R       | R/W
-        STD_CMD_FullAvailableCapacity = 0x0Eu, STD_CMD_FAC = 0x0Eu,         // mAh      | R       | R/W
-        STD_CMD_RemainingCapacity = 0x10u, STD_CMD_RM = 0x10u,              // mAh      | R       | R/W
-        STD_CMD_FullChargeCapacity = 0x12u, STD_CMD_FCC = 0x12u,            // mAh      | R       | R/W
-        STD_CMD_AverageCurrent = 0x14u, STD_CMD_AI = 0x14u,                 // mA       | R       | R/W
-        STD_CMD_TimeToEmpty = 0x16u, STD_CMD_TTE = 0x16u,                   // minutes  | R       | R/W
-        STD_CMD_TimeToFull = 0x18u, STD_CMD_TTF = 0x18u,                    // minutes  | R       | R/W
-        STD_CMD_StandbyCurrent = 0x1Au, STD_CMD_SI = 0x1Au,                 // mA       | R       | R/W
-        STD_CMD_StandbyTimeToEmpty = 0x1Cu, STD_CMD_STTE = 0x1Cu,           // minutes  | R       | R/W
-        STD_CMD_MaxLoadCurrent = 0x1Eu, STD_CMD_MLI = 0x1Eu,                // mA       | R       | R/W
-        STD_CMD_MaxLoadTimeToEmpty = 0x20u, STD_CMD_MLTTE = 0x20u,          // minutes  | R       | R/W
-        STD_CMD_AvailableEnergy = 0x22u, STD_CMD_AE = 0x22u,                // mWh      | R       | R/W
-        STD_CMD_AveragePower = 0x24u, STD_CMD_AP = 0x24u,                   // mW       | R       | R/W
-        STD_CMD_TimeToEmptyAtConstantPower = 0x26u, STD_CMD_TTECP = 0x26u,  // minutes  | R       | R/W
-        STD_CMD_CycleCount = 0x2Au, STD_CMD_CC = 0x2Au,                     // counts   | R       | R/W
-        STD_CMD_StateOfCharge = 0x2Cu, STD_CMD_SOC = 0x2Cu                  // %        | R       | R/W
-      };
-
-      enum ControlSubcommand {
-                                            // sealed access
-                                            // -------------
-        SUB_CMD_CONTROL_STATUS = 0x0000u,   // yes
-        SUB_CMD_DEVICE_TYPE = 0x0001u,      // yes
-        SUB_CMD_FW_VERSION = 0x0002u,       // yes
-        SUB_CMD_HW_VERSION = 0x0003u,       // yes
-        SUB_CMD_DF_CHECKSUM = 0x0004u,      // no
-        SUB_CMD_RESET_DATA = 0x0005u,       // yes
-        SUB_CMD_PREV_MACWRITE = 0x0007u,    // yes
-        SUB_CMD_CHEM_ID = 0x0008u,          // yes
-        SUB_CMD_BOARD_OFFSET = 0x0009u,     // no
-        SUB_CMD_CC_INT_OFFSET = 0x000Au,    // no
-        SUB_CMD_WRITE_OFFSET = 0x000Bu,     // no
-        SUB_CMD_SET_HIBERNATE = 0x0011u,    // yes
-        SUB_CMD_CLEAR_HIBERNATE = 0x0012u,  // yes
-        SUB_CMD_SET_SLEEPp = 0x0013u,       // yes
-        SUB_CMD_CLEAR_SLEEPp = 0x0014u,     // yes
-        SUB_CMD_SEALED = 0x0020u,           // no
-        SUB_CMD_IT_ENABLE = 0x0021u,        // no
-        SUB_CMD_IF_CHECKSUM = 0x0022u,      // no
-        SUB_CMD_CAL_MODE = 0x0040u,         // no
-        SUB_CMD_RESET = 0x0041u,            // no
-      };
-
-      enum ExtendedCommand {
-                                                                    // length | unit | sealed | unsealed
-                                                                    // -------+------+--------+----------
-        EXT_CMD_DesignCapacity = 0x3Cu, EXT_CMD_DCAP = 0x3Cu,       //      2 |  mAh |     R  |      R
-        EXT_CMD_DataFlashClass = 0x3Eu, EXT_CMD_DFCLS = 0x3Eu,      //      1 |  N/A |    N/A |     R/W
-        EXT_CMD_DataFlashBlock = 0x3Fu, EXT_CMD_DFBLK = 0x3Fu,      //      1 |  N/A |    R/W |     R/W
-        EXT_CMD_BlockData = 0x40u, EXT_CMD_DFD = 0x40u,             //     32 |  N/A |     R  |     R/W
-        EXT_CMD_BlockDataCheckSum = 0x60u,EXT_CMD_DFDCKS = 0x60u,   //      1 |  N/A |    R/W |     R/W
-        EXT_CMD_BlockDataControl = 0x61u, EXT_CMD_DFDCNTL = 0x61u,  //      1 |  N/A |    N/A |     R/W
-        EXT_CMD_DeviceNameLength = 0x62u, EXT_CMD_DNAMELEN = 0x62u, //      1 |  N/A |     R  |      R
-        EXT_CMD_DeviceName = 0x63u, EXT_CMD_DNAME = 0x63u,          //      7 |  N/A |     R  |      R
-        EXT_CMD_ApplicationStatus = 0x6Au, EXT_CMD_APPSTAT = 0x6Au  //      1 |  N/A |     R  |      R
-      };
-
-      enum ExtendedCommandAccess {
-        EXT_CMD_READ = 0,
-        EXT_CMD_WRITE = 1,
-      };
-
-      enum SelftestResult {
-        ST_OK = BaseSensor<>::OK,
-        ST_ABORT_NO_BAT = BaseSensor<>::OK+1,
-        ST_FAIL_ANY = BaseSensor<>::FAIL,
-        ST_FAIL_READ_HW_VERSION = BaseSensor<>::FAIL + 1,
-        ST_FAIL_READ_FW_VERSION = BaseSensor<>::FAIL + 2,
-        ST_FAIL_READ_DEVICENAMELENGTH = BaseSensor<>::FAIL + 3,
-        ST_FAIL_READ_DEVICENAME = BaseSensor<>::FAIL + 4,
-        ST_FAIL_SET_ITENABLE = BaseSensor<>::FAIL + 5,
-        ST_FAIL_READ_STATUS = BaseSensor<>::FAIL + 6,
-        ST_FAIL_READ_FLAGS = BaseSensor<>::FAIL + 7,
-        ST_FAIL_READ_TEMP = BaseSensor<>::FAIL + 8,
-        ST_FAIL_READ_FAC = BaseSensor<>::FAIL + 9,
-        ST_FAIL_READ_FCC = BaseSensor<>::FAIL + 10,
-        ST_FAIL_READ_RM = BaseSensor<>::FAIL + 11,
-        ST_FAIL_READ_SOC = BaseSensor<>::FAIL + 12,
-        ST_FAIL_READ_VOLT = BaseSensor<>::FAIL + 13,
-        ST_FAIL_READ_AI = BaseSensor<>::FAIL + 14,
-        ST_FAIL_READ_AP = BaseSensor<>::FAIL + 15,
-        ST_FAIL_READ_TTE = BaseSensor<>::FAIL + 16,
-        ST_FAIL_READ_TTF = BaseSensor<>::FAIL + 17
-      };
-
-      union ControlStatus {
-        uint16_t value = 0;
-        struct {
-          uint16_t qen : 1;
-          uint16_t vok : 1;
-          uint16_t rup_dis : 1;
-          uint16_t ldmd : 1;
-          uint16_t sleep : 1;
-          uint16_t snooze : 1;
-          uint16_t hibernate : 1;
-          uint16_t rsvd_7_8_9 : 3;
-          uint16_t bca : 1;
-          uint16_t cca : 1;
-          uint16_t csv : 1;
-          uint16_t ss : 1;
-          uint16_t fas : 1;
-          uint16_t rsvd_15 : 1;
-        } content;
-      };
-
-      union Flags {
-        uint16_t value = 0;
-        struct {
-          uint16_t dsg : 1;
-          uint16_t socf : 1;
-          uint16_t soc1 : 1;
-          uint16_t bat_det : 1;
-          uint16_t wait_id : 1;
-          uint16_t ocv_gd : 1;
-          uint16_t rsvd_6_7 : 2;
-          uint16_t chg : 1;
-          uint16_t fc : 1;
-          uint16_t xchg : 1;
-          uint16_t chg_inh : 1;
-          uint16_t rsvd_12_13 : 2;
-          uint16_t otd : 1;
-          uint16_t otc : 1;
-        } content;
-      };
-
-      union Version {
-        uint16_t value = 0;
-        struct {
-          uint16_t minor_low : 4;
-          uint16_t minor_high : 4;
-          uint16_t major_low : 4;
-          uint16_t major_high : 4;
-        } content;
-      };
-
-      struct UpdateData {
-        uint16_t minutes_to_empty;
-        uint16_t minutes_to_full;
-        uint16_t average_power_mW;
-        uint8_t state_of_charge; // %
-      };
-
-    private:
-      enum I2CAddress {
-        I2C_ADDR = 0x55u
-      };
-
-      enum DataFlashSubClassID {
-        CONFIGURATION_Safety = 2,
-        CONFIGURATION_ChargeInhibitConfig = 32,
-        CONFIGURATION_Charge = 34,
-        CONFIGURATION_ChargeTermination = 36,
-        CONFIGURATION_Data = 48,
-        CONFIGURATION_Discharge = 49,
-        SYSTEM_DATA_ManufacturerInfo = 57,
-        CONFIGURATION_Registers = 64,
-        CONFIGURATION_Power = 68,
-        FUEL_GAUGING_ItCfg = 80,
-        FUEL_GAUGING_CurrentThresholds = 81,
-        FUEL_GAUGING_State = 82,
-        DEFAULT_RA_TABLES_Def0Ra = 87,
-        DEFAULT_RA_TABLES_Def1Ra = 88,
-        RA_TABLES_Pack0Ra = 91,
-        RA_TABLES_Pack1Ra = 92,
-        RA_TABLES_Pack0Rax = 93,
-        RA_TABLES_Pack1Rax = 94,
-        CALIBRATION_Data = 104,
-        CALIBRATION_Current = 107,
-        SECURITY_Codes = 112
-      };
-
-      union DataFlashBlock {
-        uint8_t raw[33];
-        struct Content {
-          uint8_t data[32];
-          uint8_t checksum;
-        } content;
-      };
-
-      I2CDriver *const i2c_driver;
-      I2CTxParams tx_params;
-
-      chibios_rt::EvtSource eventSource;
-
-      const GPIO_TypeDef* const batgd_pingrp;
-      const uint8_t batgd_pin;
-      const GPIO_TypeDef* const batlow_pingrp;
-      const uint8_t batlow_pin;
-
-      UpdateData status;
-
-    public:
-      Driver(I2CDriver &i2c_driver, const GPIO_TypeDef &batgd_pingrp, const uint8_t batgd_pin, const GPIO_TypeDef &batlow_pingrp, const uint8_t batlow_pin);
-      virtual ~Driver();
-
-      chibios_rt::EvtSource* getEventSource();
-
-      msg_t init(InitData* initialization_data = NULL);
-      msg_t update();
-      msg_t wakeup();
-      msg_t hibernate();
-  #ifndef AMIRO_NCALIBRATION
-      msg_t calibration(CalibData* calibration_data = NULL);
-  #endif
-  #ifndef AMIRO_NSELFTEST
-      msg_t selftest();
-  #endif
-
-      bool isBatteryGood() const;
-      bool isBatteryLow() const;
-
-      const UpdateData& getStatus() const;
-
-    protected:
-      virtual msg_t main(void);
-
-    private:
-      msg_t stdCommand(const StandardCommand cmd, uint16_t &dst);
-      msg_t readName();
-      msg_t subCommand(const ControlSubcommand cmd, uint16_t* dst = NULL);
-      msg_t extCommand(const ExtendedCommand cmd, const ExtendedCommandAccess rw, uint8_t* buf = NULL, const uint8_t length = 1, const uint8_t offset = 0);
-
-      msg_t readDataFlashBlock(DataFlashBlock &block, const DataFlashSubClassID sub_id, const uint8_t sub_block = 0);
-
-    };
-
-  }
-
-}
-
-#endif /* AMIRO_BQ27500_H_ */
diff --git a/include/amiro/power/ina219.hpp b/include/amiro/power/ina219.hpp
deleted file mode 100644
index d772d89..0000000
--- a/include/amiro/power/ina219.hpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * INA219 - Power Monitor
- */
-
-#ifndef AMIRO_INA219_H_
-#define AMIRO_INA219_H_
-
-#include <ch.hpp>
-#include <amiro/bus/i2c/I2CParams.hpp>
-#include <amiro/bus/i2c/I2CDriver.hpp>
-
-#include <amiro/BaseSensor.hpp>
-
-namespace amiro {
-
-  namespace INA219 {
-
-    namespace Configuration
-    {
-      union Register {
-        uint16_t value = 0;
-        struct {
-          uint16_t mode : 3;
-          uint16_t sadc : 4;
-          uint16_t badc : 4;
-          uint16_t pg : 2;
-          uint16_t brng : 1;
-          uint16_t rsvd : 1;
-          uint16_t rst : 1;
-        } content;
-      };
-
-      enum BusRange {
-        BRNG_16V = 0,
-        BRNG_32V = 1, BRNG_DEFAULT = 1
-      };
-
-      enum Pga {
-        PGA_40mV = 0,
-        PGA_80mV = 1,
-        PGA_160mV = 2,
-        PGA_320mV = 3, PGA_DEFAULT = 3
-      };
-
-      enum Adc {
-        ADC_84us = 0x0u,
-        ADC_148us = 0x1u,
-        ADC_276us = 0x2u,
-        ADC_532us = 0x3u, ADC_632us_alt = 0x8u, ADC_DEFAULT = 0x3u,
-        ADC_1060us = 0x9u,
-        ADC_2130us = 0xAu,
-        ADC_4260us = 0xBu,
-        ADC_8510us = 0xCu,
-        ADC_17020us = 0xDu,
-        ADC_34050us = 0xEu,
-        ADC_68100us = 0xFu
-      };
-
-      enum Mode {
-        MODE_PowerDown = 0x0u,
-        MODE_ShuntV_Triggered = 0x1u,
-        MODE_BusV_Triggered = 0x2u,
-        MODE_ShuntBus_Triggered = 0x3u,
-        MODE_AdcOff = 0x4u,
-        MODE_ShuntV_Continuous = 0x5u,
-        MODE_BusV_Continuous = 0x6u,
-        MODE_ShuntBus_Continuous = 0x7u, MODE_DEFAULT = 0x7u
-      };
-    } // end of namespace Configuration
-
-
-
-    struct InitData {
-      Configuration::Register configuration;
-      uint16_t calibration;
-      uint16_t current_lsb_uA;
-    };
-
-    struct CalibData {
-      struct CalibInput {
-        float shunt_resistance_O;
-        float max_expected_current_A;
-        uint16_t current_lsb_uA;
-        Configuration::Register configuration;
-      } input;
-      struct CalibOutput {
-        float max_current_before_overflow_A;
-        float max_shuntvoltage_before_overflow_V;
-        uint16_t current_lsb_uA;
-        uint16_t calibration_value;
-      } output;
-
-      uint16_t power_lsb_uW() const
-      {
-        return 20 * output.current_lsb_uA;
-      }
-
-      float maximum_power_W() const
-      {
-        return output.max_current_before_overflow_A * ((input.configuration.content.brng == Configuration::BusRange::BRNG_32V)? 32 : 16);}
-    };
-
-    struct BusVoltage {
-      uint32_t voltage_uV : 25;
-      uint32_t rsvd : 5;
-      uint32_t conversion_ready : 1;
-      uint32_t overflow : 1;
-    };
-
-    class Driver : public BaseSensor<InitData,CalibData>, public chibios_rt::BaseStaticThread<256>
-    {
-    public:
-      enum SelftestResult {
-        ST_OK = BaseSensor<>::OK,
-        ST_FAIL_ANY = BaseSensor<>::FAIL,
-        ST_FAIL_BACKUP = BaseSensor<>::FAIL + 1,
-        ST_FAIL_RESET = BaseSensor<>::FAIL + 2,
-        ST_FAIL_IS_DEFAULT = BaseSensor<>::FAIL + 3,
-        ST_FAIL_WRITE_CONFIG = BaseSensor<>::FAIL + 4,
-        ST_FAIL_WRITE_CALIB = BaseSensor<>::FAIL + 5,
-        ST_FAIL_CHECK_CONFIG = BaseSensor<>::FAIL + 6,
-        ST_FAIL_CHECK_CALIB = BaseSensor<>::FAIL + 7
-      };
-
-    private:
-      union BusVoltage {
-        uint16_t value = 0;
-        struct {
-          uint16_t overflow : 1;
-          uint16_t conversion_ready : 1;
-          uint16_t rsvd : 1;
-          uint16_t voltage : 13;
-        } content;
-      };
-
-      struct Status {
-        Driver::BusVoltage bus_voltage;
-        uint16_t power;
-
-        Status() {bus_voltage.value = 0; power = 0;}
-      };
-
-    public:
-      enum RegisterAddress {
-        REG_CONFIGURATION = 0x00u,
-        REG_SHUNT_VOLTAGE = 0x01u,
-        REG_BUS_VOLTAGE = 0x02u,
-        REG_POWER = 0x03u,
-        REG_CURRENT = 0x04u,
-        REG_CALIBRATION = 0x05u
-      };
-
-    private:
-      enum RegisterMask {
-        MASK_CONFIGURATION = 0x3FFFu,
-        MASK_CALIBRATION = 0xFFFEu,
-        MASK_RESET = 0x8000u
-      };
-
-      I2CDriver *const i2c_driver;
-      I2CTxParams tx_params;
-      Configuration::Register config;
-      uint16_t current_lsb_uA;
-      Status status;
-
-    public:
-      /* constructor & destructor */
-      explicit Driver(I2CDriver &i2c_driver, const uint8_t i2c_address);
-      virtual ~Driver();
-
-      /* inherited functions from BaseSensor */
-      msg_t init(InitData* initialization_data = NULL);
-      msg_t update();
-      msg_t wakeup();
-      msg_t hibernate();
-#ifndef AMIRO_NCALIBRATION
-      msg_t calibration(CalibData* calibration_data = NULL);
-#endif
-#ifndef AMIRO_NSELFTEST
-      msg_t selftest();
-#endif
-
-      INA219::BusVoltage getVoltage() const
-      {
-        return this->busVoltageReg2uV(this->status.bus_voltage);
-      }
-
-      uint32_t getPower_uW() const
-      {
-        return this->powerReg2uW(this->status.power);
-      }
-
-      uint32_t getCurrent_uA() const
-      {
-        return this->powerReg2uW(this->status.power) / this->busVoltageReg2uV(this->status.bus_voltage).voltage_uV;
-      }
-
-
-
-      inline Configuration::Register readConfiguration();
-      inline int32_t readShuntVoltage_uV();
-      inline INA219::BusVoltage readBusVoltage();
-      inline uint32_t readPower_uW();
-      inline int32_t readCurrent_uA();
-      inline uint16_t readCalibration();
-
-      uint8_t reset();
-
-    protected:
-      virtual msg_t main(void);
-
-    public:
-      msg_t readRegister(const RegisterAddress reg, uint16_t& dst);
-      msg_t writeRegister(const RegisterAddress reg, const uint16_t& val);
-
-    private:
-      static inline INA219::BusVoltage busVoltageReg2uV(const INA219::Driver::BusVoltage reg_val)
-      {
-        INA219::BusVoltage bus_voltage;
-        bus_voltage.conversion_ready = reg_val.content.conversion_ready;
-        bus_voltage.overflow = reg_val.content.conversion_ready;
-        /*
-         * The least significant bit represents 4mV.
-         * -> Multiply with 4000 in order to convert to uV.
-         */
-        bus_voltage.voltage_uV = reg_val.content.voltage * 4000;
-        return bus_voltage;
-      }
-
-      inline uint32_t powerReg2uW(const uint16_t reg_val) const
-      {
-        /*
-         * Multiply with the value of the least significant bit for the current and the constant 20.
-         * -> see data sheet, chapter 'Programming the INA219 power measurement engine' for details
-         */
-        return reg_val * 20 * this->current_lsb_uA;
-      }
-    };
-
-  } // end of namespace INA219
-
-}
-
-#endif /* AMIRO_INA219_H_ */
diff --git a/include/amiro/power/ltc4412.hpp b/include/amiro/power/ltc4412.hpp
deleted file mode 100644
index 195b23c..0000000
--- a/include/amiro/power/ltc4412.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * LTC4412 - PowerPath Controller
- */
-
-#ifndef AMIRO_LTC4412_H_
-#define AMIRO_LTC4412_H_
-
-#include <hal.h>
-
-namespace amiro {
-
-class BaseLTC4412
-{
-public:
-  BaseLTC4412()
-  {}
-
-  virtual ~BaseLTC4412()
-  {}
-
-  virtual bool isPluggedIn() const = 0;
-};
-
-class BaseLTC4412wEN : public BaseLTC4412
-{
-public:
-  BaseLTC4412wEN()
-  {}
-
-  virtual ~BaseLTC4412wEN()
-  {}
-
-  virtual void enable(const bool enable = true) = 0;
-
-  virtual bool isEnabled() const = 0;
-
-  virtual bool isPluggedIn() const = 0;
-};
-
-
-
-template <uintptr_t STAT_PadGrp, uint8_t STAT_Pad>
-class LTC4412 : public BaseLTC4412
-{
-public:
-  LTC4412()
-  {}
-
-  virtual ~LTC4412()
-  {}
-
-  bool isPluggedIn() const
-  {
-    return (palReadPad((GPIO_TypeDef*)STAT_PadGrp, STAT_Pad) == PAL_HIGH);
-  }
-
-};
-
-template <uintptr_t STAT_PadGrp, uint8_t STAT_Pad, uintptr_t EN_PadGrp, uint8_t EN_Pad>
-class LTC4412wEN : public BaseLTC4412wEN
-{
-private:
-  bool is_enabled;
-
-public:
-  LTC4412wEN(const bool enable = false) :
-    is_enabled(enable)
-  {
-    this->enable(enable);
-  }
-
-  virtual ~LTC4412wEN()
-  {}
-
-  void enable(const bool enable = true)
-  {
-    // writing to a port is not atomic, thus the system must be locked
-    chSysLock();
-    palWritePad((GPIO_TypeDef*)EN_PadGrp, EN_Pad, enable? PAL_LOW : PAL_HIGH);
-    this->is_enabled = enable;
-    chSysUnlock();
-  }
-
-  bool isEnabled() const
-  {
-    return this->is_enabled;
-  }
-
-  bool isPluggedIn() const
-  {
-    return (palReadPad((GPIO_TypeDef*)STAT_PadGrp, STAT_Pad) == PAL_HIGH);
-  }
-
-};
-
-}
-
-#endif /* AMIRO_LTC4412_H_ */
diff --git a/include/amiro/power/tps62113.hpp b/include/amiro/power/tps62113.hpp
deleted file mode 100644
index cd6989f..0000000
--- a/include/amiro/power/tps62113.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * TPS62113 - StepDown Converter
- */
-
-#ifndef AMIRO_TPS62113_H_
-#define AMIRO_TPS62113_H_
-
-namespace amiro {
-
-  template <uintptr_t PadGrp, uint32_t Pad>
-  class TPS62113
-  {
-    public:
-    TPS62113()
-    {}
-
-    ~TPS62113()
-    {}
-
-    static void enable(const bool en = true)
-    {
-      palWritePad((GPIO_TypeDef*)PadGrp, Pad, (en? PAL_HIGH : PAL_LOW));
-      return;
-    }
-  };
-
-}
-
-#endif /* AMIRO_TPS62113_H_ */
diff --git a/include/amiro/proximity/vcnl4020.hpp b/include/amiro/proximity/vcnl4020.hpp
deleted file mode 100644
index 06c9dfb..0000000
--- a/include/amiro/proximity/vcnl4020.hpp
+++ /dev/null
@@ -1,236 +0,0 @@
-#ifndef AMIRO_VCNL4020_H_
-#define AMIRO_VCNL4020_H_
-
-#include <amiro/bus/i2c/I2CParams.hpp>
-
-namespace amiro {
-
-class I2CDriver;
-
-/**
- * VCNL4020 IR Proximity/Ambient Light Sensor Driver
- * \todo Interrupt Support
- */
-class VCNL4020 : public chibios_rt::BaseStaticThread<256> {
-
-    enum { SLA = 0x13u };
-
-    enum { PRODUCT_ID_REVISION = 0x21u };
-
-    struct registers {
-
-      uint8_t  reserved_0x00_0x7F[0x80u];
-      uint8_t  command;
-      uint8_t  revision;
-      uint8_t  proximity_rate;
-      uint8_t  ir_led_current;
-      uint8_t  ambient_param;
-      uint16_t ambient_result; /* BE */
-      uint16_t proximity_result; /* BE */
-      uint8_t  interrupt_ctrl;
-      uint16_t low_thres; /* BE */
-      uint16_t high_thres; /* BE */
-      uint8_t  interrupt_status;
-      uint8_t  proximity_adjust;
-      uint8_t  ambient_ir_level; /* Do Not Use */
-    } __attribute__((packed));
-
-  public:
-
-    struct VCNL4020Config {
-
-      uint8_t command;
-      uint8_t ambient_parameter;
-      uint8_t ir_led_current_mA;
-      uint8_t proximity_rate;
-
-    };
-
-    enum {
-
-      PROX_RATE_1_95    = 0x00u, /* 250 / (2**(7-0)) */
-      PROX_RATE_3_90625 = 0x01u, /* 250 / (2**(7-1)) */
-      PROX_RATE_7_8125  = 0x02u, /* 250 / (2**(7-2)) */
-      PROX_RATE_15_625  = 0x03u, /* 250 / (2**(7-3)) */
-      PROX_RATE_31_25   = 0x04u, /* 250 / (2**(7-4)) */
-      PROX_RATE_62_5    = 0x05u, /* 250 / (2**(7-5)) */
-      PROX_RATE_125     = 0x06u, /* 250 / (2**(7-6)) */
-      PROX_RATE_250     = 0x07u  /* 250 / (2**(7-7)) */
-
-    };
-
-    enum {
-
-      AMBIENT_CONT_CONV   = 0x80u,
-      AMBIENT_RATE_1      = 0x00u,
-      AMBIENT_RATE_2      = 0x10u,
-      AMBIENT_RATE_3      = 0x20u,
-      AMBIENT_RATE_4      = 0x30u,
-      AMBIENT_RATE_5      = 0x40u,
-      AMBIENT_RATE_6      = 0x50u,
-      AMBIENT_RATE_8      = 0x60u,
-      AMBIENT_RATE_10     = 0x70u,
-      AMBIENT_AUTO_OFFSET = 0x10u,
-      AMBIENT_AVG_1       = 0x00u,
-      AMBIENT_AVG_2       = 0x01u,
-      AMBIENT_AVG_4       = 0x02u,
-      AMBIENT_AVG_8       = 0x03u,
-      AMBIENT_AVG_16      = 0x04u,
-      AMBIENT_AVG_32      = 0x05u,
-      AMBIENT_AVG_64      = 0x06u,
-      AMBIENT_AVG_128     = 0x07u,
-
-    };
-
-    enum {
-      INT_THRES_SEL     = 0x01u,
-      INT_THRES_EN      = 0x02u,
-      INT_ALS_READY_EN  = 0x04u,
-      INT_PROX_READY_EN = 0x08u,
-    };
-
-    enum {
-      INT_TH_HI      = 0x01u,
-      INT_TH_LOW     = 0x02u,
-      INT_ALS_READY  = 0x04u,
-      INT_PROX_READY = 0x08u,
-      INT_CNT_1      = 0x00u,
-      INT_CNT_2      = 0x20u,
-      INT_CNT_4      = 0x40u,
-      INT_CNT_8      = 0x60u,
-      INT_CNT_16     = 0x80u,
-      INT_CNT_32     = 0xA0u,
-      INT_CNT_64     = 0xC0u,
-      INT_CNT_128    = 0xE0u,
-    };
-
-    enum {
-
-      MOD_DLY_MASK    = 0x07u,
-      MOD_DLY_SHIFT   = 0x05u,
-      MOD_DEAD_MASK   = 0x07u,
-      MOD_DEAD_SHIFT  = 0x00u,
-      PROX_FREQ_390   = 0x00u,
-      PROX_FREQ_781   = 0x08u,
-      PROX_FREQ_1_562 = 0x10u,
-      PROX_FREQ_3_125 = 0x18u,
-
-    };
-
-    enum {
-
-      CONFIG_LOCK   = 0x80u,
-      ALS_DATA_RDY  = 0x40u,
-      PROX_DATA_RDY = 0x20u,
-      ALS_OD        = 0x10u,
-      PROX_OD       = 0x08u,
-      ALS_EN        = 0x04u,
-      PROX_EN       = 0x02u,
-      SELFTIMED_EN  = 0x01u,
-
-    };
-
-    /**
-     * Return types of getCheck()
-     */
-    enum {
-      CHECK_OK   = 0x00u,
-      CHECK_FAIL = 0x01u,
-    };
-
-    /**
-     * Return types of calibration
-     */
-    enum {
-      CALIB_OK   = 0x00u,
-      CALIB_FAIL = 0x01u,
-    };
-
-  public:
-    VCNL4020(I2CDriver *driver, const VCNL4020Config *config);
-    virtual ~VCNL4020();
-
-    chibios_rt::EvtSource* getEventSource();
-
-    /**
-     * Returns the last measured ambient light value.
-     *
-     * @return Measured ambient light value
-     */
-    uint16_t getAmbientLight();
-
-    /**
-     * Returns the last measured proximity value w/o offset.
-     * Additionally, the value is scaled, so that full-scale
-     * as a measurement can be reached.
-     *
-     * @return Measured proximity value without offset
-     */
-    uint16_t getProximityScaledWoOffset();
-
-    /**
-     * Returns the last measured proximity value.
-     *
-     * @return Measured proximity value
-     */
-    uint16_t getProximity();
-
-    /**
-     * Returns the offset of the vcnl4020.
-     * calibrate() or setOffset() needs to be run first,
-     * otherwise the return value is 0.
-     *
-     * @return Offset value of the device
-     */
-    uint16_t getProximityOffset();
-
-    /**
-     * Sets the offset value, which will be substracted from
-     * the measured value.
-     *
-     * @param offset
-     */
-    void setProximityOffset(uint16_t offset);
-
-    /**
-     * Checks the vcnl4020 by reading the product
-     * id from it an comparing it to the standard
-     * value
-     *
-     * @return [CHECK_OK | CHECK_FAIL]
-     */
-    uint8_t getCheck();
-
-    /**
-     * Starts the calibration of the vcnl4020 and
-     *
-     * @return [ CALIB_OK | CALIB_FAIL]
-     */
-    uint8_t calibrate();
-
-  protected:
-    virtual msg_t main(void);
-
-  private:
-    inline msg_t readIntensities();
-    inline msg_t writeIRConf();
-
-    /**
-     * Starts the offset calibration
-     *
-     * @return [ CALIB_OK | CALIB_FAIL]
-     */
-    uint8_t calibrateOffset(uint16_t &proximityFloorMeanValue);
-
-    I2CDriver *driver;
-    const VCNL4020Config *config;
-    chibios_rt::EvtSource eventSource;
-    uint16_t ambient;
-    uint16_t proximity;
-    uint16_t proximityOffset;
-    I2CTxParams tx_params;
-};
-
-}
-
-#endif /* AMIRO_VCNL4020_H_ */
diff --git a/include/amiro/radio/a2500r24a.hpp b/include/amiro/radio/a2500r24a.hpp
deleted file mode 100644
index 32fe696..0000000
--- a/include/amiro/radio/a2500r24a.hpp
+++ /dev/null
@@ -1,164 +0,0 @@
-#ifndef A2500R24A_HPP_
-#define A2500R24A_HPP_
-
-#include <ch.hpp>
-
-namespace amiro {
-
-class HWSPIDriver;
-
-class A2500R24A : public chibios_rt::BaseStaticThread<256> {
-
- public:
-
-  struct A2500R24AConfig {
-  };
-
-  /**
-   * Return types of getCheck()
-   */
-  enum {
-    CHECK_OK = 0x00u,
-    CHECK_FAIL = 0x01u,
-  };
-
-  //private:
-
-  struct registers {
-    uint8_t IOCFG2;
-    uint8_t IOCFG1;
-    uint8_t IOCFG0;
-    uint8_t FIFOTHR;
-    uint8_t SYNC1;
-    uint8_t SYNC0;
-    uint8_t PKTLEN;
-    uint8_t PKTCTRL1;
-    uint8_t PKTCTRL0;
-    uint8_t ADDR;
-    uint8_t CHANNR;
-    uint8_t FSCTRL1;
-    uint8_t FSCTRL0;
-    uint8_t FREQ2;
-    uint8_t FREQ1;
-    uint8_t FREQ0;
-    uint8_t MDMCFG4;
-    uint8_t MDMCFG3;
-    uint8_t MDMCFG2;
-    uint8_t MDMCFG1;
-    uint8_t MDMCFG0;
-    uint8_t DEVIATN;
-    uint8_t MCSM2;
-    uint8_t MCSM1;
-    uint8_t MCSM0;
-    uint8_t FOCCFG;
-    uint8_t BSCFG;
-    uint8_t AGCCTRL2;
-    uint8_t AGCCTRL1;
-    uint8_t AGCCTRL0;
-    uint8_t WOREVT1;
-    uint8_t WOREVT0;
-    uint8_t WORCTRL;
-    uint8_t FREND1;
-    uint8_t FREND0;
-    uint8_t FSCAL3;
-    uint8_t FSCAL2;
-    uint8_t FSCAL1;
-    uint8_t FSCAL0;
-    uint8_t RCCTRL1;
-    uint8_t RCCTRL0;
-    uint8_t FSTEST;
-    uint8_t PTEST;
-    uint8_t AGCTEST;
-    uint8_t TEST2;
-    uint8_t TEST1;
-    uint8_t TEST0;
-    uint8_t reserved_0x2F;
-  }__attribute__((packed));
-
-  struct registerStrobe {
-    uint8_t configurationRegister[offsetof(A2500R24A::registers, reserved_0x2F)+1];
-    uint8_t SRES;
-    uint8_t SFSTXON;
-    uint8_t SXOFF;
-    uint8_t SCAL;
-    uint8_t SRX;
-    uint8_t STX;
-    uint8_t SIDLE;
-    uint8_t reserved_0x37;
-    uint8_t SWOR;
-    uint8_t SPWD;
-    uint8_t SFRX;
-    uint8_t SFTX;
-    uint8_t SWORRST;
-    uint8_t SNOP;
-    uint8_t PATABLE;
-    uint8_t RX_TX_FIFO;
-  }__attribute__((packed));
-
-  struct registerStatus {
-    uint8_t configurationRegister[offsetof(A2500R24A::registers, reserved_0x2F)+1];
-    uint8_t PARTNUM;
-    uint8_t VERSION;
-    uint8_t FREQEST;
-    uint8_t LQI;
-    uint8_t RSSI;
-    uint8_t MARCSTATE;
-    uint8_t WORTIME1;
-    uint8_t WORTIME0;
-    uint8_t PKTSTATUS;
-    uint8_t VCO_VC_DAC;
-    uint8_t TXBYTES;
-    uint8_t RXBYTES;
-    uint8_t RCCTRL1_STATUS;
-    uint8_t RCCTRL0_STATUS;
-  }__attribute__((packed));
-
-  enum {
-    A2500R24A_PARTNUM = 0x80u,
-    A2500R24A_VERSION = 0x03u,
-  };
-
-  enum {
-    // For register access below address 0x30 the burst mode is available
-    // to read multiple bytes
-    SPI_BURST_ENA     = 0x40u,
-    SPI_BURST_DIS     = 0x00u,
-    // For addresses above (and including) 0x30 either the status or strobe access
-    // has to be choosen, instead of burst mode
-    SPI_STATUS_ACCESS = 0x40u,
-    SPI_STROBE_ACCESS = 0x00u,
-    // Read or write the register address
-    SPI_READ      = 0x80u,
-    SPI_WRITE     = 0x00u,
-  };
-
- public:
-  A2500R24A(HWSPIDriver* driver);
-  virtual ~A2500R24A();
-
-  chibios_rt::EvtSource* getEventSource();
-  msg_t configure(A2500R24AConfig* config);
-
-  /**
-   * Check the presence of the radio chip by reading
-   * the identifier register and comparing it to the standard
-   * value
-   */
-  uint8_t getCheck();
-
- protected:
-  virtual msg_t main();
-
- private:
-  inline void updateSensorData();
-
- private:
-
-  HWSPIDriver* driver;
-  chibios_rt::EvtSource eventSource;
-
-};
-
-} /* amiro */
-
-#endif /* A2500R24A_HPP_ */
diff --git a/include/amiro/serial_reset/iwrap_can_mux.hpp b/include/amiro/serial_reset/iwrap_can_mux.hpp
deleted file mode 100644
index e9b50b6..0000000
--- a/include/amiro/serial_reset/iwrap_can_mux.hpp
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef IWRAP_CAN_MUX_HPP_
-#define IWRAP_CAN_MUX_HPP_
-
-#include <ch.hpp>
-
-#define BLUETOOTH_START_FRAME   0xBF
-/** \brief Define bluetooth link address to iWRAP control */
-#define BLUETOOTH_LINK          0x00
-/** \brief Define bluetooth frame flags */
-#define BLUETOOTH_FLAGS         0x00
-/** \brief Define nLINK = {LINK} XOR 0xFF */
-#define BLUETOOTH_NLINK         0xFF
-
-/* States of bluetooth communication */
-/** \brief bluetooth waiting for start frame signal */
-#define BLUETOOTH_STATUS_START    0
-/** \brief bluetooth waiting for link address */
-#define BLUETOOTH_STATUS_LINK     1
-/** \brief bluetooth waiting for frame flags */
-#define BLUETOOTH_STATUS_FLAGS    2
-/** \brief bluetooth waiting for data length */
-#define BLUETOOTH_STATUS_LENGTH   3
-/** \brief bluetooth waiting for data */
-#define BLUETOOTH_STATUS_DATA     4
-/** \brief bluetooth waiting for frame end (nLINK) */
-#define BLUETOOTH_STATUS_END      5
-
-#define OFFSET_TIME_RESET_MS                2000
-#define INPUT_BL_RESET_ADDITIONAL_BYTES     0
-#define INPUT_BL_RESET_LENGTH               3
-
-namespace amiro {
-
-  class IwrapCanMux : public chibios_rt::BaseSequentialStreamInterface {
-  public:
-    IwrapCanMux(SerialDriver *_sd_, CANDriver *can, const uint8_t boardId);
-    virtual ~IwrapCanMux();
-
-    void convCan2Serial(uint8_t *inputs, size_t n);
-    void sendSwitchCmd(uint8_t setid);
-    void rcvSwitchCmd(uint8_t setid);
-
-    size_t write(const uint8_t *bp, size_t n);
-    size_t read(uint8_t *bp, size_t n);
-    msg_t put(uint8_t b);
-    msg_t get(void);
-
-  protected:
-
-
-  private:
-    /* Reset command. */
-    const uint8_t inputBLReset[3] = {0x02, 0xFF, 0x00};
-//    const uint8_t inputchshell[3] = {0x00, 0x68, 0x0D};
-//    const uint8_t inputsh_board[8] = {0x73, 0x68, 0x5F, 0x62, 0x6F, 0x61, 0x72, 0x6C};
-
-//    void checkBluetoothStatus(void)
-    void restartSystem(void);
-    bool checkByteForBLReset(uint8_t *inputs, size_t size);
-    msg_t sendViaCan(uint32_t id, uint8_t *inputs, size_t size);
-
-    uint8_t inputAddBytes[INPUT_BL_RESET_ADDITIONAL_BYTES];    // Buffer for additional bytes.
-    uint8_t resetStatus;      // Status of reset
-    uint8_t resetAddBytes;    // Counter of additional bytes
-    uint8_t bluetoothStatus;
-
-    SerialDriver *sd_;
-    CANDriver *canDriver;
-    uint8_t myID;
-    volatile uint8_t queryShellID;
-    volatile uint8_t replyShellID;
-
-    CANTxFrame txmsg;
-    uint8_t inputChar[16] = {};
-  };
-
-} /* amiro */
-
-#endif /* IWRAP_CAN_MUX_HPP_ */
-
-
diff --git a/include/amiro/serial_reset/serial_can_mux.hpp b/include/amiro/serial_reset/serial_can_mux.hpp
deleted file mode 100644
index b19849d..0000000
--- a/include/amiro/serial_reset/serial_can_mux.hpp
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef SERIAL_CAN_MUX_HPP_
-#define SERIAL_CAN_MUX_HPP_
-
-#include <ch.hpp>
-
-#define OFFSET_TIME_RESET_MS                2000
-#define INPUT_BL_RESET_ADDITIONAL_BYTES     0
-#define INPUT_BL_RESET_LENGTH               3
-
-namespace amiro {
-
-  class SerialCanMux : public chibios_rt::BaseSequentialStreamInterface {
-  public:
-    SerialCanMux(SerialDriver *_sd_, CANDriver *can, const uint8_t boardId);
-    virtual ~SerialCanMux();
-
-    void convCan2Serial(uint8_t *inputs, size_t n);
-    void sendSwitchCmd(uint8_t setid);
-    void rcvSwitchCmd(uint8_t setid);
-
-    size_t write(const uint8_t *bp, size_t n);
-    size_t read(uint8_t *bp, size_t n);
-    msg_t put(uint8_t b);
-    msg_t get(void);
-
-  protected:
-
-  private:
-    /* Reset command. */
-    const uint8_t inputBLReset[3] = {0x02, 0xFF, 0x00};
-//    const uint8_t inputchshell[3] = {0x00, 0x68, 0x0D};
-//    const uint8_t inputsh_board[8] = {0x73, 0x68, 0x5F, 0x62, 0x6F, 0x61, 0x72, 0x6C};
-
-    void restartSystem(void);
-    bool checkByteForBLReset(uint8_t *inputs, size_t size);
-    msg_t sendViaCan(uint32_t id, uint8_t *inputs, size_t size);
-
-    uint8_t inputAddBytes[INPUT_BL_RESET_ADDITIONAL_BYTES];    // Buffer for additional bytes.
-    uint8_t resetStatus;      // Status of reset
-    uint8_t resetAddBytes;    // Counter of additional bytes
-
-    SerialDriver *sd_;
-    CANDriver *canDriver;
-    uint8_t myID;
-    volatile uint8_t queryShellID;
-    volatile uint8_t replyShellID;
-
-    CANTxFrame txmsg;
-    uint8_t inputChar[16] = {};
-  };
-
-} /* amiro */
-
-#endif /* SERIAL_CAN_MUX_HPP_ */
-
-
diff --git a/include/amiro/util/rwlock.hpp b/include/amiro/util/rwlock.hpp
deleted file mode 100644
index a6263fe..0000000
--- a/include/amiro/util/rwlock.hpp
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef AMIRO_RWLOCK_H_
-#define AMIRO_RWLOCK_H_
-
-#include <ch.hpp>
-
-namespace amiro {
-
-/**
- * @brief An enhanced mutex with parallel read but exclusive write capabilities
- */
-class RWLock
-{
-public:
-  /**
-   * @brief An enum to specify the favoritism of the RWLock
-   */
-  enum Favor : bool {
-    FAVOR_READERS = false, /**< Favors readers, even if writers are waiting */
-    FAVOR_WRITERS = true,  /**< Favors writers and holds new readers back */
-  };
-
-  /**
-   * @brief An enum to specify what to wait for in the tryLockReading() and tryLockWriting() methods.
-   */
-  enum WaitingType : uint8_t {
-    WAIT_FOR_NONE = 0,  /**< does not block at all */
-    WAIT_FOR_MUTEX = 1, /**< blocks at the mutex */
-    WAIT_FOR_QUEUE = 2, /**< waits for the queues */
-  };
-
-private:
-  /**
-   * @brief A status struct holding the current configuration of the RWLock.
-   */
-  struct AccessStatus {
-    uint8_t reader_count : 7; /**< The number of currently active readers (128 max) */
-    uint8_t favor        : 1; /**< The currently selected favoritism */
-  };
-
-  chibios_rt::Mutex mutex;             /**< A mutex lock used for synchronization */
-  chibios_rt::CondVar waiting_readers; /**< A condition variable for waiting readers */
-  chibios_rt::CondVar waiting_writers; /**< A condition variable for all waiting writers */
-  AccessStatus status;                 /**< The current status of the RWLock */
-
-public:
-  /**
-   * @brief Constructor of the RWLock class.
-   * @param[in] favor The initial favoritism (default: FAVOR_WRITERS)
-   */
-  explicit RWLock(const Favor favor = FAVOR_WRITERS);
-
-  /**
-   * @brief Destructor of the RWLock class.
-   */
-  virtual ~RWLock();
-
-  /**
-   * @brief Lock the RWLock as a reader (shared mode)
-   */
-  void lockReading();
-
-  /**
-   * @brief Lock the RWLock as a writer (exclusive mode)
-   */
-  void lockWriting();
-
-  /**
-   * @brief Try to lock the RWLock as a reader (shared mode) but do not block
-   * @param[in] wait Can be used to wait for the mutex to lock or the queue to be empty
-   * @return True if the RWLock was successfully locked; False if not
-   */
-  bool tryLockReading(const WaitingType wait = WAIT_FOR_NONE);
-
-  /**
-   * @brief Try to lock the RWLock as a writer (exclusive mode) but do not block
-   * @param[in] wait Can be used to wait for the mutex to lock or the queue to be empty
-   * @return True if the RWLock was successfully locked; False if not
-   */
-  bool tryLockWriting(const WaitingType wait = WAIT_FOR_NONE);
-
-  /**
-   * @brief Unlocks the RWLock.
-   * If it was locked in shared or exclusive mode is detected automatically.
-   */
-  void unlock();
-
-  /**
-   * @brief Set the favoritism of the RWLock
-   * @param[in] favor Either FAVOR_READERS or FAVOR_WRITERS
-   */
-  void setFavoritism(const Favor favor);
-
-  /**
-   * @brief Try to set the favoritism of the RWLock but do not block
-   * @param[in] favor Either FAVOR_READERS or FAVOR_WRITERS
-   * @return True if the favoritism was successfully set; False if not
-   */
-  bool trySetFavoritism(const Favor favor);
-
-};
-
-} // end of namespace amiro
-
-#endif // AMIRO_RWLOCK_H_
-
diff --git a/include/amiro/util/stringstream.h b/include/amiro/util/stringstream.h
deleted file mode 100644
index 7b258f2..0000000
--- a/include/amiro/util/stringstream.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef STRINGSTREAM_H_
-#define STRINGSTREAM_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct BaseSequentialStreamVMT;
-
-struct stringstream_t {
-  const struct BaseSequentialStreamVMT *vmt;
-  uint8_t string[256];
-  uint8_t ins_ix;
-  uint8_t out_ix;
-};
-
-void StringStreamInit(void *instance);
-size_t StringStreamWrite(void *instance, const uint8_t *bp, size_t n);
-size_t StringStreamRead(void *instance, uint8_t *bp, size_t n);
-msg_t StringStreamPut(void *instance, uint8_t b);
-msg_t StringStreamGet(void *instance);
-size_t StringStreamTellp(void *instance);
-uint8_t *StringStreamStrGet(void *instance);
-void StringStreamStrSet(void *instance, const char *str);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* STRINGSTREAM_H_ */
diff --git a/include/amiro/util/util.h b/include/amiro/util/util.h
deleted file mode 100644
index e3070fe..0000000
--- a/include/amiro/util/util.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * util.h
- *
- *  Created on: Jun 18, 2014
- *      Author: Robert ABEL
- */
-
-#ifndef UTIL_H_
-#define UTIL_H_
-
-#define ARRAY_SIZE(_X_) (sizeof(_X_) / sizeof((_X_)[0]))
-
-#define MEMBER_SIZE(_TYPE_, _MEMBER_) sizeof(((_TYPE_ *)0)->_MEMBER_)
-
-#endif /* UTIL_H_ */
diff --git a/kernel/ChibiOS b/kernel/ChibiOS
new file mode 160000
index 0000000..1aec737
--- /dev/null
+++ b/kernel/ChibiOS
@@ -0,0 +1 @@
+Subproject commit 1aec7371a82e70d83d4aabd05445f5a9ac619b37
diff --git a/kernel/kernel.mk b/kernel/kernel.mk
new file mode 100644
index 0000000..0f51d4a
--- /dev/null
+++ b/kernel/kernel.mk
@@ -0,0 +1,3 @@
+# set kernel path variable
+AMIROOS_KERNEL = $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))/ChibiOS
+
diff --git a/kernel/kernelsetup.sh b/kernel/kernelsetup.sh
new file mode 100755
index 0000000..6bae538
--- /dev/null
+++ b/kernel/kernelsetup.sh
@@ -0,0 +1,813 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+################################################################################
+# GENERIC FUNCTIONS                                                            #
+################################################################################
+
+### print an error message #####################################################
+# Prints a error <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printError <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printError {
+  local string="ERROR:   $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a warning message ####################################################
+# Prints a warning <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printMessage <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printWarning {
+  local string="WARNING: $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)"
+}
+
+### print an information message ###############################################
+# Prints an information <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printInfo <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printInfo {
+  local string="INFO:    $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)"
+}
+
+### print a message to file ####################################################
+# Appends a <message> to a log file, specified by the variable 'LOG_FILE'.
+#
+# usage       printLog <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printLog {
+  local string="LOG:     $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+}
+
+### exit the script normally ###################################################
+# Prints a delimiter and exits the script normally (returns 0).
+#
+# usage:      quitScript
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
+  exit 0
+}
+
+### read a user input ##########################################################
+# Reads a single character user input from a set up <options> and stores it in
+# a given <return> variable.
+#
+# usage:      readUserInput <options> <return>
+# arguments:  <options>
+#                 String definiing the set of valid characters.
+#                 If the string is empty, the user can input any character.
+#             <return>
+#                 Variable to store the selected character to.
+# return:     n/a
+#
+function readUserInput {
+  local input=""
+  # read user input
+  while [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); do
+    read -p "your selection: " -n 1 -e input
+    if [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); then
+      printWarning "[$input] is no valid action\n"
+    fi
+  done
+  printLog "[$input] has been selected\n"
+  eval $2="$input"
+}
+
+### check whether argument is an option ########################################
+# Checks a <string> whether it is an option.
+# Options are defined to either start with '--' followed by any string, or
+# to start with a single '-' followed by a single character, or
+# to start with a single '-' followed by a single character, a '=' and any string.
+# Examples: '--option', '--option=arg', '-o', '-o=arg', '--'
+#
+# usage:      parseIsOption <string>
+# arguments:  <string>
+#                 A string to check whether it is an option.
+# return:     0
+#                 <string> is an option.
+#             -1
+#                 <string> is not an option.
+#
+function parseIsOption {
+  if [[ "$1" =~ ^-(.$|.=.*) ]] || [[ "$1" =~ ^--.* ]]; then
+    return 0
+  else
+    return -1
+  fi
+}
+
+### set the log file ###########################################################
+# Sets a specified <infile> as log file and checks whether it already exists.
+# If so, the log may either be appended to the file, its content can be cleared,
+# or no log is generated at all.
+# The resulting path is stored in <outvar>.
+#
+# usage:      setLogFile [--option=<option>] [--quiet] <infile> <outvar>
+# arguments:  --option=<option>
+#                 Select what to do if <file> already exists.
+#                 Possible values are 'a', 'c', 'r' and 'n'.
+#                 - a: append (starts with a separator)
+#                 - c: continue (does not insert a seperator)
+#                 - r: delete and restart
+#                 - n: no log
+#                 If no option is secified but <file> exists, an interactive selection is provided.
+#             --quiet
+#                 Suppress all messages.
+#             <infile>
+#                 Path of the wanted log file.
+#             <outvar>
+#                 Variable to store the path of the log file to.
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: invalid input
+#
+function setLogFile {
+  local filepath=""
+  local option=""
+  local quiet=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -o=*|--option=*)
+          option=${1#*=}; shift 1;;
+        -o*|--option*)
+          option="$2"; shift 2;;
+        -q|--quiet)
+          quiet=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+  filepath=$(realpath ${otherargs[0]})
+
+  # if file already exists
+  if [ -e $filepath ]; then
+    # if no option was specified, ask what to do
+    if [ -z "$option" ]; then
+      printWarning "log file $filepath already esists\n"
+      local userinput=""
+      printf "Select what to do:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput "AaRrNn" userinput
+      option=${userinput,,}
+    fi
+    # evaluate option
+    case "$option" in
+      a|c)
+        if [ $quiet = false ]; then
+          printInfo "appending log to $filepath\n"
+        fi
+        if [ $option != c ]; then
+          printf "\n" >> $filepath
+          printf "######################################################################\n" >> $filepath
+          printf "\n" >> $filepath
+        fi
+        ;;
+      r)
+        echo -n "" > $filepath
+        if [ $quiet = false ]; then
+          printInfo "content of $filepath wiped\n"
+        fi
+        ;;
+      n)
+        if [ $quiet = false ]; then
+          printInfo "no log file will be generated\n"
+        fi
+        filepath=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $option\n"; return -1;;
+    esac
+  else
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
+  fi
+
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
+}
+
+################################################################################
+# SPECIFIC FUNCTIONS                                                           #
+################################################################################
+
+### print welcome text #########################################################
+# Prints a welcome message to standard out.
+#
+# usage:      printWelcomeText
+# arguments:  n/a
+# return:     n/a
+#
+function printWelcomeText {
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "#              Welcome to the ChibiOS submodule setup!               #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+  printf "#                                                                    #\n"
+  printf "# This is free software; see the source for copying conditions.      #\n"
+  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+  printf "# Excellence Initiative.                                             #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+}
+
+### print help #################################################################
+# Prints a help text to standard out.
+#
+# usage:      printHelp
+# arguments:  n/a
+# return:     n/a
+#
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-i|--init] [-p|--patch] [-d|--documentation=<option>] [-w|--wipe] [-q|--quit] [--log=<file>]\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -i, --init\n"
+  printf "              Initialize ChibiOS submodule.\n"
+  printf "          -p, --patch,\n"
+  printf "              Apply patches to CHibiOS.\n"
+  printf "          -d, --documentation <option>\n"
+  printf "              Possible options are: 'g' and 'o' (can be combined).\n"
+  printf "              - g: Generate HTML documentation of ChibiOS.\n"
+  printf "              - o: Open HTML documentation of ChibiOS.\n"
+  printf "          -w, --wipe\n"
+  printf "              Wipe ChibiOS submodule.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### initialize ChibiOS submodule ###############################################
+# Initializes the ChibiOS Git submodule.
+#
+# usage:      initChibiOS
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Aborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function initChibiOS {
+  printInfo "initializing ChibiOS submodule...\n"
+  local userdir=$(pwd)
+  local kerneldir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local chibiosdir=${kerneldir}/ChibiOS
+
+  # if the kernel folder is not empty
+  if [ ! -z "$(ls -A $chibiosdir)" ]; then
+    printWarning "$chibiosdir is not empty. Delete and reinitialize? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        wipeChibiOS
+        ;;
+      N|n)
+        printWarning "ChibiOS initialization aborted by user\n"
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  fi
+
+  # initialize submodule to default branch
+  cd $kerneldir
+  git submodule update --init $chibiosdir 2>&1 | tee -a $LOG_FILE
+  while [ ${PIPESTATUS[0]} -ne 0 ]; do
+    printWarning "initialitaion failed. Retry? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        git submodule update --init $chibiosdir 2>&1 | tee -a $LOG_FILE;;
+      N|n)
+        printWarning "ChibiOS initialization aborted by user\n"
+        cd $userdir
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  done
+  cd $userdir
+
+  return 0
+}
+
+### patch ChibiOS ##############################################################
+# Applies patches to ChibiOS submodule.
+#
+# usage:      patchChibiOS
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: ChibiOS not initialized yet.
+#             2
+#                 Warning: Setup aborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function patchChibiOS {
+  printInfo "applying patches to ChibiOS\n"
+  local userdir=$(pwd)
+  local kerneldir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local chibiosdir=${kerneldir}/ChibiOS
+  local git_branch_patched="AMiRo-OS"
+
+  # if the ChibiOS folder is empty
+  if [ -z "$(ls -A $chibiosdir)" ]; then
+    printWarning "$chibiosdir is empty. Please initialize first.\n"
+    return 1
+  else 
+    # get some information from Git
+    cd $chibiosdir
+    local git_branch_current=$(git rev-parse --abbrev-ref HEAD)
+    local git_branches=$(git for-each-ref --format="%(refname)")
+    local git_dirtyfiles=($(git ls-files -dmo --exclude-standard --exclude=/doc))
+    cd $userdir
+
+    local issues=0
+    # if the current branch is already $git_branch_patched
+    if [ "$git_branch_current" = "$git_branch_patched" ]; then
+      issues=$((issues + 1))
+      printWarning "current branch is already $git_branch_patched\n"
+    fi
+    # if the current branch is bot $git_branch_patched, but another branch $git_branch_patched already exists
+    if [ "$git_branch_current" != "$git_branch_patched" ] && [[ "$git_branches" = *"$git_branch_patched"* ]]; then
+      issues=$((issues + 1))
+      printWarning "another branch $git_branch_patched already exists\n"
+    fi
+    # if there are untracked, modified, or deleted files
+    if [ ${#git_dirtyfiles[@]} != 0 ]; then
+      issues=$((issues + 1))
+      printWarning "there are ${#git_dirtyfiles[@]} untracked, modified, or deleted files\n"
+    fi
+    if [ $issues -gt 0 ]; then
+      local userinput=""
+      printWarning "$issues issues detected. Do you want to continue? [y/n]\n"
+      readUserInput "YyNn" userinput
+      case "$userinput" in
+        Y|y)
+          ;;
+        N|n)
+          printfWarning "ChibiOS patching aborted by user\n"
+          return 2
+          ;;
+        *) # sanity check (return error)
+          printError "unexpected input: $userinput\n"; return -1;;
+      esac
+    fi
+
+    # create a new branch and apply the patches
+    local patches=${kerneldir}/patches/*.patch
+    cd $chibiosdir
+    git checkout -b "$git_branch_patched" 2>&1 | tee -a $LOG_FILE
+    for patch in $patches; do
+      cp $patch .
+      patch=$(basename $patch)
+      git apply --whitespace=nowarn < $patch 2>&1 | tee -a $LOG_FILE
+      rm $patch
+#      # These lines are disabled for safety reasons:
+#      #   Filed commits are detected as valid changes by the super-project.
+#      #   This may lead to errorneous updates of the super-project, as to point to one of these commit hashes.
+#      #   Since these commits are not pushed upstream, initialization of the super-project will therefore fail, because
+#      #   the referenced hashed (after patching) do not exist in a clean copy of this sub-project.
+#      git add $(git ls-files -dmo --exclude-standard --exclude=/doc) $(git diff --name-only) 2>&1 | tee -a $LOG_FILE
+#      git commit --message="$patch applied" 2>&1 | tee -a $LOG_FILE
+    done
+    cd $userdir
+
+    return 0
+  fi
+}
+
+### ChibiOS dcoumentation setup ################################################
+#
+# usage:      documentation [<option>]
+# arguments:  <option>
+#                 Can be either 'g' or 'o' to generate or open HTML documentation respectively.
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Kernel not nitialized yet.
+#             2
+#                 Warning: Setup aborted by user.
+#             3
+#                 Warning: Issues occurred.
+#             -1
+#                 Error: Unexpected user input.
+#
+function documentation {
+  local userdir=$(pwd)
+  local kerneldir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local chibiosdir=${kerneldir}/ChibiOS
+
+  # if the ChibiOS folder is empty
+  if [ -z "$(ls -A $chibiosdir)" ]; then
+    printWarning "$chibiosdir is empty. Please initialize first.\n"
+    return 1
+  else
+    local option="";
+    # if no argument was specified, ask what to do
+    if [ $# -eq 0 ]; then
+      printInfo "ChibiOS documentation setup\n"
+      printf "Please select one of the following actions:\n"
+      printf "  [G] - generate HTML documentation\n"
+      printf "  [O] - open HTML documentation\n"
+      printf "  [A] - abort this setup\n"
+      local userinput
+      readUserInput "GgOoAa" userinput
+      option=${userinput,,}
+      if [ $option = "a" ]; then
+        printInfo "ChibiOS documentation setup aborted by user\n"
+        return 2
+      fi
+    else
+      option="$1"
+    fi
+
+    local issues=0
+    case "$option" in
+      # generate HTML documentation
+      g)
+        # ChibiOS/HAL: check if required files exis
+        if [ -f ${chibiosdir}/doc/hal/makehtml.sh ]; then
+          printInfo "generating ChibiOS/HAL documentation...\n"
+          cd ${chibiosdir}/doc/hal
+          ${chibiosdir}/doc/hal/makehtml.sh 2>&1 | tee -a $LOG_FILE
+          cd $userdir
+          printInfo "access ChibiOS/HAL documentation via ${chibiosdir}doc/hal/html/index.html\n"
+        else
+          issues=$((issues + 1))
+          printError "could not generate ChibiOS/HAL documentation\n"
+        fi
+        # ChibiOS/RT: check if required files exis
+        if [ -f ${chibiosdir}/doc/rt/makehtml.sh ]; then
+          printInfo "generating ChibiOS/RT documentation...\n"
+          cd ${chibiosdir}/doc/rt
+          ${chibiosdir}/doc/rt/makehtml.sh 2>&1 | tee -a $LOG_FILE
+          cd $userdir
+          printInfo "access ChibiOS/RT documentation via ${chibiosdir}doc/rt/html/index.html\n"
+        else
+          issues=$((issues + 1))
+          printError "could not generate ChibiOS/RT documentation\n"
+        fi
+        # ChibiOS/NIL: check if required files exis
+        if [ -f ${chibiosdir}/doc/nil/makehtml.sh ]; then
+          printInfo "generating ChibiOS/NIL documentation...\n"
+          cd ${chibiosdir}/doc/nil
+          ${chibiosdir}/doc/nil/makehtml.sh 2>&1 | tee -a $LOG_FILE
+          cd $userdir
+          printInfo "access ChibiOS/NIL documentation via ${chibiosdir}edoc/nil/html/index.html\n"
+        else
+          issues=$((issues + 1))
+          printError "could not generate ChibiOS/NIL documentation\n"
+        fi
+        ;;
+
+      # open HTML documentation
+      o)
+        # ChibiOS/HAL: check if required files exis
+        if [ -f ${chibiosdir}/doc/hal/html/index.html ]; then
+          printInfo "open ChibiOS/HAL documentation\n"
+          xdg-open ${chibiosdir}/doc/hal/html/index.html &> /dev/null &
+        else
+          issues=$((issues + 1))
+          printError "could not open ChibiOS/HAL documentation\n"
+        fi
+        # ChibiOS/RT: check if required files exis
+        if [ -f ${chibiosdir}/doc/rt/html/index.html ]; then
+          printInfo "open ChibiOS/RT documentation\n"
+          xdg-open ${chibiosdir}/doc/rt/html/index.html &> /dev/null &
+        else
+          issues=$((issues + 1))
+          printError "could not open ChibiOS/RT documentation\n"
+        fi
+        # ChibiOS/NIL: check if required files exis
+        if [ -f ${chibiosdir}/doc/nil/html/index.html ]; then
+          printInfo "open ChibiOS/NIL documentation\n"
+          xdg-open ${chibiosdir}/doc/nil/html/index.html &> /dev/null &
+        else
+          issues=$((issues + 1))
+          printError "could not open ChibiOS/NIL documentation\n"
+        fi
+        ;;
+
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+
+    if [ $issues -gt 0 ]; then
+      return 3
+    else
+      return 0
+    fi
+  fi
+}
+
+### reset ChibiOS submodule and wipe directory #################################
+# Resets the ChibiOS Git submodule and wipes the directory.
+#
+# usage:      wipeChibiOS
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Submodule directory is already empty.
+#             2
+#                 Warning: Wiping aborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function wipeChibiOS {
+  printInfo "reset and wipe Git submodule $kerneldir\n"
+  local userdir=$(pwd)
+  local kerneldir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local chibiosdir=${kerneldir}/ChibiOS
+  local git_branch_patched="AMiRo-OS"
+
+  # if the ChibiOS folder is empty
+  if [ -z "$(ls -A $chibiosdir)" ]; then
+    printInfo "$chibiosdir is alread empty\n"
+    return 1
+  else 
+    # get some information from Git
+    cd $kerneldir
+    local git_basehash=($(git ls-tree -d HEAD $kerneldir)); git_basehash=${git_basehash[2]}
+    cd $chibiosdir
+    local git_branch_current=$(git rev-parse --abbrev-ref HEAD)
+    local git_difftobase="$(git diff ${git_basehash}..HEAD)"
+    local git_commits=$(git log --format=oneline ${git_basehash}..HEAD)
+    local git_dirtyfiles=($(git ls-files -dmo --exclude-standard --exclude=/doc))
+    cd $userdir
+    local issues=0
+    # if the HEAD is neither detached, nor is the current branch $git_branch_patched
+    if [ "$git_branch_current" != "HEAD" ] && [ "$git_branch_current" != "$git_branch_patched" ]; then
+      issues=$((issues + 1))
+      printWarning "modifications to ChibiOS Git submodule detected\n"
+    fi
+    # if HEAD is ahead of submodule base commit but with more than just applied patches
+    if [ -n "$git_difftobase" ] && [ -n "$(echo $git_commits | grep -Ev '\.patch applied$')" ]; then
+      issues=$((issues + 1))
+      printWarning "HEAD is ahead of submodule base by unexpected commits\n"
+    fi
+    # if there are untracked, modified, or deleted files
+    if [ ${#git_dirtyfiles[@]} != 0 ]; then
+      issues=$((issues + 1))
+      printWarning "there are ${#git_dirtyfiles[@]} untracked, modified, or deleted files\n"
+    fi
+    if [ $issues -gt 0 ]; then
+      local userinput=""
+      printWarning "$issues issues detected. Do you want to continue? [y/n]\n"
+      readUserInput "YyNn" userinput
+      case "$userinput" in
+        Y|y)
+          ;;
+        N|n)
+          printfWarning "wiping ChibiOS Git submodule aborted by user\n"
+          return 2
+          ;;
+        *) # sanity check (return error)
+          printError "unexpected input: $userinput\n"; return -1;;
+      esac
+    fi
+
+    # checkout base commit and delete all local branches
+    cd $kerneldir
+    git submodule update --force --checkout $kerneldir | tee -a $LOG_FILE
+    cd $chibiosdir
+    local git_branches=($(git for-each-ref --format="%(refname)"))
+    for branch in $git_branches; do
+      if [[ $branch = *"heads/"* ]]; then
+        git branch -D ${branch##*/} | tee -a $LOG_FILE
+      fi
+    done
+    cd $userdir
+
+    # deinitialize ChibiOS submodule and delete any remaining files
+    cd $kerneldir
+    git submodule deinit -f $chibiosdir 2>&1 | tee -a $LOG_FILE
+    rm -rf $chibiosdir/*
+    cd $userdir
+
+    return 0
+  fi
+}
+
+### main function of this script ###############################################
+# The kernel setup provides comfortable initialization, patching, documentation
+# generation and cleanup for ChibiOS.
+#
+# usage:      see function printHelp
+# arguments:  see function printHelp
+# return:     0
+#                 No error or warning occurred.
+#
+function main {
+  # print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  printf "\n"
+
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
+
+  # set log file if specified
+  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
+    # get the parameter (file name)
+    local cmdidx=1
+    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
+      cmdidx=$[cmdidx + 1]
+    done
+    local cmd="${!cmdidx}"
+    local logfile=""
+    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
+      logfile=${cmd#*=}
+    else
+      local filenameidx=$((cmdidx + 1))
+      logfile="${!filenameidx}"
+    fi
+    # optionally force silent appending
+    if [[ "$cmd" = "--LOG"* ]]; then
+      setLogFile --option=c --quiet "$logfile" LOG_FILE
+    else
+      setLogFile "$logfile" LOG_FILE
+      printf "\n"
+    fi
+  fi
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -i|--init)
+           initChibiOS; printf "\n"; shift 1;;
+        -p|--patch)
+           patchChibiOS; printf "\n"; shift 1;;
+        -d=*|--documentation=*)
+           documentation "${1#*=}"; printf "\n"; shift 1;;
+        -d|--documentation)
+           if ( ! parseIsOption $2 ); then
+             documentation "$2"; printf "\n"; shift 2
+           else
+             documentation; printf "\n"; shift 1
+           fi;;
+        -w|--wipe)
+          wipeChibiOS; printf "\n"; shift 1;;
+        -q|--quit)
+          quitScript; shift 1;;
+        --log=*|--LOG=*) # already handled; ignore
+          shift 1;;
+        --log|--LOG) # already handled; ignore
+          shift 2;;
+        --noinfo) # already handled; ignore
+          shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "ChibiOS kernel setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [I] - initialize ChibiOS submodule\n"
+    printf "  [P] - apply patches to ChibiOS\n"
+    printf "  [D] - generate or open HTML documentation\n"
+    printf "  [W] - wipe ChibiOS submodule\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "IiPpDdWwQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      I|i)
+        initChibiOS; printf "\n";;
+      P|p)
+        patchChibiOS; printf "\n";;
+      D|d)
+        documentation; printf "\n";;
+      W|w)
+        wipeChibiOS; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
diff --git a/kernel/patches/BaseStaticThread-diamond-problem-fix.patch b/kernel/patches/BaseStaticThread-diamond-problem-fix.patch
new file mode 100644
index 0000000..86f6030
--- /dev/null
+++ b/kernel/patches/BaseStaticThread-diamond-problem-fix.patch
@@ -0,0 +1,25 @@
+From 94da217d87dd5994e8ac096a121241dafd7b41e6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20Sch=C3=B6pping?= <tschoepp@cit-ec.uni-bielefeld.de>
+Date: Tue, 13 Jun 2017 11:04:04 +0200
+Subject: [PATCH] BaseStaticThread diamond problem fix
+
+---
+ os/various/cpp_wrappers/ch.hpp | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/os/various/cpp_wrappers/ch.hpp b/os/various/cpp_wrappers/ch.hpp
+index ec86566..4eb7b2e 100644
+--- a/os/various/cpp_wrappers/ch.hpp
++++ b/os/various/cpp_wrappers/ch.hpp
+@@ -877,7 +877,7 @@ namespace chibios_rt {
+    * @param N               the working area size for the thread class
+    */
+   template <int N>
+-  class BaseStaticThread : public BaseThread {
++  class BaseStaticThread : public virtual BaseThread {
+   protected:
+     THD_WORKING_AREA(wa, N);
+ 
+-- 
+2.7.4
+
diff --git a/kernel/patches/Introduced-I2C-without-DMA.patch b/kernel/patches/Introduced-I2C-without-DMA.patch
new file mode 100644
index 0000000..d50e930
--- /dev/null
+++ b/kernel/patches/Introduced-I2C-without-DMA.patch
@@ -0,0 +1,479 @@
+From 736d3be25b7389b6130e0c372328aa56e2532250 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20Sch=C3=B6pping?= <tschoepp@cit-ec.uni-bielefeld.de>
+Date: Mon, 12 Jun 2017 17:28:49 +0200
+Subject: [PATCH] Introduced I2C without DMA (I2Cv1 only).
+
+---
+ os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c | 181 ++++++++++++++++++++++++++++-
+ os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h |  30 +++++
+ 2 files changed, 210 insertions(+), 1 deletion(-)
+
+diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
+index 20b8cf8..b2cfb59 100644
+--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
++++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
+@@ -34,6 +34,7 @@
+ /* Driver local definitions.                                                 */
+ /*===========================================================================*/
+ 
++#if STM32_I2C_USE_DMA
+ #define I2C1_RX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM,                        \
+                        STM32_I2C1_RX_DMA_CHN)
+@@ -57,6 +58,7 @@
+ #define I2C3_TX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM,                        \
+                        STM32_I2C3_TX_DMA_CHN)
++#endif /* STM32_I2C_USE_DMA */
+ 
+ /*===========================================================================*/
+ /* Driver constants.                                                         */
+@@ -72,6 +74,20 @@
+ #define I2C_EV6_MASTER_REC_MODE_SELECTED                                    \
+   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
+ 
++#define I2C_EV7_MASTER_REC_BYTE_RECEIVED                                    \
++  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_RXNE))
++
++#define I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP                               \
++  ((uint32_t)(                                      I2C_SR1_RXNE))
++
++#define I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED                              \
++  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) |                         \
++              I2C_SR1_BTF | I2C_SR1_RXNE))
++
++#define I2C_EV8_MASTER_BYTE_TRANSMITTING                                    \
++  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA)<< 16) |           \
++              I2C_SR1_TXE))
++
+ #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED                                   \
+   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) |          \
+               I2C_SR1_BTF | I2C_SR1_TXE))
+@@ -128,9 +144,11 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
+   dp->CR2 = 0;
+   dp->SR1 = 0;
+ 
++#if STM32_I2C_USE_DMA
+   /* Stops the associated DMA streams.*/
+   dmaStreamDisable(i2cp->dmatx);
+   dmaStreamDisable(i2cp->dmarx);
++#endif /* STM32_I2C_USE_DMA */
+ }
+ 
+ /**
+@@ -247,12 +265,13 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
+   uint32_t regSR2 = dp->SR2;
+   uint32_t event = dp->SR1;
+ 
++#if STM32_I2C_USE_DMA
+   /* Interrupts are disabled just before dmaStreamEnable() because there
+      is no need of interrupts until next transaction begin. All the work is
+      done by the DMA.*/
+   switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
+   case I2C_EV5_MASTER_MODE_SELECT:
+-    if ((i2cp->addr >> 8) > 0) { 
++    if ((i2cp->addr >> 8) > 0) {
+       /* 10-bit address: 1 1 1 1 0 X X R/W */
+       dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
+     } else {
+@@ -292,8 +311,125 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
+   /* Clear ADDR flag. */
+   if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
+     (void)dp->SR2;
++#else
++  switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
++  case I2C_EV5_MASTER_MODE_SELECT:
++    dp->CR2 |= I2C_CR2_ITBUFEN;
++    dp->DR = i2cp->addr;
++    break;
++  case I2C_EV6_MASTER_TRA_MODE_SELECTED:
++    (void)dp->SR2; // clear ADDR flag
++    /* EV8_1 */
++    dp->DR = *(i2cp->txbuf);
++
++    ++i2cp->txbuf;
++    --i2cp->txbytes;
++
++    /* if N == 1, skip the I2C_EV8_MASTER_BYTE_TRANSMITTING event
++     * but enter I2C_EV8_2_MASTER_BYTE_TRANSMITTED next */
++    if (i2cp->txbytes == 0) {
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++    }
++    break;
++  case I2C_EV6_MASTER_REC_MODE_SELECTED:
++    switch (i2cp->rxbytes) {
++    case 1:
++      dp->CR1 &= ~I2C_CR1_ACK;
++      (void)dp->SR2; // clear ADDR flag
++      dp->CR1 |= I2C_CR1_STOP;
++      break;
++    case 2:
++      (void)dp->SR2; // clear ADDR flag
++      /* EV6_1 */
++      dp->CR1 |= I2C_CR1_POS;
++      dp->CR1 &= ~I2C_CR1_ACK;
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++      break;
++    case 3: /* N == 3 is a very special case, since EV7 is completely skipped */
++      (void)dp->SR2; // clear ADDR flag
++      /* Disable the I2C_EV7_MASTER_REC_BYTE_RECEIVED event
++       * but enter I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP next */
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++      break;
++    default: /* N > 2 */
++      (void)dp->SR2; // clear ADDR flag
++      break;
++    }
++    break;
++  case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
++    if (i2cp->rxbytes > 3) {
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      --i2cp->rxbytes;
++    }
++    if (i2cp->rxbytes == 3) {
++      /* Disable this event for DataN-2, but force into event
++       * I2C_EV7_2_EV7_3_MASTER_REC_BYTE_RECEIVED_QUEUED by not reading dp->DR. */
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++    }
++    break;
++  case I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP:
++    osalDbgAssert(i2cp->rxbytes == 1, "more than 1 byte to be received");
++    *(i2cp->rxbuf) = dp->DR;
++    --i2cp->rxbytes;
++    dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
++    _i2c_wakeup_isr(i2cp);
++    break;
++  case I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED:
++    if (i2cp->rxbytes == 3) {
++      /* EV7_2 (N > 2) */
++      dp->CR1 &= ~I2C_CR1_ACK;
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      dp->CR1 |= I2C_CR1_STOP;
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      i2cp->rxbytes -= 2;
++      /* enable I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP event */
++      dp->CR2 |= I2C_CR2_ITBUFEN;
++    } else {
++      /* EV7_3 (N == 2) */
++      dp->CR1 |= I2C_CR1_STOP;
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      *(i2cp->rxbuf) = dp->DR;
++      i2cp->rxbytes -= 2;
++
++      dp->CR1 &= ~I2C_CR1_POS;
++      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
++
++      _i2c_wakeup_isr(i2cp);
++    }
++    break;
++  case I2C_EV8_MASTER_BYTE_TRANSMITTING:
++    dp->DR = *(i2cp->txbuf);
++    ++i2cp->txbuf;
++    --i2cp->txbytes;
++
++    /* if this was the last byte, ensure that this event is not entered again */
++    if (i2cp->txbytes == 0) {
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++    }
++    break;
++  case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
++    if (i2cp->rxbytes > 0) {
++      /* start "read after write" operation (LSB of address = 1 => read) */
++      i2cp->addr |= 0x01;
++      dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
++    } else {
++      dp->CR1 |= I2C_CR1_STOP;
++      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
++      _i2c_wakeup_isr(i2cp);
++    }
++    break;
++  default:
++    osalDbgAssert(i2cp->rxbytes != 1, "more than 1 byte to be received");
++    break;
++  }
++#endif /* STM32_I2C_USE_DMA */
+ }
+ 
++#if STM32_I2C_USE_DMA
+ /**
+  * @brief   DMA RX end IRQ handler.
+  *
+@@ -347,6 +483,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+      of R/W transaction itself.*/
+   dp->CR2 |= I2C_CR2_ITEVTEN;
+ }
++#endif /* STM32_I2C_USE_DMA */
+ 
+ /**
+  * @brief   I2C error handler.
+@@ -358,9 +495,11 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+  */
+ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
+ 
++#if STM32_I2C_USE_DMA
+   /* Clears interrupt flags just to be safe.*/
+   dmaStreamDisable(i2cp->dmatx);
+   dmaStreamDisable(i2cp->dmarx);
++#endif /* STM32_I2C_USE_DMA */
+ 
+   i2cp->errors = I2C_NO_ERROR;
+ 
+@@ -506,24 +645,30 @@ void i2c_lld_init(void) {
+   i2cObjectInit(&I2CD1);
+   I2CD1.thread = NULL;
+   I2CD1.i2c    = I2C1;
++#if STM32_I2C_USE_DMA
+   I2CD1.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM);
+   I2CD1.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM);
++#endif /* STM32_I2C_USE_DMA */
+ #endif /* STM32_I2C_USE_I2C1 */
+ 
+ #if STM32_I2C_USE_I2C2
+   i2cObjectInit(&I2CD2);
+   I2CD2.thread = NULL;
+   I2CD2.i2c    = I2C2;
++#if STM32_I2C_USE_DMA
+   I2CD2.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM);
+   I2CD2.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM);
++#endif /* STM32_I2C_USE_DMA */
+ #endif /* STM32_I2C_USE_I2C2 */
+ 
+ #if STM32_I2C_USE_I2C3
+   i2cObjectInit(&I2CD3);
+   I2CD3.thread = NULL;
+   I2CD3.i2c    = I2C3;
++#if STM32_I2C_USE_DMA
+   I2CD3.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM);
+   I2CD3.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM);
++#endif /* STM32_I2C_USE_DMA */
+ #endif /* STM32_I2C_USE_I2C3 */
+ }
+ 
+@@ -540,6 +685,7 @@ void i2c_lld_start(I2CDriver *i2cp) {
+   /* If in stopped state then enables the I2C and DMA clocks.*/
+   if (i2cp->state == I2C_STOP) {
+ 
++#if STM32_I2C_USE_DMA
+     i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
+                       STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
+                       STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
+@@ -548,9 +694,11 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                       STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
+                       STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
+                       STM32_DMA_CR_DIR_P2M;
++#endif /* STM32_I2C_USE_DMA */
+ 
+ #if STM32_I2C_USE_I2C1
+     if (&I2CD1 == i2cp) {
++#if STM32_I2C_USE_DMA
+       bool b;
+ 
+       rccResetI2C1();
+@@ -564,19 +712,23 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+                             (void *)i2cp);
+       osalDbgAssert(!b, "stream already allocated");
++#endif /* STM32_I2C_USE_DMA */
+       rccEnableI2C1(FALSE);
+       nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
+       nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
+ 
++#if STM32_I2C_USE_DMA
+       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
++#endif /* STM32_I2C_USE_DMA */
+     }
+ #endif /* STM32_I2C_USE_I2C1 */
+ 
+ #if STM32_I2C_USE_I2C2
+     if (&I2CD2 == i2cp) {
++#if STM32_I2C_USE_DMA
+       bool b;
+ 
+       rccResetI2C2();
+@@ -590,19 +742,23 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+                             (void *)i2cp);
+       osalDbgAssert(!b, "stream already allocated");
++#endif /* STM32_I2C_USE_DMA */
+       rccEnableI2C2(FALSE);
+       nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
+       nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
+ 
++#if STM32_I2C_USE_DMA
+       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
++#endif /* STM32_I2C_USE_DMA */
+     }
+ #endif /* STM32_I2C_USE_I2C2 */
+ 
+ #if STM32_I2C_USE_I2C3
+     if (&I2CD3 == i2cp) {
++#if STM32_I2C_USE_DMA
+       bool b;
+ 
+       rccResetI2C3();
+@@ -616,26 +772,35 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+                             (void *)i2cp);
+       osalDbgAssert(!b, "stream already allocated");
++#endif /* STM32_I2C_USE_DMA */
+       rccEnableI2C3(FALSE);
+       nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
+       nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
+ 
++#if STM32_I2C_USE_DMA
+       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
++#endif /* STM32_I2C_USE_DMA */
+     }
+ #endif /* STM32_I2C_USE_I2C3 */
+   }
+ 
++#if STM32_I2C_USE_DMA
+   /* I2C registers pointed by the DMA.*/
+   dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
+   dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
++#endif /* STM32_I2C_USE_DMA */
+ 
+   /* Reset i2c peripheral.*/
+   dp->CR1 = I2C_CR1_SWRST;
+   dp->CR1 = 0;
++#if STM32_I2C_USE_DMA
+   dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
++#else
++  dp->CR2 = I2C_CR2_ITERREN;
++#endif /* STM32_I2C_USE_DMA */
+ 
+   /* Setup I2C parameters.*/
+   i2c_lld_set_clock(i2cp);
+@@ -659,8 +824,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
+ 
+     /* I2C disable.*/
+     i2c_lld_abort_operation(i2cp);
++#if STM32_I2C_USE_DMA
+     dmaStreamRelease(i2cp->dmatx);
+     dmaStreamRelease(i2cp->dmarx);
++#endif /* STM32_I2C_USE_DMA */
+ 
+ #if STM32_I2C_USE_I2C1
+     if (&I2CD1 == i2cp) {
+@@ -730,10 +897,15 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+   /* Releases the lock from high level driver.*/
+   osalSysUnlock();
+ 
++#if STM32_I2C_USE_DMA
+   /* RX DMA setup.*/
+   dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+   dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+   dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++  i2cp->rxbuf = rxbuf;
++  i2cp->rxbytes = rxbytes;
++#endif /* STM32_I2C_USE_DMA */
+ 
+   /* Calculating the time window for the timeout on the busy bus condition.*/
+   start = osalOsGetSystemTimeX();
+@@ -810,6 +982,7 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+   /* Releases the lock from high level driver.*/
+   osalSysUnlock();
+ 
++#if STM32_I2C_USE_DMA
+   /* TX DMA setup.*/
+   dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
+   dmaStreamSetMemory0(i2cp->dmatx, txbuf);
+@@ -819,6 +992,12 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+   dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+   dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+   dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++  i2cp->txbuf = txbuf;
++  i2cp->txbytes = txbytes;
++  i2cp->rxbuf = rxbuf;
++  i2cp->rxbytes = rxbytes;
++#endif /* STM32_I2C_USE_DMA */
+ 
+   /* Calculating the time window for the timeout on the busy bus condition.*/
+   start = osalOsGetSystemTimeX();
+diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
+index a812ceb..127c708 100644
+--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
++++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
+@@ -76,6 +76,15 @@
+ #endif
+ 
+ /**
++ * @brief   I2C data transfer use dma switch.
++ * @details If set to @p TRUE the support for I2C DMA is included.
++ * @note    The default is @p FALSE.
++ */
++#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__)
++#define STM32_I2C_USE_DMA                   TRUE
++#endif
++
++/**
+  * @brief   I2C timeout on busy condition in milliseconds.
+  */
+ #if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
+@@ -249,6 +258,7 @@
+ #error "Invalid IRQ priority assigned to I2C3"
+ #endif
+ 
++#if STM32_I2C_USE_DMA
+ #if STM32_I2C_USE_I2C1 &&                                                   \
+     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
+ #error "Invalid DMA priority assigned to I2C1"
+@@ -319,6 +329,7 @@
+ #if !defined(STM32_DMA_REQUIRED)
+ #define STM32_DMA_REQUIRED
+ #endif
++#endif /* STM32_I2C_USE_DMA */
+ 
+ /* Check clock range. */
+ #if defined(STM32F4XX)
+@@ -436,6 +447,7 @@ struct I2CDriver {
+    * @brief     Current slave address without R/W bit.
+    */
+   i2caddr_t                 addr;
++#if STM32_I2C_USE_DMA
+   /**
+    * @brief RX DMA mode bit mask.
+    */
+@@ -452,6 +464,24 @@ struct I2CDriver {
+    * @brief     Transmit DMA channel.
+    */
+   const stm32_dma_stream_t  *dmatx;
++#else
++  /**
++   * @brief     Receive buffer.
++   */
++  uint8_t                   *rxbuf;
++  /**
++   * @brief     Receive buffer size.
++   */
++  size_t                    rxbytes;
++  /**
++   * @brief     Transmit buffer.
++   */
++  const uint8_t             *txbuf;
++  /**
++   * @brief     Transmit buffer size.
++   */
++  size_t                    txbytes;
++#endif /* STM32_I2C_USE_DMA */
+   /**
+    * @brief     Pointer to the I2Cx registers block.
+    */
+-- 
+2.7.4
+
diff --git a/kernel/patches/Introduced-support-for-the-ADC-analog-watchdog.patch b/kernel/patches/Introduced-support-for-the-ADC-analog-watchdog.patch
new file mode 100644
index 0000000..e048860
--- /dev/null
+++ b/kernel/patches/Introduced-support-for-the-ADC-analog-watchdog.patch
@@ -0,0 +1,111 @@
+From d5e13e540dec58ece6de3d246a166185418f3fd3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20Sch=C3=B6pping?= <tschoepp@cit-ec.uni-bielefeld.de>
+Date: Mon, 12 Jun 2017 17:27:13 +0200
+Subject: [PATCH] Introduced support for the ADC analog watchdog (ADCv2 only).
+
+---
+ os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c | 20 +++++++++++++++++---
+ os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h | 21 ++++++++++++++++++++-
+ 2 files changed, 37 insertions(+), 4 deletions(-)
+
+diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c
+index b2e651e..d5875ee 100644
+--- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c
++++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.c
+@@ -124,7 +124,11 @@ OSAL_IRQ_HANDLER(STM32_ADC_HANDLER) {
+     if (ADCD1.grpp != NULL)
+       _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW);
+   }
+-  /* TODO: Add here analog watchdog handling.*/
++  if (sr & ADC_SR_AWD) {
++    if (ADCD1.grpp != NULL) {
++      _adc_isr_error_code(&ADCD1, ADC_ERR_WATCHDOG);
++    }
++  }
+ #if defined(STM32_ADC_ADC1_IRQ_HOOK)
+   STM32_ADC_ADC1_IRQ_HOOK
+ #endif
+@@ -141,7 +145,11 @@ OSAL_IRQ_HANDLER(STM32_ADC_HANDLER) {
+     if (ADCD2.grpp != NULL)
+       _adc_isr_error_code(&ADCD2, ADC_ERR_OVERFLOW);
+   }
+-  /* TODO: Add here analog watchdog handling.*/
++  if (sr & ADC_SR_AWD) {
++    if (ADCD2.grpp != NULL) {
++      _adc_isr_error_code(&ADCD2, ADC_ERR_WATCHDOG);
++    }
++  }
+ #if defined(STM32_ADC_ADC2_IRQ_HOOK)
+   STM32_ADC_ADC2_IRQ_HOOK
+ #endif
+@@ -158,7 +166,11 @@ OSAL_IRQ_HANDLER(STM32_ADC_HANDLER) {
+     if (ADCD3.grpp != NULL)
+       _adc_isr_error_code(&ADCD3, ADC_ERR_OVERFLOW);
+   }
+-  /* TODO: Add here analog watchdog handling.*/
++  if (sr & ADC_SR_AWD) {
++    if (ADCD3.grpp != NULL) {
++      _adc_isr_error_code(&ADCD3, ADC_ERR_WATCHDOG);
++    }
++  }
+ #if defined(STM32_ADC_ADC3_IRQ_HOOK)
+   STM32_ADC_ADC3_IRQ_HOOK
+ #endif
+@@ -350,6 +362,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
+   adcp->adc->SR    = 0;
+   adcp->adc->SMPR1 = grpp->smpr1;
+   adcp->adc->SMPR2 = grpp->smpr2;
++  adcp->adc->HTR   = grpp->htr;
++  adcp->adc->LTR   = grpp->ltr;
+   adcp->adc->SQR1  = grpp->sqr1 | ADC_SQR1_NUM_CH(grpp->num_channels);
+   adcp->adc->SQR2  = grpp->sqr2;
+   adcp->adc->SQR3  = grpp->sqr3;
+diff --git a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h
+index 13df506..fa266f0 100644
+--- a/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h
++++ b/os/hal/ports/STM32/LLD/ADCv2/hal_adc_lld.h
+@@ -313,7 +313,8 @@ typedef uint16_t adc_channels_num_t;
+  */
+ typedef enum {
+   ADC_ERR_DMAFAILURE = 0,                   /**< DMA operations failure.    */
+-  ADC_ERR_OVERFLOW = 1                      /**< ADC overflow condition.    */
++  ADC_ERR_OVERFLOW = 1,                     /**< ADC overflow condition.    */
++  ADC_ERR_WATCHDOG = 2                      /**< ADC watchdog condition.    */
+ } adcerror_t;
+ 
+ /**
+@@ -392,6 +393,16 @@ typedef struct {
+    */
+   uint32_t                  smpr2;
+   /**
++   * @brief   ADC watchdog high threshold register.
++   * @details This field defines the high threshold of the analog watchdog.
++   */
++  uint16_t                  htr;
++  /**
++   * @brief   ADC watchdog low threshold register.
++   * @details This field defines the low threshold of the analog watchdog.
++   */
++  uint16_t                  ltr;
++  /**
+    * @brief   ADC SQR1 register initialization data.
+    * @details Conversion group sequence 13...16 + sequence length.
+    */
+@@ -531,6 +542,14 @@ struct ADCDriver {
+ #define ADC_SMPR1_SMP_VBAT(n)   ((n) << 24) /**< @brief VBAT sampling time. */
+ /** @} */
+ 
++/**
++ * @name    Threshold settings helper macros
++ * @{
++ */
++#define ADC_HTR(n)              ((n > ADC_HTR_HT) ? ADC_HTR_HT : n) /**< @brief High threshold limitation.  */
++#define ADC_LTR(n)              ((n > ADC_LTR_LT) ? ADC_LTR_LT : n) /**< @brief Low threshold limitation.   */
++/** @} */
++
+ /*===========================================================================*/
+ /* External declarations.                                                    */
+ /*===========================================================================*/
+-- 
+2.7.4
+
diff --git a/os/amiroos.h b/os/amiroos.h
new file mode 100644
index 0000000..dfdcb46
--- /dev/null
+++ b/os/amiroos.h
@@ -0,0 +1,79 @@
+/*
+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
+
+/** @} */
+
+/* core headers */
+#include <aosconf.h>
+#include <module.h>
+
+#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"
+#include "core/inc/aos_debug.h"
+#include "core/inc/aos_shell.h"
+#include "core/inc/aos_ssm.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
new file mode 100644
index 0000000..1556cac
--- /dev/null
+++ b/os/core/core.mk
@@ -0,0 +1,41 @@
+################################################################################
+# 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 $(abspath $(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_shell.c \
+                  $(AMIROOS_CORE_DIR)src/aos_ssm.c \
+                  $(AMIROOS_CORE_DIR)src/aos_system.c \
+                  $(AMIROOS_CORE_DIR)src/aos_thread.c \
+                  $(AMIROOS_CORE_DIR)src/aos_timer.c \
+                  $(AMIROOS_CORE_DIR)src/aos_unittest.c\
+                  $(AMIROOS_CORE_DIR)src/main.c
+
diff --git a/os/core/inc/aos_confcheck.h b/os/core/inc/aos_confcheck.h
new file mode 100644
index 0000000..ff383e1
--- /dev/null
+++ b/os/core/inc/aos_confcheck.h
@@ -0,0 +1,72 @@
+/*
+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_CONFCHECK_H_
+#define _AMIROOS_CONFCHECK_H_
+
+#include <aosconf.h>
+
+/*
+ * Kernel parameters and options
+ */
+
+#ifndef AMIROOS_CFG_SSSP_MASTER
+  #error "AMIROOS_CFG_SSSP_MASTER not defined in aosconf.h"
+#endif
+
+#ifndef AMIROOS_CFG_SSSP_SYSSYNCPERIOD
+  #error "AMIROOS_CFG_SSSP_SYSSYNCPERIOD 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
+
+/*
+ * 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_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
new file mode 100644
index 0000000..58a853b
--- /dev/null
+++ b/os/core/inc/aos_debug.h
@@ -0,0 +1,82 @@
+/*
+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_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);                                      \
+}
+
+#else
+
+#define aosDbgCheck(c) {                                  \
+  (void)(c);                                              \
+  }
+
+#define aosDbgAssert(c) {                                 \
+  (void)(c);                                              \
+}
+
+#define aosDbgAssertMsg(c, r) {                           \
+  (void)(c);                                              \
+  (void)(r);                                              \
+}
+
+#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_shell.h b/os/core/inc/aos_shell.h
new file mode 100644
index 0000000..41dd511
--- /dev/null
+++ b/os/core/inc/aos_shell.h
@@ -0,0 +1,175 @@
+/*
+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_SHELL_H_
+#define _AMIROOS_SHELL_H_
+
+#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 system uptime with the prompt.
+ */
+#define AOS_SHELL_CONFIG_MATCH_CASE             (1 << 3)
+
+/**
+ * @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 {
+  aos_shellcommand_t* command;  /**< Pointer to the command that was executed. */
+  int retval;                   /**< Return value of the executed command. */
+} aos_shellexecstatus_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   Stream for user I/O.
+   */
+  BaseSequentialStream* 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   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, BaseSequentialStream* stream, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize);
+  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);
+  THD_FUNCTION(aosShellThread, shell);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _AMIROOS_SHELL_H_ */
diff --git a/os/core/inc/aos_ssm.h b/os/core/inc/aos_ssm.h
new file mode 100644
index 0000000..dccb5f2
--- /dev/null
+++ b/os/core/inc/aos_ssm.h
@@ -0,0 +1,120 @@
+/*
+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_SSM_H_
+#define _AMIROOS_SSM_H_
+
+#include <hal.h>
+#include <aos_types.h>
+#include <aos_debug.h>
+
+/**
+ * @brief   Sequential Stream Multiplexer output structure.
+ */
+typedef struct ssm_output {
+  /**
+   * @brief   Pointer to a BaseSequentialStream object.
+   */
+  BaseSequentialStream* stream;
+
+  /**
+   * @brief   Pointer to the next element in a singly linked list.
+   */
+  struct ssm_output* next;
+
+  /**
+   * @brief   Flags related to the output.
+   */
+  uint8_t flags;
+} ssm_output_t;
+
+/**
+ * @brief   Output flag to indicate whether the output is attached to a SSM list.
+ */
+#define SSM_OUTPUT_FLAG_ATTACHED                (1 << 0)
+
+/**
+ * @brief   Output flag to indicate whether the output is enabled.
+ */
+#define SSM_OUTPUT_FLAG_ENABLED                 (1 << 1)
+
+/**
+ * @brief   Sequential Stream Multiplexer specific methods.
+ */
+#define _sequential_stream_mux_methods          \
+  _base_sequential_stream_methods               \
+
+/**
+ * @brief   Sequential Stream Multiplexer specific data.
+ */
+#define _sequential_stream_mux_data             \
+  _base_sequential_stream_data                  \
+  ssm_output_t* outputs;                        \
+  BaseSequentialStream* input;                  \
+
+/**
+ * @brief   Sequential Stream Multiplexer virtual methods table.
+ */
+struct SequentialStreamMuxVMT {
+  _sequential_stream_mux_methods
+};
+
+/**
+ * @brief   Sequential Stream Multiplexer structure.
+ */
+typedef struct {
+  /**
+   * @brief   Virtual methods table.
+   */
+  const struct SequentialStreamMuxVMT *vmt;
+
+  /**
+   * @brief   Data fields.
+   */
+  _sequential_stream_mux_data
+} SequentialStreamMux;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void ssmObjectInit(SequentialStreamMux* ssmp);
+  void ssmOutputInit(ssm_output_t* op, BaseSequentialStream* stream);
+  void ssmAddOutput(SequentialStreamMux* ssmp, ssm_output_t* output);
+  aos_status_t ssmRemoveOutput(SequentialStreamMux* ssmp, BaseSequentialStream* stream, ssm_output_t** removed);
+  aos_status_t ssmEnableOutput(SequentialStreamMux* ssmp, BaseSequentialStream* stream);
+  aos_status_t ssmDisableOutput(SequentialStreamMux* ssmp, BaseSequentialStream* stream);
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @brief   Set the input stream
+ *
+ * @param[in] ssmp    pointer to the @p SequentialStreamMux object
+ * @param[in] stream  pointer to a @p BaseSequentialStream or NULL to disable input
+ */
+static inline void ssmSetInput(SequentialStreamMux* ssmp, BaseSequentialStream* stream)
+{
+  aosDbgCheck(ssmp != NULL);
+
+  ssmp->input = stream;
+
+  return;
+}
+
+#endif /* _AMIROOS_SSM_H_ */
diff --git a/os/core/inc/aos_system.h b/os/core/inc/aos_system.h
new file mode 100644
index 0000000..7f68ddd
--- /dev/null
+++ b/os/core/inc/aos_system.h
@@ -0,0 +1,202 @@
+/*
+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_SYSTEM_H_
+#define _AMIROOS_SYSTEM_H_
+
+#include <aos_ssm.h>
+#include <amiro-lld.h>
+#include <aos_shell.h>
+#include <aos_time.h>
+#include <chprintf.h>
+
+/**
+ * @brief   Default system I/O stream.
+ */
+#define AOS_SYSTEM_STDIO                        ((BaseSequentialStream*)aos.ssm)
+
+/**
+ * @brief   Printf function that uses the default system I/O stream.
+ */
+#define aosprintf(fmt, ...)                     chprintf((BaseSequentialStream*)AOS_SYSTEM_STDIO, fmt, ##__VA_ARGS__)
+
+/**
+ * @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 to transportation mode was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION    (eventflags_t)(1 << 0)
+
+/**
+ * @brief   System event flag which is emitted when a shutdown to deepsleep mode was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP         (eventflags_t)(1 << 1)
+
+/**
+ * @brief   System event flag which is emitted when a shutdown to hibernate mode was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_HIBERNATE         (eventflags_t)(1 << 2)
+
+/**
+ * @brief   System event flag which is emitted when a system restart was initiated.
+ */
+#define AOS_SYSTEM_EVENTFLAGS_RESTART           (eventflags_t)(1 << 3)
+
+/**
+ * @brief   Major version of the implemented SSSP.
+ */
+#define AOS_SYSTEM_SSSP_MAJOR                   1
+
+/**
+ * @brief   Minor version of the implemented SSSP.
+ */
+#define AOS_SYSTEM_SSSP_MINOR                   3
+
+/**
+ * @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  = 0x0000, /**< Identifier of SSSP startup phase stage 1-1. */
+  AOS_SSSP_STARTUP_1_2  = 0x0001, /**< Identifier of SSSP startup phase stage 1-2. */
+  AOS_SSSP_STARTUP_1_3  = 0x0002, /**< Identifier of SSSP startup phase stage 1-3. */
+  AOS_SSSP_STARTUP_2_1  = 0x0004, /**< Identifier of SSSP startup phase stage 2-1. */
+  AOS_SSSP_STARTUP_2_2  = 0x0005, /**< Identifier of SSSP startup phase stage 2-2. */
+  AOS_SSSP_STARTUP_3_1  = 0x0008, /**< Identifier of SSSP startup phase stage 3-1. */
+  AOS_SSSP_STARTUP_3_2  = 0x0009, /**< Identifier of SSSP startup phase stage 3-2. */
+  AOS_SSSP_STARTUP_3_3  = 0x000A, /**< Identifier of SSSP startup phase stage 3-3. */
+  AOS_SSSP_STARTUP_3_4  = 0x000B, /**< Identifier of SSSP startup phase stage 3-4. */
+  AOS_SSSP_OPERATION    = 0x0100, /**< Identifier of SSSP operation pahse. */
+  AOS_SSSP_SHUTDOWN_1_1 = 0x0200, /**< Identifier of SSSP shutdown phase stage 1-1. */
+  AOS_SSSP_SHUTDOWN_1_2 = 0x0201, /**< Identifier of SSSP shutdown phase stage 1-2. */
+  AOS_SSSP_SHUTDOWN_1_3 = 0x0202, /**< Identifier of SSSP shutdown phase stage 1-3. */
+  AOS_SSSP_SHUTDOWN_2_1 = 0x0204, /**< Identifier of SSSP shutdown phase stage 2-1. */
+  AOS_SSSP_SHUTDOWN_2_2 = 0x0205, /**< Identifier of SSSP shutdown phase stage 2-2. */
+  AOS_SSSP_SHUTDOWN_3   = 0x0208, /**< Identifier of SSSP shutdown phase stage 3. */
+} aos_ssspstage_t;
+
+/**
+ * @brief   AMiRo-OS base system structure.
+ */
+typedef struct aos_system {
+  /**
+   * @brief   Current SSSP stage of the system.
+   */
+  aos_ssspstage_t ssspStage;
+
+  /**
+   * @brief   Event structure.
+   */
+  struct {
+
+    /**
+     * @brief   I/O related events.
+     */
+    struct {
+      /**
+       * @brief   I/O event source.
+       */
+      event_source_t source;
+
+      /**
+       * @brief   Event flags emitted when a PD signal interrupt occurs.
+       */
+      eventflags_t flagsSignalPd;
+
+      /**
+       * @brief   Event flags emitted when a Sync signal interrupt occurs.
+       */
+      eventflags_t flagsSignalSync;
+    } io;
+
+    /**
+     * @brief   Operating system events.
+     */
+    struct {
+      /**
+       * @brief   OS event source.
+       */
+      event_source_t source;
+    } os;
+  } events;
+
+  /**
+   * @brief   Sequentiel Stream Multiplexer for system I/O
+   */
+  SequentialStreamMux* ssm;
+
+#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;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void aosSysInit(EXTDriver* extDrv, EXTConfig* extCfg, apalControlGpio_t* gpioPd, apalControlGpio_t* gpioSync, eventflags_t flagsSignalPd, eventflags_t evtFlagsSync, const char* shellPrompt);
+  void aosSysStart(void);
+  eventmask_t aosSysSsspStartupOsInitSyncCheck(event_listener_t* syncEvtListener);
+  void aosSysGetUptimeX(aos_timestamp_t* ut);
+  void aosSysShutdownInit(aos_shutdown_t shutdown);
+  void aosSysStop(void);
+  void aosSysDeinit(void);
+  void aosSysShutdownFinal(EXTDriver* extDrv, 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
new file mode 100644
index 0000000..b158d93
--- /dev/null
+++ b/os/core/inc/aos_thread.h
@@ -0,0 +1,232 @@
+/*
+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_THREAD_H_
+#define _AMIROOS_THREAD_H_
+
+#include <aos_time.h>
+#include <aos_system.h>
+
+/**
+ * @brief   Minimum thread priority.
+ */
+#define THD_LOWPRIO_MIN     ((tprio_t)  (LOWPRIO))
+
+/**
+ * @brief   Maximum priority for background threads.
+ */
+#define THD_LOWPRIO_MAX     ((tprio_t)  (LOWPRIO + ((NORMALPRIO - LOWPRIO) / 2)))
+
+/**
+ * @brief   Minimum priority for normal/standard threads.
+ */
+#define THD_NORMALPRIO_MIN  ((tprio_t)  (THD_LOWPRIO_MAX + 1))
+
+/**
+ * @brief   Maximum priority for normal/standard threads.
+ */
+#define THD_NORMALPRIO_MAX  ((tprio_t)  (NORMALPRIO))
+
+/**
+ * @brief   Minimum priority for important threads.
+ */
+#define THD_HIGHPRIO_MIN    ((tprio_t)  (NORMALPRIO + 1))
+
+/**
+ * @brief   Maximum priority for important threads.
+ */
+#define THD_HIGHPRIO_MAX    ((tprio_t)  (NORMALPRIO + ((HIGHPRIO - NORMALPRIO) / 2)))
+
+/**
+ * @brief   Minimum priority for real-time threads.
+ */
+#define THD_RTPRIO_MIN      ((tprio_t)  (THD_HIGHPRIO_MAX + 1))
+
+/**
+ * @brief   Maximum priority for real-time threads.
+ */
+#define THD_RTPRIO_MAX      ((tprio_t)  (HIGHPRIO - 1))
+
+/**
+ * @brief   Priority for the system control thread.
+ */
+#define THD_CTRLPRIO     ((tprio_t)  (HIGHPRIO))
+
+/**
+ * @brief   Maximum timeframe that can be slept in system ticks.
+ */
+#define THD_MAX_SLEEP_ST    TIME_MAXIMUM
+
+/**
+ * @brief   Maximum timeframe that can be slept in seconds.
+ */
+#define THD_MAX_SLEEP_S     (ST2S(THD_MAX_SLEEP_ST) - 1)
+
+/**
+ * @brief   Maximum timeframe that can be slept in milliseconds.
+ */
+#define THD_MAX_SLEEP_MS    (ST2MS(THD_MAX_SLEEP_ST) - 1)
+
+/**
+ * @brief   Maximum timeframe that can be slept in microseconds.
+ */
+#define THD_MAX_SLEEP_US    (ST2US(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
new file mode 100644
index 0000000..ec0dd15
--- /dev/null
+++ b/os/core/inc/aos_time.h
@@ -0,0 +1,207 @@
+/*
+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_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)
+
+#endif /* _AMIROOS_TIME_H_ */
diff --git a/os/core/inc/aos_timer.h b/os/core/inc/aos_timer.h
new file mode 100644
index 0000000..c0c5cbe
--- /dev/null
+++ b/os/core/inc/aos_timer.h
@@ -0,0 +1,250 @@
+/*
+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_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 TIMER_MAX_INTERVAL_ST         TIME_MAXIMUM
+
+/**
+ * @brief   Maximum timer interval that can be set in seconds.
+ */
+#define TIMER_MAX_INTERVAL_S          (ST2S(TIMER_MAX_INTERVAL_ST) - 1)
+
+/**
+ * @brief   Maximum timer interval that can be set in milliseconds.
+ */
+#define TIMER_MAX_INTERVAL_MS         (ST2MS(TIMER_MAX_INTERVAL_ST) - 1)
+
+/**
+ * @brief   Maximum timer interval that can be set in microseconds.
+ */
+#define TIMER_MAX_INTERVAL_US         (ST2US(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
new file mode 100644
index 0000000..5d24b32
--- /dev/null
+++ b/os/core/inc/aos_types.h
@@ -0,0 +1,34 @@
+/*
+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_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
new file mode 100644
index 0000000..6bf995c
--- /dev/null
+++ b/os/core/inc/aos_unittest.h
@@ -0,0 +1,108 @@
+/*
+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_UNITTEST_H_
+#define _AMIROOS_UNITTEST_H_
+
+#include <aosconf.h>
+#include <hal.h>
+#include <aos_shell.h>
+
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+
+/*
+ * 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
new file mode 100644
index 0000000..89beb1c
--- /dev/null
+++ b/os/core/src/aos_debug.c
@@ -0,0 +1,130 @@
+/*
+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 <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_shell.c b/os/core/src/aos_shell.c
new file mode 100644
index 0000000..c76169e
--- /dev/null
+++ b/os/core/src/aos_shell.c
@@ -0,0 +1,1071 @@
+/*
+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 <aos_shell.h>
+
+#include <aos_debug.h>
+#include <aos_time.h>
+#include <aos_system.h>
+#include <chprintf.h>
+#include <string.h>
+#include <aos_thread.h>
+
+/**
+ * @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);
+  aosDbgCheck(shell->stream != NULL);
+
+  // print the system uptime before prompt is configured
+  if (shell->config & AOS_SHELL_CONFIG_PROMPT_UPTIME) {
+    // get current system uptime
+    aos_timestamp_t uptime;
+    aosSysGetUptime(&uptime);
+
+    chprintf(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));
+  }
+
+  // print the actual prompt string
+  if (shell->prompt && !(shell->config & AOS_SHELL_CONFIG_PROMPT_MINIMAL)) {
+    chprintf(shell->stream, "%s$ ", shell->prompt);
+  } else {
+    chprintf(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);
+  aosDbgCheck(shell->stream != 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);
+  aosDbgCheck(shell->stream != 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]);
+}
+
+/**
+ * @brief   Reads a line from input stream
+ * @details The line is directly written to the given shell object.
+ *
+ * @param[in] shell   Pointer to the shell object.
+ *
+ * @return              A status indicator.
+ * @retval AOS_SUCCESS  Input sucessfully read, line is valid.
+ * @retval AOS_ERROR    An I/O error occurred.
+ */
+static aos_status_t _readLine(aos_shell_t* shell)
+{
+  aosDbgCheck(shell != NULL);
+
+  /*
+   * Enumerator to encode a function.
+   */
+  typedef enum {
+    READ_CHAR,
+    AUTOFILL,
+    SUGGEST,
+    INS_TOGGLE,
+    DELETE_FORWARD,
+    DELETE_BACKWARD,
+    RECALL_LAST,
+    CLEAR,
+    CURSOR2START,
+    CURSOR2END,
+    CURSOR_LEFT,
+    CURSOR_RIGHT,
+    EXECUTE,
+    ESC_START,
+    NONE,
+  } func_t;
+
+  // local variables
+  func_t func = NONE;
+  func_t lastfunc = NONE;
+  bool noinput = true;
+  size_t lineend = 0;
+  size_t cursorpos = 0;
+  char c;
+  uint8_t escp = 0;
+  char escseq[5] = {'\0'};
+
+  // read character by character from stream
+  while (streamRead(shell->stream, (uint8_t*)&c, 1)) {
+    special_key_t key = KEY_UNKNOWN;
+
+    // parse escape sequence
+    if (escp > 0) {
+      escseq[escp] = c;
+      ++escp;
+      key = _interpreteEscapeSequence(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 variables and interprete key/character
+        escp = 0;
+        memset(escseq, '\0', sizeof(escseq));
+      }
+    }
+
+    // interprete keys or characters
+    {
+      func = NONE; // default
+      if (key == KEY_UNKNOWN &&
+          (/* printable character */ c >= '\x20' && c <= '\x7E') ) {
+        func = READ_CHAR;
+      } else if (key == KEY_TAB ||
+                 /* horizontal tab ('\t') */ c == '\x09') {
+        // pressing tab once applies auto fill,
+        // presing a second time prints suggestions
+        if (lastfunc == AUTOFILL || lastfunc == SUGGEST) {
+          func = SUGGEST;
+        } else {
+          func = AUTOFILL;
+        }
+      } else if (key == KEY_INSERT) {
+        func = INS_TOGGLE;
+      } else if (key == KEY_DELETE ||
+                 /* [DEL] */ c == '\x7F') {
+        // ignore of cursor is very right
+        if (cursorpos < lineend) {
+          func = DELETE_FORWARD;
+        }
+      } else if (key == KEY_BACKSPACE ||
+                 /* backpace ('\b') */c == '\x08') {
+        // ignore if cursor is very left
+        if (cursorpos > 0) {
+          func = DELETE_BACKWARD;
+        }
+      } else if (key == KEY_PAGE_UP ||
+                 key == KEY_ARROW_UP) {
+        // ignore if there was some input
+        if (noinput) {
+          func = RECALL_LAST;
+        }
+      } else if (key == KEY_PAGE_DOWN ||
+                 key == KEY_ARROW_DOWN ||
+                 /* end of test */ c == '\x03' ||
+                 /* end of transmission */ c == '\x04') {
+        // ignore if line is empty
+        if (lineend > 0) {
+          func = CLEAR;
+        }
+      } else if (key == KEY_HOME) {
+        // ignore if cursor is very left
+        if (cursorpos > 0) {
+          func = CURSOR2START;
+        }
+      } else if (key == KEY_END) {
+        // ignore if cursor is very right
+        if (cursorpos < lineend) {
+          func = CURSOR2END;
+        }
+      } else if (key == KEY_ARROW_LEFT) {
+        // ignore if cursor is very left
+        if (cursorpos > 0) {
+          func = CURSOR_LEFT;
+        }
+      } else if (key == KEY_ARROW_RIGHT) {
+        // ignore if cursor is very right
+        if (cursorpos < lineend) {
+          func = CURSOR_RIGHT;
+        }
+      } else if (/* carriage return ('\r') */c == '\x0D' ||
+                 /* line feed ('\n') */ c == '\x0A') {
+        func = EXECUTE;
+      } else if (key == KEY_ESCAPE ||
+                 /* [ESCAPE] */ c == '\x1B') {
+        func = ESC_START;
+      }
+    }
+
+    /* handle function */
+    switch (func) {
+      case READ_CHAR:
+        // line is full
+        if (lineend + 1 >= shell->linesize) {
+          _moveCursor(shell, cursorpos, lineend);
+          chprintf(shell->stream, "\n\tmaximum line width reached\n");
+          _printPrompt(shell);
+          _printLine(shell, 0, lineend);
+          _moveCursor(shell, lineend, cursorpos);
+        }
+        // read character
+        else {
+          // clear old line content on first input
+          if (noinput) {
+            memset(shell->line, '\0', shell->linesize);
+            noinput = false;
+          }
+          // overwrite content
+          if (shell->config & AOS_SHELL_CONFIG_INPUT_OVERWRITE) {
+            shell->line[cursorpos] = c;
+            ++cursorpos;
+            lineend = (cursorpos > lineend) ? cursorpos : lineend;
+            streamPut(shell->stream, c);
+          }
+          // insert character
+          else {
+            memmove(&(shell->line[cursorpos+1]), &(shell->line[cursorpos]), lineend - cursorpos);
+            shell->line[cursorpos] = c;
+            ++lineend;
+            _printLine(shell, cursorpos, lineend);
+            ++cursorpos;
+            _moveCursor(shell, lineend, cursorpos);
+          }
+        }
+        break;
+
+      case AUTOFILL:
+      {
+        const char* fill = shell->line;
+        size_t cmatch = 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 == cursorpos) {
+            cmatch = cursorpos;
+            fill = cmd->name;
+            // break the loop only if there are no case mismatches with the input
+            n = 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 > 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 > cursorpos || (cmatch == cursorpos && matchlevel == CHAR_MATCH_NCASE)) {
+          noinput = false;
+          // limit auto fill so it will not overflow the line width
+          if (lineend + (cmatch - cursorpos) > shell->linesize) {
+            cmatch = shell->linesize - lineend + cursorpos;
+          }
+          // move trailing memory further in the line
+          memmove(&(shell->line[cmatch]), &(shell->line[cursorpos]), lineend - cursorpos);
+          lineend += cmatch - cursorpos;
+          // if there was no incorrect case when matching
+          if (matchlevel == CHAR_MATCH_CASE) {
+            // insert fill command name to line
+            memcpy(&(shell->line[cursorpos]), &(fill[cursorpos]), cmatch - cursorpos);
+            // print the output
+            _printLine(shell, cursorpos, lineend);
+          } else {
+            // overwrite line with fill command name
+            memcpy(shell->line, fill, cmatch);
+            // reprint the whole line
+            _moveCursor(shell, cursorpos, 0);
+            _printLine(shell, 0, lineend);
+          }
+          // move cursor to the end of the matching sequence
+          cursorpos = cmatch;
+          _moveCursor(shell, lineend, cursorpos);
+        }
+        break;
+      }
+
+      case 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 = cursorpos;
+          if (cursorpos > 0) {
+            _strccmp(shell->line, cmd->name, true, &i, NULL);
+          }
+          const int cmp = (i < cursorpos) ?
+                            (i - 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, cursorpos, lineend);
+              streamPut(shell->stream, '\n');
+            }
+            // print the command
+            chprintf(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, lineend);
+          _moveCursor(shell, lineend, cursorpos);
+          noinput = false;
+        }
+        break;
+      }
+
+      case INS_TOGGLE:
+        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 DELETE_FORWARD:
+        --lineend;
+        memmove(&(shell->line[cursorpos]), &(shell->line[cursorpos+1]), lineend - cursorpos);
+        _printLine(shell, cursorpos, lineend);
+        streamPut(shell->stream, ' ');
+        _moveCursor(shell, lineend + 1, cursorpos);
+        break;
+
+      case DELETE_BACKWARD:
+        --cursorpos;
+        memmove(&(shell->line[cursorpos]), &(shell->line[cursorpos+1]), lineend - cursorpos);
+        --lineend;
+        shell->line[lineend] = '\0';
+        _moveCursor(shell, cursorpos + 1, cursorpos);
+        _printLine(shell, cursorpos, lineend);
+        streamPut(shell->stream, ' ');
+        _moveCursor(shell, lineend+1, cursorpos);
+        break;
+
+      case RECALL_LAST:
+      {
+        // replace any intermediate NUL bytes with spaces
+        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);
+                lineend = nul_end + 1;
+                break;
+              } else {
+                ++nul_end;
+              }
+            }
+            nul_start = nul_end + 1;
+          } else {
+            ++lineend;
+            ++nul_start;
+          }
+        }
+        cursorpos = lineend;
+        // print the line
+        noinput = _printLine(shell, 0, lineend) == 0;
+        break;
+      }
+
+      case CLEAR:
+        // clear output
+        _moveCursor(shell, cursorpos, 0);
+        for (cursorpos = 0; cursorpos < lineend; ++cursorpos) {
+          streamPut(shell->stream, ' ');
+        }
+        _moveCursor(shell, lineend, 0);
+        cursorpos = 0;
+        lineend = 0;
+        noinput = true;
+        break;
+
+      case CURSOR2START:
+        _moveCursor(shell, cursorpos, 0);
+        cursorpos = 0;
+        break;
+
+      case CURSOR2END:
+        _moveCursor(shell, cursorpos, lineend);
+        cursorpos = lineend;
+        break;
+
+      case CURSOR_LEFT:
+        _moveCursor(shell, cursorpos, cursorpos-1);
+        --cursorpos;
+        break;
+
+      case CURSOR_RIGHT:
+        _moveCursor(shell, cursorpos, cursorpos+1);
+        ++cursorpos;
+        break;
+
+      case EXECUTE:
+        streamPut(shell->stream, '\n');
+        // return a warning if there was no input
+        if (noinput) {
+          return AOS_WARNING;
+        } else {
+          // fill the remainder of the line with NUL bytes
+          memset(&(shell->line[lineend]), '\0', shell->linesize - lineend);
+          return AOS_SUCCESS;
+        }
+        break;
+
+      case ESC_START:
+        escseq[0] = c;
+        ++escp;
+        break;
+
+      case NONE:
+      default:
+        // do nothing (ignore input) and read next byte
+        continue;
+        break;
+    }
+
+    lastfunc = func;
+  } /* end of while */
+
+  /* This code is only executed when some error occurred.
+   * The reason may be:
+   *   - The input stream was disabled (streamRead() returned 0)
+   *   - Parsing of input failed unexpectedly
+   */
+  return AOS_ERROR;
+}
+
+/**
+ * @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, BaseSequentialStream* stream, const char* prompt, char* line, size_t linesize, char** arglist, size_t arglistsize)
+{
+  aosDbgCheck(shell != NULL);
+  aosDbgCheck(stream != NULL);
+  aosDbgCheck(line != NULL);
+  aosDbgCheck(arglist != NULL);
+
+  // set parameters
+  shell->thread = NULL;
+  chEvtObjectInit(&shell->eventSource);
+  shell->stream = stream;
+  shell->prompt = prompt;
+  shell->commands = NULL;
+  shell->execstatus.command = NULL;
+  shell->execstatus.retval = 0;
+  shell->line = line;
+  shell->linesize = linesize;
+  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   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 (1) {
+    // if the end of the list was reached, append the command
+    if (*curr == NULL) {
+      *curr = cmd;
+      return AOS_SUCCESS;
+    } else {
+      // 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;
+      }
+    }
+  }
+}
+
+/**
+ * @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   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
+  size_t nargs = 0;
+  aos_status_t readlval;
+
+  // fire start event
+  chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_START);
+
+  // enter thread loop
+  while (!chThdShouldTerminateX()) {
+    // print the prompt
+    _printPrompt((aos_shell_t*)shell);
+
+    // read input line
+    readlval = _readLine((aos_shell_t*)shell);
+    if (readlval == AOS_ERROR) {
+      // emit an error event
+      chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_IOERROR);
+      // erither break the loop or try again afte some time
+      if (chThdShouldTerminateX()) {
+        break;
+      } else {
+        aosThdSSleep(1);
+      }
+    }
+
+    // parse input line to arguments only if reading the line was successful
+    nargs = (readlval == AOS_SUCCESS) ? _parseArguments((aos_shell_t*)shell) : 0;
+    if (nargs > ((aos_shell_t*)shell)->arglistsize) {
+      // error: too many arguments
+      chprintf(((aos_shell_t*)shell)->stream, "\tERROR: too many arguments\n");
+      continue;
+    }
+
+    // skip if there are no arguments
+    if (nargs > 0) {
+      // search command list for arg[0] and execure callback function
+      aos_shellcommand_t* 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(((aos_shell_t*)shell)->stream, nargs, ((aos_shell_t*)shell)->arglist);
+          chEvtBroadcastFlags(&(((aos_shell_t*)shell)->eventSource), AOS_SHELL_EVTFLAG_DONE);
+          // append a line break so the next print will start from the very left
+          // usually this should just add an empty line, which is visually appealing
+          chprintf(((aos_shell_t*)shell)->stream, "\n");
+          // notify if the command was not successful
+          if (((aos_shell_t*)shell)->execstatus.retval != 0) {
+            chprintf(((aos_shell_t*)shell)->stream, "command returned exit status %d\n", ((aos_shell_t*)shell)->execstatus.retval);
+          }
+          break;
+        }
+        cmd = cmd->next;
+      }
+      // if no matching command was found, print an error
+      if (cmd == NULL) {
+        chprintf(((aos_shell_t*)shell)->stream, "%s: command not found\n", ((aos_shell_t*)shell)->arglist[0]);
+      }
+    }
+
+  } /* end of while loop */
+
+  // 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
+}
diff --git a/os/core/src/aos_ssm.c b/os/core/src/aos_ssm.c
new file mode 100644
index 0000000..52bf62a
--- /dev/null
+++ b/os/core/src/aos_ssm.c
@@ -0,0 +1,288 @@
+/*
+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 <aos_ssm.h>
+
+/**
+ * @brief   Sequential Stream Multiplexer write.
+ *
+ * @param[in] ip      pointer to a @p SequentialStreamMux object
+ * @param[in] bp      pointer to the data buffer
+ * @param[in] n       the maximum amount of bytes to be transferred
+ *
+ * @return            The minimum number of bytes written to one of the BaseSequentialStreams.
+ *                    If the return value is lower than n, one or multiple (or even all) streams could not write all bytes as requested.
+ */
+static size_t write(void *ip, const uint8_t *bp, size_t n)
+{
+  // initialize the number of written bytes
+  size_t outbytes = ~0;
+  // iterate over all output streams associated with te mux
+  ssm_output_t* out = ((SequentialStreamMux*)ip)->outputs;
+  while (out != NULL) {
+    // if the output is enabled
+    if (out->flags | SSM_OUTPUT_FLAG_ENABLED) {
+      // write to the stream
+      register const size_t ob = streamWrite(out->stream, bp, n);
+      // retrieve the minimal number of bytes written across all streams
+      outbytes = (ob < outbytes) ? ob : outbytes;
+    }
+    // iterate to the next stream
+    out = out->next;
+  }
+
+  return (outbytes == (size_t)~0) ? 0 : outbytes;
+}
+
+/**
+ * @brief   Sequential Stream Multiplexer read.
+ *
+ * @param[in]  ip     pointer to a @p SequentialStreamMux object
+ * @param[out] bp     pointer to the data buffer
+ * @param[in]  n      the maximum amount of data to be transferred
+ *
+ * @return            The number of bytes transferred.
+ */
+static size_t read(void *ip, uint8_t *bp, size_t n)
+{
+  // check whether a input stream is set
+  if ( ((SequentialStreamMux*)ip)->input != NULL ) {
+    // read from the input stream
+    return streamRead(((SequentialStreamMux*)ip)->input, bp, n);
+  } else {
+    // return zero since
+    return 0;
+  }
+}
+
+/**
+ * @brief   Sequential Stream Multiplexer blocking byte write
+ *
+ * @param[in] ip      pointer to a @p SequentialStreamMux object
+ * @param[in] b       the byte value to be written
+ *
+ * @return            The operation status.
+ *                    The operation status is ORed from all enabled output streams.
+ *                    The operation status of each output stream depends on its implementation.
+ */
+static msg_t put(void *ip, uint8_t b)
+{
+  // initialize the return value
+  msg_t retval = MSG_OK;
+  // iterate over all output streams associated with the mux
+  ssm_output_t* out = ((SequentialStreamMux*)ip)->outputs;
+  while (out != NULL) {
+    // if the output is enabled
+    if (out->flags | SSM_OUTPUT_FLAG_ENABLED) {
+      // put the given byte on the stream
+      retval |= streamPut(out->stream, b);
+    }
+    // iterate to rhe next stream
+    out = out->next;
+  }
+
+  return retval;
+}
+
+/**
+ * @brief   Sequential Stream Multiplexer blocking byte read
+ *
+ * @param[in] ip      pointer to the @p SequentialStreamMux object
+ *
+ * @return            A byte value from the input.
+ */
+static msg_t get(void *ip)
+{
+  // check whether an input is set
+  if ( ((SequentialStreamMux*)ip)->input != NULL) {
+    // get a byte from the input
+    return streamGet(((SequentialStreamMux*)ip)->input);
+  } else {
+    // return an error
+    return MSG_RESET;
+  }
+}
+
+static const struct SequentialStreamMuxVMT vmt = {
+  write, read, put, get
+};
+
+/**
+ * @brief   Initializes a @p SequentialStreamMux object
+ *
+ * @param[in] ssmp    pointer to the @p SequentialStreamMux object
+ */
+void ssmObjectInit(SequentialStreamMux *ssmp)
+{
+  aosDbgCheck(ssmp != NULL);
+
+  // initialize object variables
+  ssmp->vmt = &vmt;
+  ssmp->outputs = NULL;
+  ssmp->input = NULL;
+
+  return;
+}
+
+/**
+ * @brief   Initializes a @p ssm_output_t object
+ *
+ * @param[in] op    pointer to the @p ssm_output_t object
+ */
+void ssmOutputInit(ssm_output_t* op, BaseSequentialStream* stream)
+{
+  aosDbgCheck(op != NULL);
+
+  // initialize object variables
+  op->stream = stream;
+  op->next = NULL;
+  op->flags = 0;
+
+  return;
+}
+
+/**
+ * @brief   Adds an output to the SSM object.
+ * @note    New outputs are always prepended to the list.
+ *
+ * @param[in] ssmp    pointer to the @p SequentialStreamMux object to be modified
+ * @param[in] output  pointer to the @p ssm_output_t object to be inserted
+ */
+void ssmAddOutput(SequentialStreamMux* ssmp, ssm_output_t* output)
+{
+  aosDbgCheck(ssmp != NULL);
+  aosDbgCheck(output != NULL);
+  aosDbgCheck(output->next == NULL && output->flags ^ SSM_OUTPUT_FLAG_ATTACHED);
+
+  // prepend output to the list
+  output->flags = SSM_OUTPUT_FLAG_ATTACHED;
+  output->next = ssmp->outputs;
+  ssmp->outputs = output;
+
+  return;
+}
+
+/**
+ * @brief   Removes an output from the SSM object.
+ *
+ * @param[in] ssmp      pointer to the @p SequentialStreamMux object to be modified
+ * @param[in] stream    pointer to the @p BaseSequentialStream to remove
+ * @param[out] removed  pointer to the @p ssm_output_t that was removed, or NULL
+ *
+ * @return              Error code indicating any errors or warnings.
+ * @retval AOS_SUCCESS  the stream was removed sucessfully
+ * @retval AOS_ERROR    the stream was not found in the list
+ */
+aos_status_t ssmRemoveOutput(SequentialStreamMux* ssmp, BaseSequentialStream* stream, ssm_output_t** removed)
+{
+  aosDbgCheck(ssmp != NULL);
+  aosDbgCheck(stream != NULL);
+
+  // local varibales
+  ssm_output_t* prev = NULL;
+  ssm_output_t* curr = ssmp->outputs;
+
+  // iterate through the list and search for the specified stream
+  while (curr != NULL) {
+    // if the stream was found, remove it
+    if (curr->stream == stream) {
+      // special case: the first stream matches
+      if (prev == NULL) {
+        ssmp->outputs->next = curr->next;
+      } else {
+        prev->next = curr->next;
+      }
+      curr->next = NULL;
+      curr->flags &= ~SSM_OUTPUT_FLAG_ATTACHED;
+      // set the optional output argument
+      if (removed != NULL) {
+        *removed = curr;
+      }
+      return AOS_SUCCESS;
+    }
+    // iterate through to the next item
+    else {
+      prev = curr;
+      curr = curr->next;
+    }
+  }
+
+  // if the stream was not found, return an error
+  return AOS_ERROR;
+}
+
+/**
+ * @brief   Enable an associated stream
+ *
+ * @param[in] ssmp    pointer to the @p SequentialStreamMux object
+ * @param[in] stream  pointer to the @p BaseSequentialStream to enable
+ *
+ * @return            The operation status.
+ * @retval AOS_SUCCESS  if the operation succeeded.
+ * @retval AOS_ERROR    if the specified stream is not associated to the @p SequentialStreamMux.
+ */
+aos_status_t ssmEnableOutput(SequentialStreamMux *ssmp, BaseSequentialStream *stream)
+{
+  aosDbgCheck(ssmp != NULL);
+  aosDbgCheck(stream != NULL);
+
+  // iterate over all output streams associated to the given mux
+  ssm_output_t* out = ssmp->outputs;
+  while (out != NULL) {
+    // if the output was found, activate the enabled flag
+    if (out->stream == stream) {
+      out->flags |= SSM_OUTPUT_FLAG_ENABLED;
+      return AOS_SUCCESS;
+    } else {
+      out = out->next;
+    }
+  }
+  // error if the stream is not associated with the mux
+  return AOS_ERROR;
+}
+
+/**
+ * @brief   Disable an associated stream
+ *
+ * @param[in] ssmp    pointer to the @p SequentialStreamMux or derived class
+ * @param[in] stream  pointer to the stream to disable
+ *
+ *
+ * @return            The operation status.
+ * @retval AOS_OK     if the operation succeeded.
+ * @retval AOS_ERROR  if the specified stream is not associated to the @p SequentialStreamMux.
+ */
+aos_status_t ssmDisableOutput(SequentialStreamMux *ssmp, BaseSequentialStream *stream)
+{
+  aosDbgCheck(ssmp != NULL);
+  aosDbgCheck(stream != NULL);
+
+  // iterate over all output streams associated to the given mux
+  ssm_output_t* out = ssmp->outputs;
+  while (out != NULL) {
+    // if the output was found, activate the enabled flag
+    if (out->stream == stream) {
+      out->flags &= ~SSM_OUTPUT_FLAG_ENABLED;
+      return AOS_SUCCESS;
+    } else {
+      out = out->next;
+    }
+  }
+  // error if the stream is not associated with the mux
+  return AOS_ERROR;
+}
diff --git a/os/core/src/aos_system.c b/os/core/src/aos_system.c
new file mode 100644
index 0000000..47a764d
--- /dev/null
+++ b/os/core/src/aos_system.c
@@ -0,0 +1,904 @@
+/*
+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 <aos_system.h>
+
+#include <chprintf.h>
+#include <amiroos.h>
+#include <amiroblt.h>
+#include <string.h>
+#include <stdarg.h>
+#if (AMIROOS_CFG_TESTS_ENABLE == true)
+#include <ch_test.h>
+#endif
+
+/**
+ * @brief   Period of the system timer.
+ */
+#define SYSTIMER_PERIOD               (TIME_MAXIMUM - CH_CFG_ST_TIMEDELTA)
+
+/**
+ * @brief   Width of the printable system info text.
+ */
+#define SYSTEM_INFO_WIDTH             70
+
+/* 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   PD signal GPIO.
+ */
+static apalControlGpio_t* _gpioPd;
+
+/**
+ * @brief   Sync signal GPIO.
+ */
+static apalControlGpio_t* _gpioSync;
+
+/**
+ * @brief   Sequelntiel Stream Multiplexer for the system I/O stream.
+ */
+static SequentialStreamMux _ssm;
+
+/**
+ * @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_SHELL_ENABLE == true) || defined(__DOXYGEN__)
+/**
+ * @brief   System shell.
+ */
+static aos_shell_t _shell;
+
+/**
+ * @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 = {
+  /* SSSP stage */ AOS_SSSP_STARTUP_2_1,
+  /* event      */ {
+    /* I/O      */ {
+      /* source           */ {
+        /* next listener  */ NULL,
+      },
+      /* flagsSignalPd    */ 0,
+      /* flagsSignalSync  */ 0,
+    },
+    /* OS */ {
+      /* source */ {
+        /* next listener  */ NULL,
+      }
+    },
+  },
+  /* ssm        */ &_ssm,
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  /* shell      */ &_shell,
+#endif
+};
+
+/**
+ * @brief   Print a separator line.
+ *
+ * @param[in] stream    Stream to print to.
+ * @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.
+ * @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(stream != NULL);
+
+  unsigned int n = 0;
+
+  // print the name and trailing spaces
+  n += chprintf(stream, name);
+  while (n < namewidth) {
+    streamPut(stream, ' ');
+    ++n;
+  }
+
+  // print the content
+  va_list ap;
+  va_start(ap, fmt);
+  n += chvprintf(stream, fmt, ap);
+  va_end(ap);
+
+  return n;
+}
+
+/**
+ * @brief   Prints information about the system.
+ *
+ * @param[in] stream    Stream to print to.
+ */
+static void _printSystemInfo(BaseSequentialStream *stream)
+{
+  aosDbgCheck(stream != NULL);
+
+  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
+  _printSystemInfoLine(stream, "Module", 14, "%s (v%s)\n", BOARD_NAME, BOARD_VERSION);
+#ifdef PLATFORM_NAME
+  _printSystemInfoLine(stream, "Platform", 14, "%s\n", PLATFORM_NAME);
+#endif
+#ifdef PORT_CORE_VARIANT_NAME
+  _printSystemInfoLine(stream, "Core Variant", 14, "%s\n", PORT_CORE_VARIANT_NAME);
+#endif
+  _printSystemInfoLine(stream, "Architecture", 14, "%s\n", PORT_ARCHITECTURE_NAME);
+  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
+  _printSystemInfoLine(stream, "AMiRo-OS" ,14, "%u.%u.%u %s (%s build)\n", AMIROOS_VERSION_MAJOR, AMIROOS_VERSION_MINOR, AMIROOS_VERSION_PATCH, AMIROOS_RELEASE_TYPE, (AMIROOS_CFG_DBG == true) ? "debug" : "release");
+  _printSystemInfoLine(stream, "AMiRo-LLD" ,14, "%u.%u.%u %s (periphAL %u.%u)\n", 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" ,14, "%u.%u.%u %s\n", CH_KERNEL_MAJOR, CH_KERNEL_MINOR, CH_KERNEL_PATCH, (CH_KERNEL_STABLE == 1) ? "stable" : "non-stable");
+  _printSystemInfoLine(stream, "ChibiOS/HAL",14, "%u.%u.%u %s\n", CH_HAL_MAJOR, CH_HAL_MINOR, CH_HAL_PATCH, (CH_HAL_STABLE == 1) ? "stable" : "non-stable");
+  _printSystemInfoLine(stream, "Compiler" ,14, "%s %u.%u.%u\n", "GCC", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); // TODO: support other compilers than GCC
+  _printSystemInfoLine(stream, "Compiled" ,14, "%s - %s\n", __DATE__, __TIME__);
+  _printSystemInfoSeparator(stream, '-', SYSTEM_INFO_WIDTH);
+  if (BL_CALLBACK_TABLE_ADDRESS->magicNumber == BL_MAGIC_NUMBER) {
+    _printSystemInfoLine(stream, "AMiRo-BLT", 14, "%u.%u.%u %s (SSSP %u.%u)\n", 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);
+    _printSystemInfoLine(stream, "Compiler", 14, "%s %u.%u.%u\n", (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 {
+    chprintf(stream, "Bootloader incompatible or not available.\n");
+  }
+  _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[])
+{
+  // 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;
+              retval = AOS_OK;
+            }
+            else if (strcmp(argv[3], "uptime") == 0) {
+              aos.shell->config |= AOS_SHELL_CONFIG_PROMPT_UPTIME;
+              retval = AOS_OK;
+            }
+          }
+        }
+        // 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");
+        chprintf(stream, "  prompt style:  %s, %s\n",
+                 (aos.shell->config & AOS_SHELL_CONFIG_PROMPT_MINIMAL) ? "minimal" : "text",
+                 (aos.shell->config & AOS_SHELL_CONFIG_PROMPT_UPTIME) ? "system uptime" : "no 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;
+      }
+    }
+  }
+
+  // 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|notime\n");
+    chprintf(stream, "        Configures the prompt.\n");
+    chprintf(stream, "      match casesensitive|caseinsenitive\n");
+    chprintf(stream, "        Configures string matching.\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[])
+{
+  (void)argc;
+  (void)argv;
+
+  // print system information
+  _printSystemInfo(stream);
+
+  // print time measurement precision
+  chprintf(stream, "system 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));
+
+  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[])
+{
+  // 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.source, AOS_SYSTEM_EVENTFLAGS_HIBERNATE);
+      chThdExit(MSG_OK);
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--deepsleep") == 0) {
+      chEvtBroadcastFlags(&aos.events.os.source, AOS_SYSTEM_EVENTFLAGS_DEEPSLEEP);
+      chThdExit(MSG_OK);
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-t") == 0 || strcmp(argv[1], "--transportation") == 0) {
+      chEvtBroadcastFlags(&aos.events.os.source, AOS_SYSTEM_EVENTFLAGS_TRANSPORTATION);
+      chThdExit(MSG_OK);
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--restart") == 0) {
+      chEvtBroadcastFlags(&aos.events.os.source, AOS_SYSTEM_EVENTFLAGS_RESTART);
+      chThdExit(MSG_OK);
+      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[])
+{
+  (void)argc;
+  (void)argv;
+
+  tprio_t prio = chThdGetPriorityX();
+  chThdSetPriority(HIGHPRIO - 5); // some tests increase priorirty by 5, so this is the maximum priority permitted
+  msg_t retval = test_execute(stream);
+  chThdSetPriority(prio);
+
+  return retval;
+}
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/**
+ * @brief   Callback function for the PD signal interrupt.
+ *
+ * @param[in] extp      Pointer to the interrupt driver object.
+ * @param[in] channel   Interrupt channel identifier.
+ */
+static void _signalPdCallback(EXTDriver* extp, expchannel_t channel)
+{
+  (void)extp;
+  (void)channel;
+
+  chSysLockFromISR();
+  chEvtBroadcastFlagsI(&aos.events.io.source, aos.events.io.flagsSignalPd);
+  chSysUnlockFromISR();
+
+  return;
+}
+
+/**
+ * @brief   Callback function for the Sync signal interrupt.
+ *
+ * @param[in] extp      Pointer to the interrupt driver object.
+ * @param[in] channel   Interrupt channel identifier.
+ */
+static void _signalSyncCallback(EXTDriver* extp, expchannel_t channel)
+{
+  (void)extp;
+  (void)channel;
+
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  chSysLockFromISR();
+  chEvtBroadcastFlagsI(&aos.events.io.source, aos.events.io.flagsSignalSync);
+  chSysUnlockFromISR();
+#else
+  apalControlGpioState_t s_state;
+  aos_timestamp_t uptime;
+
+  chSysLockFromISR();
+  // get current uptime
+  aosSysGetUptimeX(&uptime);
+  // read signal S
+  apalControlGpioGet(_gpioSync, &s_state);
+  // if S was toggled from on to off during SSSP operation phase
+  if (aos.ssspStage == AOS_SSSP_OPERATION && s_state == APAL_GPIO_OFF) {
+    // align the uptime with the synchronization period
+    if (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD < AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2) {
+      _uptime -= uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD;
+    } else {
+      _uptime += AMIROOS_CFG_SSSP_SYSSYNCPERIOD - (uptime % AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
+    }
+  }
+  // broadcast event
+  chEvtBroadcastFlagsI(&aos.events.io.source, aos.events.io.flagsSignalSync);
+  chSysUnlockFromISR();
+#endif
+
+  return;
+}
+
+/**
+ * @brief   Callback function for the uptime accumulation timer.
+ *
+ * @param[in] par   Generic parameter.
+ */
+#include <module.h>
+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 += LL_ST2US(st - _synctime);
+  _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();
+  // read and toggle signal S
+  apalControlGpioGet(_gpioSync, &s_state);
+  s_state = (s_state == APAL_GPIO_ON) ? APAL_GPIO_OFF : APAL_GPIO_ON;
+  apalControlGpioSet(_gpioSync, 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, LL_US2ST(_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, LL_US2ST(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] extDrv        Pointer to the interrupt driver.
+ * @param[in] extCfg        Configuration for the interrupt driver.
+ * @param[in] gpioPd        GPIO of the PD signal.
+ * @param[in] gpioSync      GPIO of the Sync signal
+ * @param[in] evtFlagsPd    Event flags to be set when a PD interrupt occurs.
+ * @param[in] evtFlagsSync  Event flags to be set when a Sync interrupt occurs.
+ * @param[in] shellPrompt   String to be printed as prompt of the system shell.
+ */
+void aosSysInit(EXTDriver* extDrv,
+                EXTConfig* extCfg,
+                apalControlGpio_t* gpioPd,
+                apalControlGpio_t* gpioSync,
+                eventflags_t evtFlagsPd,
+                eventflags_t evtFlagsSync,
+                const char* shellPrompt)
+{
+  // check arguments
+  aosDbgCheck(extDrv != NULL);
+  aosDbgCheck(extCfg != NULL);
+  aosDbgCheck(gpioPd != NULL);
+  aosDbgCheck(gpioSync != NULL);
+
+  // set control thread to maximum priority
+  chThdSetPriority(THD_CTRLPRIO);
+
+  // set local variables
+  _gpioPd = gpioPd;
+  _gpioSync = gpioSync;
+  chVTObjectInit(&_systimer);
+  _synctime = 0;
+  _uptime = 0;
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+  chVTObjectInit(&_syssynctimer);
+  _syssynctime = 0;
+#endif
+
+  // set aos configuration
+  aos.ssspStage = AOS_SSSP_STARTUP_2_1;
+  chEvtObjectInit(&aos.events.io.source);
+  chEvtObjectInit(&aos.events.os.source);
+  aos.events.io.flagsSignalPd = evtFlagsPd;
+  aos.events.io.flagsSignalSync = evtFlagsSync;
+  ssmObjectInit(aos.ssm);
+
+  // setup external interrupt system
+  extCfg->channels[gpioPd->gpio->pad].cb = _signalPdCallback;
+  extCfg->channels[gpioSync->gpio->pad].cb = _signalSyncCallback;
+  extStart(extDrv, extCfg);
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  // init shell
+  aosShellInit(aos.shell,
+               (BaseSequentialStream*)aos.ssm,
+               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
+#else
+  (void)shellPrompt;
+#endif
+
+  return;
+}
+
+/**
+ * @brief   Starts the system and all system threads.
+ */
+inline void aosSysStart(void)
+{
+  // update the system SSSP stage
+  aos.ssspStage = AOS_SSSP_OPERATION;
+
+  // prin system information
+  _printSystemInfo(AOS_SYSTEM_STDIO);
+  aosprintf("\n");
+
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  // start system shell thread
+  aos.shell->thread = chThdCreateStatic(_shell_wa, sizeof(_shell_wa), THD_LOWPRIO_MIN, 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.ssspStage = AOS_SSSP_STARTUP_2_2;
+
+  // deactivate the sync signal to indicate that the module is ready (SSSPv1 stage 2.1 of startup phase)
+  apalControlGpioSet(_gpioSync, 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(_gpioSync, &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 == aos.events.io.flagsSignalSync &&
+      s == APAL_GPIO_OFF) {
+    chSysLock();
+#if (AMIROOS_CFG_SSSP_MASTER == true)
+    // start the systen synchronization counter
+    chVTSetI(&_syssynctimer, LL_US2ST(AMIROOS_CFG_SSSP_SYSSYNCPERIOD / 2), &_sysSyncTimerCallback, NULL);
+#endif
+    // 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 + LL_ST2US(chVTGetSystemTimeX() - _synctime);
+
+  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.ssspStage = 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(_gpioPd, APAL_GPIO_ON);
+  }
+  // activate the SYS_SYNC signal
+  apalControlGpioSet(_gpioSync, APAL_GPIO_ON);
+  chSysUnlock();
+
+  switch (shutdown) {
+    case AOS_SHUTDOWN_PASSIVE:
+      aosprintf("shutdown request received...\n");
+      break;
+    case AOS_SHUTDOWN_HIBERNATE:
+      aosprintf("shutdown to hibernate mode...\n");
+      break;
+    case AOS_SHUTDOWN_DEEPSLEEP:
+      aosprintf("shutdown to deepsleep mode...\n");
+      break;
+    case AOS_SHUTDOWN_TRANSPORTATION:
+      aosprintf("shutdown to transportation mode...\n");
+      break;
+    case AOS_SHUTDOWN_RESTART:
+      aosprintf("restarting system...\n");
+      break;
+   // must never occur
+   case AOS_SHUTDOWN_NONE:
+   default:
+      break;
+  }
+
+  // update the system SSSP stage
+  aos.ssspStage = 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)
+  chThdTerminate(aos.shell->thread);
+#endif
+
+  return;
+}
+
+/**
+ * @brief   Deinitialize all system variables.
+ */
+void aosSysDeinit(void)
+{
+  aos.ssm->input = NULL;
+
+  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] extDrv      Pointer to the interrupt driver.
+ * @param[in] shutdown    Type of shutdown.
+ */
+void aosSysShutdownFinal(EXTDriver* extDrv, aos_shutdown_t shutdown)
+{
+  // check arguments
+  aosDbgCheck(extDrv != NULL);
+  aosDbgCheck(shutdown != AOS_SHUTDOWN_NONE);
+
+  // stop external interrupt system
+  extStop(extDrv);
+
+  // update the system SSSP stage
+  aos.ssspStage = 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
new file mode 100644
index 0000000..3a460ce
--- /dev/null
+++ b/os/core/src/aos_thread.c
@@ -0,0 +1,50 @@
+/*
+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 <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) > THD_MAX_SLEEP_US) ) {
+    chThdSleepS(US2ST(THD_MAX_SLEEP_US));
+    aosSysGetUptimeX(&uptime);
+  }
+
+  // sleep the remaining time
+  if (*t > uptime) {
+    systime_t rest = US2ST(*t - uptime);
+    if (rest > TIME_IMMEDIATE) {
+      chThdSleepS(rest);
+    }
+  }
+
+  return;
+}
diff --git a/os/core/src/aos_timer.c b/os/core/src/aos_timer.c
new file mode 100644
index 0000000..0c8e505
--- /dev/null
+++ b/os/core/src/aos_timer.c
@@ -0,0 +1,285 @@
+/*
+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 <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) > TIMER_MAX_INTERVAL_US) {
+      chVTSetI(&(timer->vt), US2ST(TIMER_MAX_INTERVAL_US), _intermediateCb, timer);
+    } else {
+      chVTSetI(&(timer->vt), US2ST(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
new file mode 100644
index 0000000..bee7850
--- /dev/null
+++ b/os/core/src/aos_unittest.c
@@ -0,0 +1,265 @@
+/*
+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 <aos_unittest.h>
+
+#include <aos_debug.h>
+#include <chprintf.h>
+#include <string.h>
+
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+
+/**
+ * @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/core/src/main.c b/os/core/src/main.c
new file mode 100644
index 0000000..136e54f
--- /dev/null
+++ b/os/core/src/main.c
@@ -0,0 +1,414 @@
+/*
+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 <hal.h>
+#include <ch.h>
+#include <amiroos.h>
+
+/**
+ * @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   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   SSM output for the programmer interface.
+ */
+static ssm_output_t _ssmProgIfOutput;
+#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(eventmask_t mask, eventflags_t flags)
+{
+  aosprintf("unexpected/unknown event recieved. mask: 0x%08X; flags: 0x%08X\n", mask, flags);
+  return;
+}
+
+/**
+ * @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_VARIABLES)
+  AMIROOS_CFG_MAIN_EXTRA_VARIABLES
+#endif
+
+  /*
+   * ##########################################################################
+   * # system initialization                                                  #
+   * ##########################################################################
+   */
+
+#if defined(AMIROOS_CFG_MAIN_INIT_HOOK_0)
+  AMIROOS_CFG_MAIN_INIT_HOOK_0();
+#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)
+  aosSysInit(&MODULE_HAL_EXT,
+             &moduleHalExtConfig,
+             &moduleSsspPd,
+             &moduleSsspSync,
+             MODULE_OS_IOEVENTFLAGS_SYSPD,
+             MODULE_OS_IOEVENTFLAGS_SYSSYNC,
+             moduleShellPrompt);
+#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 no 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 */
+  chEvtRegisterMask(&aos.events.io.source, &_eventListenerIO, IOEVENT_MASK);
+  chEvtRegisterMask(&aos.events.os.source, &_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
+  ssmOutputInit(&_ssmProgIfOutput, (BaseSequentialStream*)&MODULE_HAL_PROGIF);
+  ssmAddOutput(aos.ssm, &_ssmProgIfOutput);
+  ssmEnableOutput(aos.ssm, _ssmProgIfOutput.stream);
+  ssmSetInput(aos.ssm, (BaseSequentialStream*)&MODULE_HAL_PROGIF);
+#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 outro (end of startup stage 2) synchronization */
+  while ((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).
+     */
+    // unexpected IO events
+    if (eventmask & _eventListenerIO.events) {
+      eventflags = chEvtGetAndClearFlags(&_eventListenerIO);
+#ifdef MODULE_SSP_STARTUP_OUTRO_IO_EVENT
+      MODULE_SSP_STARTUP_OUTRO_IO_EVENT(eventmask, eventflags);
+#else
+      _unexpectedEventError(eventmask, eventflags);
+#endif
+    }
+    // unexpected OS event
+    else if (eventmask & _eventListenerOS.events) {
+      eventflags = chEvtGetAndClearFlags(&_eventListenerOS);
+      _unexpectedEventError(eventmask, eventflags);
+    }
+#if (AMIROOS_CFG_DBG == true)
+    // unknown event (must never occur, thus disabled for release builds)
+    else {
+      eventflags = 0;
+      _unexpectedEventError(eventmask, eventflags);
+    }
+#endif
+  }
+
+#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 */
+  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, US2ST_LLD(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_OS_IOEVENTFLAGS_SYSPD) {
+          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(&MODULE_HAL_EXT, 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/doc/Doxyfile b/os/doc/Doxyfile
new file mode 100644
index 0000000..c8b4e9a
--- /dev/null
+++ b/os/doc/Doxyfile
@@ -0,0 +1,2479 @@
+# 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                  = ../periphery-lld
+
+# 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/hal/hal.mk b/os/hal/hal.mk
new file mode 100644
index 0000000..7c3f38f
--- /dev/null
+++ b/os/hal/hal.mk
@@ -0,0 +1,34 @@
+################################################################################
+# 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
+HAL_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# add include path
+HALINC += $(HAL_DIR)include
+
+# add sources
+HALSRC += $(HAL_DIR)src/hal_qei.c
+
diff --git a/os/hal/include/hal_qei.h b/os/hal/include/hal_qei.h
new file mode 100644
index 0000000..aef5e62
--- /dev/null
+++ b/os/hal/include/hal_qei.h
@@ -0,0 +1,148 @@
+/*
+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    hal_qei.h
+ * @brief   QEI Driver macros and structures.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#ifndef _HAL_QEI_H_
+#define _HAL_QEI_H_
+
+#if HAL_USE_QEI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Driver state machine possible states.
+ */
+typedef enum {
+  QEI_UNINIT = 0,                   /**< Not initialized.                   */
+  QEI_STOP = 1,                     /**< Stopped.                           */
+  QEI_READY = 2,                    /**< Ready.                             */
+  QEI_ACTIVE = 4,                   /**< Active.                            */
+} qeistate_t;
+
+/**
+ * @brief   Type of a structure representing an QEI driver.
+ */
+typedef struct QEIDriver QEIDriver;
+
+#include "hal_qei_lld.h"
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/**
+ * @name    Macro Functions
+ * @{
+ */
+/**
+ * @brief   Enables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @iclass
+ */
+#define qeiEnableI(qeip) qei_lld_enable(qeip)
+
+/**
+ * @brief   Disables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @iclass
+ */
+#define qeiDisableI(qeip) qei_lld_disable(qeip)
+
+/**
+ * @brief   Returns the direction of the last transition.
+ * @details The direction is defined as boolean and is
+ *          calculated at each transition on any input.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The request direction.
+ * @retval FALSE        Position counted up.
+ * @retval TRUE         Position counted down.
+ * @iclass
+ */
+#define qeiGetDirectionI(qeip) qei_lld_get_direction(qeip)
+
+/**
+ * @brief   Returns the position of the encoder.
+ * @details The position is defined as number of pulses since last reset.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qeiGetPositionI(qeip) qei_lld_get_position(qeip)
+
+/**
+ * @brief   Returns the range of the encoder.
+ * @details The range is defined as number of maximum pulse count.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qeiGetRangeI(qeip) qei_lld_get_range(qeip)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void qeiInit(void);
+  void qeiObjectInit(QEIDriver *qeip);
+  void qeiStart(QEIDriver *qeip, const QEIConfig *config);
+  void qeiStop(QEIDriver *qeip);
+  void qeiEnable(QEIDriver *qeip);
+  void qeiDisable(QEIDriver *qeip);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_QEI */
+
+#endif /* _HAL_QEI_H_ */
+
+/** @} */
diff --git a/os/hal/ports/STM32/LLD/QEIv1/hal_qei_lld.c b/os/hal/ports/STM32/LLD/QEIv1/hal_qei_lld.c
new file mode 100644
index 0000000..0d0f739
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/QEIv1/hal_qei_lld.c
@@ -0,0 +1,302 @@
+/*
+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    STM32/hal_qei_lld.c
+ * @brief   STM32 QEI subsystem low level driver.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#include "hal.h"
+
+#include "hal_qei.h"
+
+#if HAL_USE_QEI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   QEID1 driver identifier.
+ * @note    The driver QEID1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_QEI_USE_TIM1 || defined(__DOXYGEN__)
+QEIDriver QEID1;
+#endif
+
+/**
+ * @brief   QEID2 driver identifier.
+ * @note    The driver QEID1 allocates the timer TIM2 when enabled.
+ */
+#if STM32_QEI_USE_TIM2 || defined(__DOXYGEN__)
+QEIDriver QEID2;
+#endif
+
+/**
+ * @brief   QEID3 driver identifier.
+ * @note    The driver QEID1 allocates the timer TIM3 when enabled.
+ */
+#if STM32_QEI_USE_TIM3 || defined(__DOXYGEN__)
+QEIDriver QEID3;
+#endif
+
+/**
+ * @brief   QEID4 driver identifier.
+ * @note    The driver QEID4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_QEI_USE_TIM4 || defined(__DOXYGEN__)
+QEIDriver QEID4;
+#endif
+
+/**
+ * @brief   QEID5 driver identifier.
+ * @note    The driver QEID5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_QEI_USE_TIM5 || defined(__DOXYGEN__)
+QEIDriver QEID5;
+#endif
+
+/**
+ * @brief   QEID8 driver identifier.
+ * @note    The driver QEID8 allocates the timer TIM8 when enabled.
+ */
+#if STM32_QEI_USE_TIM8 || defined(__DOXYGEN__)
+QEIDriver QEID8;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver interrupt handlers.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   Low level QEI driver initialization.
+ *
+ * @notapi
+ */
+void qei_lld_init(void) {
+
+#if STM32_QEI_USE_TIM1
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID1);
+  QEID1.tim = STM32_TIM1;
+#endif
+
+#if STM32_QEI_USE_TIM2
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID2);
+  QEID2.tim = STM32_TIM2;
+#endif
+
+#if STM32_QEI_USE_TIM3
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID3);
+  QEID3.tim = STM32_TIM3;
+#endif
+
+#if STM32_QEI_USE_TIM4
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID4);
+  QEID4.tim = STM32_TIM4;
+#endif
+
+#if STM32_QEI_USE_TIM5
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID5);
+  QEID5.tim = STM32_TIM5;
+#endif
+
+#if STM32_QEI_USE_TIM8
+  /* Driver initialization.*/
+  qeiObjectInit(&QEID8);
+  QEID8.tim = STM32_TIM8;
+#endif
+}
+
+/**
+ * @brief   Configures and activates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_start(QEIDriver *qeip) {
+  uint32_t arr, ccer;
+
+  if (qeip->state == QEI_STOP) {
+    /* Clock activation and timer reset.*/
+#if STM32_QEI_USE_TIM1
+    if (&QEID1 == qeip) {
+      rccEnableTIM1(FALSE);
+      rccResetTIM1();
+    }
+#endif
+#if STM32_QEI_USE_TIM2
+    if (&QEID2 == qeip) {
+      rccEnableTIM2(FALSE);
+      rccResetTIM2();
+    }
+#endif
+#if STM32_QEI_USE_TIM3
+    if (&QEID3 == qeip) {
+      rccEnableTIM3(FALSE);
+      rccResetTIM3();
+    }
+#endif
+#if STM32_QEI_USE_TIM4
+    if (&QEID4 == qeip) {
+      rccEnableTIM4(FALSE);
+      rccResetTIM4();
+    }
+#endif
+
+#if STM32_QEI_USE_TIM5
+    if (&QEID5 == qeip) {
+      rccEnableTIM5(FALSE);
+      rccResetTIM5();
+    }
+#endif
+#if STM32_QEI_USE_TIM8
+    if (&QEID8 == qeip) {
+      rccEnableTIM8(FALSE);
+      rccResetTIM8();
+    }
+#endif
+  }
+  else {
+    /* Driver re-configuration scenario, it must be stopped first.*/
+    qeip->tim->CR1    = 0;                  /* Timer disabled.              */
+    qeip->tim->DIER   = 0;                  /* All IRQs disabled.           */
+    qeip->tim->SR     = 0;                  /* Clear eventual pending IRQs. */
+    qeip->tim->CCR[0] = 0;                  /* Comparator 1 disabled.       */
+    qeip->tim->CCR[1] = 0;                  /* Comparator 2 disabled.       */
+    qeip->tim->CNT    = 0;                  /* Counter reset to zero.       */
+  }
+
+  /* Timer configuration.*/
+  qeip->tim->PSC  = 0;
+  arr = qeip->config->range - 1;
+  osalDbgAssert((arr <= 0xFFFF), "qei_lld_start(), #1" /*, "invalid range"*/);
+  qeip->tim->ARR  = arr & 0xFFFF;
+
+  /* CCMR1_CC1S = 01 - CH1 Input on TI1.
+     CCMR1_CC2S = 01 - CH2 Input on TI2.*/
+  qeip->tim->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
+
+  ccer = 0;
+  if (qeip->config->channels[0].mode == QEI_INPUT_INVERTED)
+    ccer |= TIM_CCER_CC1P;
+  if (qeip->config->channels[1].mode == QEI_INPUT_INVERTED)
+    ccer |= TIM_CCER_CC2P;
+  qeip->tim->CCER = ccer;
+
+  if (qeip->config->mode == QEI_COUNT_CH1)
+    qeip->tim->SMCR  = TIM_SMCR_SMS_1;
+  else if (qeip->config->mode == QEI_COUNT_CH2)
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0;
+  else
+    qeip->tim->SMCR  = TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
+}
+
+/**
+ * @brief   Deactivates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_stop(QEIDriver *qeip) {
+
+  if (qeip->state == QEI_READY) {
+    /* Clock deactivation.*/
+    qeip->tim->CR1  = 0;                    /* Timer disabled.              */
+
+#if STM32_QEI_USE_TIM1
+    if (&QEID1 == qeip) {
+      rccDisableTIM1(FALSE);
+    }
+#endif
+#if STM32_QEI_USE_TIM2
+    if (&QEID2 == qeip) {
+      rccDisableTIM2(FALSE);
+    }
+#endif
+#if STM32_QEI_USE_TIM3
+    if (&QEID3 == qeip) {
+      rccDisableTIM3(FALSE);
+    }
+#endif
+#if STM32_QEI_USE_TIM4
+    if (&QEID4 == qeip) {
+      rccDisableTIM4(FALSE);
+    }
+#endif
+#if STM32_QEI_USE_TIM5
+    if (&QEID5 == qeip) {
+      rccDisableTIM5(FALSE);
+    }
+#endif
+  }
+#if STM32_QEI_USE_TIM8
+    if (&QEID8 == qeip) {
+      rccDisableTIM8(FALSE);
+    }
+#endif
+}
+
+/**
+ * @brief   Enables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_enable(QEIDriver *qeip) {
+
+  qeip->tim->CR1  = TIM_CR1_CEN;
+}
+
+/**
+ * @brief   Disables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @notapi
+ */
+void qei_lld_disable(QEIDriver *qeip) {
+
+  qeip->tim->CR1  = 0;
+}
+
+#endif /* HAL_USE_QEI */
+
+/** @} */
diff --git a/os/hal/ports/STM32/LLD/QEIv1/hal_qei_lld.h b/os/hal/ports/STM32/LLD/QEIv1/hal_qei_lld.h
new file mode 100644
index 0000000..d4b7acc
--- /dev/null
+++ b/os/hal/ports/STM32/LLD/QEIv1/hal_qei_lld.h
@@ -0,0 +1,302 @@
+/*
+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    STM32/hal_qei_lld.h
+ * @brief   STM32 QEI subsystem low level driver header.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#ifndef _HAL_QEI_LLD_H_
+#define _HAL_QEI_LLD_H_
+
+#include "stm32_tim.h"
+
+#if HAL_USE_QEI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants.                                                         */
+/*===========================================================================*/
+
+/**
+ * @brief   Number of input channels per QEI driver.
+ */
+#define QEI_CHANNELS                            2
+
+/*===========================================================================*/
+/* Driver pre-compile time settings.                                         */
+/*===========================================================================*/
+
+/**
+ * @name    Configuration options
+ * @{
+ */
+/**
+ * @brief   QEID1 driver enable switch.
+ * @details If set to @p TRUE the support for QEID1 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM1                  TRUE
+#endif
+
+/**
+ * @brief   QEID2 driver enable switch.
+ * @details If set to @p TRUE the support for QEID2 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM2                  TRUE
+#endif
+
+/**
+ * @brief   QEID3 driver enable switch.
+ * @details If set to @p TRUE the support for QEID3 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM3                  TRUE
+#endif
+
+/**
+ * @brief   QEID4 driver enable switch.
+ * @details If set to @p TRUE the support for QEID4 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM4                  TRUE
+#endif
+
+/**
+ * @brief   QEID5 driver enable switch.
+ * @details If set to @p TRUE the support for QEID5 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM5                  TRUE
+#endif
+
+/**
+ * @brief   QEID8 driver enable switch.
+ * @details If set to @p TRUE the support for QEID8 is included.
+ * @note    The default is @p TRUE.
+ */
+#if !defined(STM32_QEI_USE_TIM8) || defined(__DOXYGEN__)
+#define STM32_QEI_USE_TIM8                  TRUE
+#endif
+/** @} */
+
+/*===========================================================================*/
+/* Derived constants and error checks.                                       */
+/*===========================================================================*/
+
+#if STM32_QEI_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if STM32_QEI_USE_TIM8 && !STM32_HAS_TIM8
+#error "TIM8 not present in the selected device"
+#endif
+
+#if !STM32_QEI_USE_TIM1 && !STM32_QEI_USE_TIM2 &&                           \
+    !STM32_QEI_USE_TIM3 && !STM32_QEI_USE_TIM4 &&                           \
+    !STM32_QEI_USE_TIM5 && !STM32_QEI_USE_TIM8
+#error "QEI driver activated but no TIM peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types.                                         */
+/*===========================================================================*/
+
+/**
+ * @brief QEI driver mode.
+ */
+typedef enum {
+  QEI_COUNT_BOTH = 0,
+  QEI_COUNT_CH1 = 1,
+  QEI_COUNT_CH2 = 2,
+} qeimode_t;
+
+/**
+ * @brief QEI input mode.
+ */
+typedef enum {
+  QEI_INPUT_NONINVERTED = 0, /**< Input channel noninverted.*/
+  QEI_INPUT_INVERTED = 1, /**< Input channel inverted.*/
+} qeiinputmode_t;
+
+/**
+ * @brief   QEI count type.
+ */
+typedef uint32_t qeicnt_t;
+
+/**
+ * @brief   Driver channel configuration structure.
+ */
+typedef struct {
+  /**
+   * @brief Channel input logic.
+   */
+  qeiinputmode_t                 mode;
+  /* End of the mandatory fields.*/
+} QEIChannelConfig;
+
+/**
+ * @brief   Driver configuration structure.
+ */
+typedef struct {
+  /**
+   * @brief   Driver mode.
+   */
+  qeimode_t                 mode;
+  /**
+   * @brief   Channels configurations.
+   */
+  QEIChannelConfig          channels[QEI_CHANNELS];
+  /**
+   * @brief   Range in pulses.
+   */
+  qeicnt_t                  range;
+  /* End of the mandatory fields.*/
+} QEIConfig;
+
+/**
+ * @brief   Structure representing an QEI driver.
+ */
+struct QEIDriver {
+  /**
+   * @brief Driver state.
+   */
+  qeistate_t                state;
+  /**
+   * @brief Current configuration data.
+   */
+  const QEIConfig           *config;
+#if defined(QEI_DRIVER_EXT_FIELDS)
+  QEI_DRIVER_EXT_FIELDS
+#endif
+  /* End of the mandatory fields.*/
+  /**
+   * @brief Pointer to the TIMx registers block.
+   */
+  stm32_tim_t               *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros.                                                            */
+/*===========================================================================*/
+
+/**
+ * @brief   Returns the direction of the last transition.
+ * @details The direction is defined as boolean and is
+ *          calculated at each transition on any input.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The request direction.
+ * @retval FALSE        Position counted up.
+ * @retval TRUE         Position counted down.
+ *
+ * @iclass
+ */
+#define qei_lld_get_direction(qeip) !!((qeip)->tim->CR1 & TIM_CR1_DIR)
+
+/**
+ * @brief   Returns the position of the encoder.
+ * @details The position is defined as number of pulses since last reset.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qei_lld_get_position(qeip) ((qeip)->tim->CNT)
+
+/**
+ * @brief   Returns the range of the encoder.
+ * @details The range is defined as number of maximum pulse count.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @return              The number of pulses.
+ *
+ * @iclass
+ */
+#define qei_lld_get_range(qeip) ((qeip)->tim->ARR + 1)
+
+/*===========================================================================*/
+/* External declarations.                                                    */
+/*===========================================================================*/
+
+#if STM32_QEI_USE_TIM1 && !defined(__DOXYGEN__)
+extern QEIDriver QEID1;
+#endif
+
+#if STM32_QEI_USE_TIM2 && !defined(__DOXYGEN__)
+extern QEIDriver QEID2;
+#endif
+
+#if STM32_QEI_USE_TIM3 && !defined(__DOXYGEN__)
+extern QEIDriver QEID3;
+#endif
+
+#if STM32_QEI_USE_TIM4 && !defined(__DOXYGEN__)
+extern QEIDriver QEID4;
+#endif
+
+#if STM32_QEI_USE_TIM5 && !defined(__DOXYGEN__)
+extern QEIDriver QEID5;
+#endif
+
+#if STM32_QEI_USE_TIM8 && !defined(__DOXYGEN__)
+extern QEIDriver QEID8;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void qei_lld_init(void);
+  void qei_lld_start(QEIDriver *qeip);
+  void qei_lld_stop(QEIDriver *qeip);
+  void qei_lld_enable(QEIDriver *qeip);
+  void qei_lld_disable(QEIDriver *qeip);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_QEI */
+
+#endif /* _HAL_QEI_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/ports/STM32/platform.mk b/os/hal/ports/STM32/platform.mk
new file mode 100644
index 0000000..142e658
--- /dev/null
+++ b/os/hal/ports/STM32/platform.mk
@@ -0,0 +1,34 @@
+################################################################################
+# 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
+PLATFORM_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# add include path
+PLATFORMINC += $(PLATFORM_DIR)LLD/QEIv1/
+
+# add C sources
+PLATFORMSRC += $(PLATFORM_DIR)LLD/QEIv1/hal_qei_lld.c
+
diff --git a/os/hal/ports/STM32F103xE.ld b/os/hal/ports/STM32F103xE.ld
new file mode 100644
index 0000000..48c7de1
--- /dev/null
+++ b/os/hal/ports/STM32F103xE.ld
@@ -0,0 +1,87 @@
+/*
+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/>.
+*/
+
+/*
+ * ST32F103xE memory setup.
+ */
+MEMORY
+{
+    flash0  : org = 0x08006000, len = 512k-24k
+    flash1  : org = 0x00000000, len = 0
+    flash2  : org = 0x00000000, len = 0
+    flash3  : org = 0x00000000, len = 0
+    flash4  : org = 0x00000000, len = 0
+    flash5  : org = 0x00000000, len = 0
+    flash6  : org = 0x00000000, len = 0
+    flash7  : org = 0x00000000, len = 0
+    ram0    : org = 0x20000000, len = 64k
+    ram1    : org = 0x00000000, len = 0
+    ram2    : org = 0x00000000, len = 0
+    ram3    : org = 0x00000000, len = 0
+    ram4    : org = 0x00000000, len = 0
+    ram5    : org = 0x00000000, len = 0
+    ram6    : org = 0x00000000, len = 0
+    ram7    : org = 0x00000000, len = 0
+}
+
+/* For each data/text section two region are defined, a virtual region
+   and a load region (_LMA suffix).*/
+
+/* Flash region to be used for exception vectors.*/
+REGION_ALIAS("VECTORS_FLASH", flash0);
+REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for constructors and destructors.*/
+REGION_ALIAS("XTORS_FLASH", flash0);
+REGION_ALIAS("XTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for code text.*/
+REGION_ALIAS("TEXT_FLASH", flash0);
+REGION_ALIAS("TEXT_FLASH_LMA", flash0);
+
+/* Flash region to be used for read only data.*/
+REGION_ALIAS("RODATA_FLASH", flash0);
+REGION_ALIAS("RODATA_FLASH_LMA", flash0);
+
+/* Flash region to be used for various.*/
+REGION_ALIAS("VARIOUS_FLASH", flash0);
+REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
+
+/* Flash region to be used for RAM(n) initialization data.*/
+REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
+
+/* RAM region to be used for Main stack. This stack accommodates the processing
+   of all exceptions and interrupts.*/
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
+
+/* RAM region to be used for the process stack. This is the stack used by
+   the main() function.*/
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
+
+/* RAM region to be used for data segment.*/
+REGION_ALIAS("DATA_RAM", ram0);
+REGION_ALIAS("DATA_RAM_LMA", flash0);
+
+/* RAM region to be used for BSS segment.*/
+REGION_ALIAS("BSS_RAM", ram0);
+
+/* RAM region to be used for the default heap.*/
+REGION_ALIAS("HEAP_RAM", ram0);
+
+/* Generic rules inclusion.*/
+INCLUDE rules.ld
diff --git a/os/hal/ports/STM32F405xG.ld b/os/hal/ports/STM32F405xG.ld
new file mode 100644
index 0000000..14d0805
--- /dev/null
+++ b/os/hal/ports/STM32F405xG.ld
@@ -0,0 +1,88 @@
+/*
+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/>.
+*/
+
+/*
+ * STM32F405xG memory setup.
+ * Note: Use of ram1 and ram2 is mutually exclusive with use of ram0.
+ */
+MEMORY
+{
+    flash0  : org = 0x08008000, len = 1M-32k
+    flash1  : org = 0x00000000, len = 0
+    flash2  : org = 0x00000000, len = 0
+    flash3  : org = 0x00000000, len = 0
+    flash4  : org = 0x00000000, len = 0
+    flash5  : org = 0x00000000, len = 0
+    flash6  : org = 0x00000000, len = 0
+    flash7  : org = 0x00000000, len = 0
+    ram0    : org = 0x20000000, len = 128k      /* SRAM1 + SRAM2 */
+    ram1    : org = 0x20000000, len = 112k      /* SRAM1 */
+    ram2    : org = 0x2001C000, len = 16k       /* SRAM2 */
+    ram3    : org = 0x00000000, len = 0
+    ram4    : org = 0x10000000, len = 64k       /* CCM SRAM */
+    ram5    : org = 0x40024000, len = 4k        /* BCKP SRAM */
+    ram6    : org = 0x00000000, len = 0
+    ram7    : org = 0x00000000, len = 0
+}
+
+/* For each data/text section two region are defined, a virtual region
+   and a load region (_LMA suffix).*/
+
+/* Flash region to be used for exception vectors.*/
+REGION_ALIAS("VECTORS_FLASH", flash0);
+REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for constructors and destructors.*/
+REGION_ALIAS("XTORS_FLASH", flash0);
+REGION_ALIAS("XTORS_FLASH_LMA", flash0);
+
+/* Flash region to be used for code text.*/
+REGION_ALIAS("TEXT_FLASH", flash0);
+REGION_ALIAS("TEXT_FLASH_LMA", flash0);
+
+/* Flash region to be used for read only data.*/
+REGION_ALIAS("RODATA_FLASH", flash0);
+REGION_ALIAS("RODATA_FLASH_LMA", flash0);
+
+/* Flash region to be used for various.*/
+REGION_ALIAS("VARIOUS_FLASH", flash0);
+REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
+
+/* Flash region to be used for RAM(n) initialization data.*/
+REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
+
+/* RAM region to be used for Main stack. This stack accommodates the processing
+   of all exceptions and interrupts.*/
+REGION_ALIAS("MAIN_STACK_RAM", ram0);
+
+/* RAM region to be used for the process stack. This is the stack used by
+   the main() function.*/
+REGION_ALIAS("PROCESS_STACK_RAM", ram0);
+
+/* RAM region to be used for data segment.*/
+REGION_ALIAS("DATA_RAM", ram0);
+REGION_ALIAS("DATA_RAM_LMA", flash0);
+
+/* RAM region to be used for BSS segment.*/
+REGION_ALIAS("BSS_RAM", ram0);
+
+/* RAM region to be used for the default heap.*/
+REGION_ALIAS("HEAP_RAM", ram0);
+
+/* Generic rules inclusion.*/
+INCLUDE rules.ld
diff --git a/os/hal/ports/rules.ld b/os/hal/ports/rules.ld
new file mode 100644
index 0000000..9df8fbe
--- /dev/null
+++ b/os/hal/ports/rules.ld
@@ -0,0 +1,27 @@
+/*
+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/>.
+*/
+
+/* Stack rules inclusion.*/
+INCLUDE rules_stacks.ld
+
+/* Code rules inclusion.*/
+INCLUDE rules_code.ld
+
+/* Data rules inclusion.*/
+INCLUDE rules_data.ld
+
diff --git a/os/hal/ports/rules.mk b/os/hal/ports/rules.mk
new file mode 100644
index 0000000..45dde0a
--- /dev/null
+++ b/os/hal/ports/rules.mk
@@ -0,0 +1,26 @@
+# ARM Cortex-Mx common makefile scripts and rules.
+
+##############################################################################
+# Processing options coming from the upper Makefile.
+#
+
+# Output directory and files
+SRECFILE = $(BUILDDIR)/$(PROJECT).srec
+
+#
+# Makefile rules
+#
+
+blt: $(SRECFILE)
+
+MAKE_ALL_RULE_HOOK: blt
+
+%.srec: %.elf $(LDSCRIPT)
+ifeq ($(USE_VERBOSE_COMPILE),yes)
+	$(SREC) $< $@
+else
+	@echo Creating $@
+	@$(SREC) $< $@
+endif
+
+# *** EOF ***
diff --git a/os/hal/ports/rules_code.ld b/os/hal/ports/rules_code.ld
new file mode 100644
index 0000000..5c47ca4
--- /dev/null
+++ b/os/hal/ports/rules_code.ld
@@ -0,0 +1,80 @@
+/*
+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/>.
+*/
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+    .vectors : ALIGN(16)
+    {
+        KEEP(*(.vectors))
+    } > VECTORS_FLASH AT > VECTORS_FLASH_LMA
+
+    .xtors : ALIGN(4)
+    {
+        __init_array_start = .;
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        __init_array_end = .;
+        __fini_array_start = .;
+        KEEP(*(.fini_array))
+        KEEP(*(SORT(.fini_array.*)))
+        __fini_array_end = .;
+    } > XTORS_FLASH AT > XTORS_FLASH_LMA
+
+    .text ALIGN(16) : ALIGN(16)
+    {
+        *(.text)
+        *(.text.*)
+        *(.glue_7t)
+        *(.glue_7)
+        *(.gcc*)
+    } > TEXT_FLASH AT > TEXT_FLASH_LMA
+
+    .rodata : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __rodata_base__ = .;
+        *(.rodata)
+        *(.rodata.*)
+        . = ALIGN(4);
+        __rodata_end__ = .;
+    } > RODATA_FLASH AT > RODATA_FLASH_LMA
+
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > VARIOUS_FLASH AT > VARIOUS_FLASH_LMA
+
+    .ARM.exidx : {
+        __exidx_start = .;
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+        __exidx_end = .;
+     } > VARIOUS_FLASH AT > VARIOUS_FLASH_LMA
+
+    .eh_frame_hdr :
+    {
+        *(.eh_frame_hdr)
+    } > VARIOUS_FLASH AT > VARIOUS_FLASH_LMA
+
+    .eh_frame : ONLY_IF_RO
+    {
+        *(.eh_frame)
+    } > VARIOUS_FLASH AT > VARIOUS_FLASH_LMA
+}
+
diff --git a/os/hal/ports/rules_data.ld b/os/hal/ports/rules_data.ld
new file mode 100644
index 0000000..74c7530
--- /dev/null
+++ b/os/hal/ports/rules_data.ld
@@ -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/>.
+*/
+
+__ram0_start__          = ORIGIN(ram0);
+__ram0_size__           = LENGTH(ram0);
+__ram0_end__            = __ram0_start__ + __ram0_size__;
+__ram1_start__          = ORIGIN(ram1);
+__ram1_size__           = LENGTH(ram1);
+__ram1_end__            = __ram1_start__ + __ram1_size__;
+__ram2_start__          = ORIGIN(ram2);
+__ram2_size__           = LENGTH(ram2);
+__ram2_end__            = __ram2_start__ + __ram2_size__;
+__ram3_start__          = ORIGIN(ram3);
+__ram3_size__           = LENGTH(ram3);
+__ram3_end__            = __ram3_start__ + __ram3_size__;
+__ram4_start__          = ORIGIN(ram4);
+__ram4_size__           = LENGTH(ram4);
+__ram4_end__            = __ram4_start__ + __ram4_size__;
+__ram5_start__          = ORIGIN(ram5);
+__ram5_size__           = LENGTH(ram5);
+__ram5_end__            = __ram5_start__ + __ram5_size__;
+__ram6_start__          = ORIGIN(ram6);
+__ram6_size__           = LENGTH(ram6);
+__ram6_end__            = __ram6_start__ + __ram6_size__;
+__ram7_start__          = ORIGIN(ram7);
+__ram7_size__           = LENGTH(ram7);
+__ram7_end__            = __ram7_start__ + __ram7_size__;
+
+ENTRY(Reset_Handler)
+
+SECTIONS
+{
+    .data : ALIGN(4)
+    {
+        . = ALIGN(4);
+        PROVIDE(_textdata = LOADADDR(.data));
+        PROVIDE(_data = .);
+        _textdata_start = LOADADDR(.data);
+        _data_start = .;
+        *(.data)
+        *(.data.*)
+        *(.ramtext)
+        . = ALIGN(4);
+        PROVIDE(_edata = .);
+        _data_end = .;
+    } > DATA_RAM AT > DATA_RAM_LMA
+
+    .bss (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        _bss_start = .;
+        *(.bss)
+        *(.bss.*)
+        *(COMMON)
+        . = ALIGN(4);
+        _bss_end = .;
+        PROVIDE(end = .);
+    } > BSS_RAM
+
+    .ram0_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram0_init_text__ = LOADADDR(.ram0_init);
+        __ram0_init__ = .;
+        KEEP(*(.ram0_init))
+        KEEP(*(.ram0_init.*))
+        . = ALIGN(4);
+    } > ram0 AT > RAM_INIT_FLASH_LMA
+
+    .ram0 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram0_clear__ = .;
+        *(.ram0_clear)
+        *(.ram0_clear.*)
+        . = ALIGN(4);
+        __ram0_noinit__ = .;
+        *(.ram0)
+        *(.ram0.*)
+        . = ALIGN(4);
+        __ram0_free__ = .;
+    } > ram0
+
+    .ram1_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram1_init_text__ = LOADADDR(.ram1_init);
+        __ram1_init__ = .;
+        KEEP(*(.ram1_init))
+        KEEP(*(.ram1_init.*))
+        . = ALIGN(4);
+    } > ram1 AT > RAM_INIT_FLASH_LMA
+
+    .ram1 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram1_clear__ = .;
+        *(.ram1_clear)
+        *(.ram1_clear.*)
+        . = ALIGN(4);
+        __ram1_noinit__ = .;
+        *(.ram1)
+        *(.ram1.*)
+        . = ALIGN(4);
+        __ram1_free__ = .;
+    } > ram1
+
+    .ram2_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram2_init_text__ = LOADADDR(.ram2_init);
+        __ram2_init__ = .;
+        KEEP(*(.ram2_init))
+        KEEP(*(.ram2_init.*))
+        . = ALIGN(4);
+    } > ram2 AT > RAM_INIT_FLASH_LMA
+
+    .ram2 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram2_clear__ = .;
+        *(.ram2_clear)
+        *(.ram2_clear.*)
+        . = ALIGN(4);
+        __ram2_noinit__ = .;
+        *(.ram2)
+        *(.ram2.*)
+        . = ALIGN(4);
+        __ram2_free__ = .;
+    } > ram2
+
+    .ram3_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram3_init_text__ = LOADADDR(.ram3_init);
+        __ram3_init__ = .;
+        KEEP(*(.ram3_init))
+        KEEP(*(.ram3_init.*))
+        . = ALIGN(4);
+    } > ram3 AT > RAM_INIT_FLASH_LMA
+
+    .ram3 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram3_clear__ = .;
+        *(.ram3_clear)
+        *(.ram3_clear.*)
+        . = ALIGN(4);
+        __ram3_noinit__ = .;
+        *(.ram3)
+        *(.ram3.*)
+        . = ALIGN(4);
+        __ram3_free__ = .;
+    } > ram3
+
+    .ram4_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram4_init_text__ = LOADADDR(.ram4_init);
+        __ram4_init__ = .;
+        KEEP(*(.ram4_init))
+        KEEP(*(.ram4_init.*))
+        . = ALIGN(4);
+    } > ram4 AT > RAM_INIT_FLASH_LMA
+
+    .ram4 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram4_clear__ = .;
+        *(.ram4_clear)
+        *(.ram4_clear.*)
+        . = ALIGN(4);
+        __ram4_noinit__ = .;
+        *(.ram4)
+        *(.ram4.*)
+        . = ALIGN(4);
+        __ram4_free__ = .;
+    } > ram4
+
+    .ram5_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram5_init_text__ = LOADADDR(.ram5_init);
+        __ram5_init__ = .;
+        KEEP(*(.ram5_init))
+        KEEP(*(.ram5_init.*))
+        . = ALIGN(4);
+    } > ram5 AT > RAM_INIT_FLASH_LMA
+
+    .ram5 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram5_clear__ = .;
+        *(.ram5_clear)
+        *(.ram5_clear.*)
+        . = ALIGN(4);
+        __ram5_noinit__ = .;
+        *(.ram5)
+        *(.ram5.*)
+        . = ALIGN(4);
+        __ram5_free__ = .;
+    } > ram5
+
+    .ram6_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram6_init_text__ = LOADADDR(.ram6_init);
+        __ram6_init__ = .;
+        KEEP(*(.ram6_init))
+        KEEP(*(.ram6_init.*))
+        . = ALIGN(4);
+    } > ram6 AT > RAM_INIT_FLASH_LMA
+
+    .ram6 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram6_clear__ = .;
+        *(.ram6_clear)
+        *(.ram6_clear.*)
+        . = ALIGN(4);
+        __ram6_noinit__ = .;
+        *(.ram6)
+        *(.ram6.*)
+        . = ALIGN(4);
+        __ram6_free__ = .;
+    } > ram6
+
+    .ram7_init : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram7_init_text__ = LOADADDR(.ram7_init);
+        __ram7_init__ = .;
+        KEEP(*(.ram7_init))
+        KEEP(*(.ram7_init.*))
+        . = ALIGN(4);
+    } > ram7 AT > RAM_INIT_FLASH_LMA
+
+    .ram7 (NOLOAD) : ALIGN(4)
+    {
+        . = ALIGN(4);
+        __ram7_clear__ = .;
+        *(.ram7_clear)
+        *(.ram7_clear.*)
+        . = ALIGN(4);
+        __ram7_noinit__ = .;
+        *(.ram7)
+        *(.ram7.*)
+        . = ALIGN(4);
+        __ram7_free__ = .;
+    } > ram7
+
+    /* The default heap uses the (statically) unused part of a RAM section.*/
+    .heap (NOLOAD) :
+    {
+        . = ALIGN(8);
+        __heap_base__ = .;
+        . = ORIGIN(HEAP_RAM) + LENGTH(HEAP_RAM);
+        __heap_end__ = .;
+    } > HEAP_RAM
+}
+
diff --git a/os/hal/ports/rules_stacks.ld b/os/hal/ports/rules_stacks.ld
new file mode 100644
index 0000000..7e74d41
--- /dev/null
+++ b/os/hal/ports/rules_stacks.ld
@@ -0,0 +1,41 @@
+/*
+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/>.
+*/
+
+SECTIONS
+{
+    /* Special section for exceptions stack.*/
+    .mstack :
+    {
+        . = ALIGN(8);
+        __main_stack_base__ = .;
+        . += __main_stack_size__;
+        . = ALIGN(8);
+        __main_stack_end__ = .;
+    } > MAIN_STACK_RAM
+
+    /* Special section for process stack.*/
+    .pstack :
+    {
+        __process_stack_base__ = .;
+        __main_thread_stack_base__ = .;
+        . += __process_stack_size__;
+        . = ALIGN(8);
+        __process_stack_end__ = .;
+        __main_thread_stack_end__ = .;
+    } > PROCESS_STACK_RAM
+}
diff --git a/os/hal/src/hal_qei.c b/os/hal/src/hal_qei.c
new file mode 100644
index 0000000..c08d175
--- /dev/null
+++ b/os/hal/src/hal_qei.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/>.
+*/
+
+/**
+ * @file    hal_qei.c
+ * @brief   QEI Driver code.
+ *
+ * @addtogroup QEI
+ * @{
+ */
+
+#include "hal.h"
+#include "hal_qei.h"
+
+#if HAL_USE_QEI || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver local definitions.                                                 */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables.                                                */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions.                                                   */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions.                                                */
+/*===========================================================================*/
+
+/**
+ * @brief   QEI Driver initialization.
+ * @note    This function is implicitly invoked by @p halInit(), there is
+ *          no need to explicitly initialize the driver.
+ *
+ * @init
+ */
+void qeiInit(void) {
+
+  qei_lld_init();
+}
+
+/**
+ * @brief   Initializes the standard part of a @p QEIDriver structure.
+ *
+ * @param[out] qeip     pointer to the @p QEIDriver object
+ *
+ * @init
+ */
+void qeiObjectInit(QEIDriver *qeip) {
+
+  qeip->state  = QEI_STOP;
+  qeip->config = NULL;
+}
+
+/**
+ * @brief   Configures and activates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ * @param[in] config    pointer to the @p QEIConfig object
+ *
+ * @api
+ */
+void qeiStart(QEIDriver *qeip, const QEIConfig *config) {
+
+  chDbgCheck((qeip != NULL) && (config != NULL) /*, "qeiStart"*/);
+
+  chSysLock();
+  chDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY),
+              "qeiStart(), #1" /*, "invalid state"*/);
+  qeip->config = config;
+  qei_lld_start(qeip);
+  qeip->state = QEI_READY;
+  chSysUnlock();
+}
+
+/**
+ * @brief   Deactivates the QEI peripheral.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @api
+ */
+void qeiStop(QEIDriver *qeip) {
+
+  chDbgCheck(qeip != NULL /*, "qeiStop"*/);
+
+  chSysLock();
+  chDbgAssert((qeip->state == QEI_STOP) || (qeip->state == QEI_READY),
+              "qeiStop(), #1" /*, "invalid state"*/);
+  qei_lld_stop(qeip);
+  qeip->state = QEI_STOP;
+  chSysUnlock();
+}
+
+/**
+ * @brief   Enables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @api
+ */
+void qeiEnable(QEIDriver *qeip) {
+
+  chDbgCheck(qeip != NULL /*, "qeiEnable"*/);
+
+  chSysLock();
+  chDbgAssert(qeip->state == QEI_READY, "qeiEnable(), #1" /*, "invalid state"*/);
+  qei_lld_enable(qeip);
+  qeip->state = QEI_ACTIVE;
+  chSysUnlock();
+}
+
+/**
+ * @brief   Disables the quadrature encoder.
+ *
+ * @param[in] qeip      pointer to the @p QEIDriver object
+ *
+ * @api
+ */
+void qeiDisable(QEIDriver *qeip) {
+
+  chDbgCheck(qeip != NULL /*, "qeiDisable"*/);
+
+  chSysLock();
+  chDbgAssert((qeip->state == QEI_READY) || (qeip->state == QEI_ACTIVE),
+              "qeiDisable(), #1" /*, "invalid state"*/);
+  qei_lld_disable(qeip);
+  qeip->state = QEI_READY;
+  chSysUnlock();
+}
+
+#endif /* HAL_USE_QEI */
+
+/** @} */
diff --git a/os/modules/DiWheelDrive_1-1/Makefile b/os/modules/DiWheelDrive_1-1/Makefile
new file mode 100644
index 0000000..ddc544e
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/Makefile
@@ -0,0 +1,302 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+
+
+################################################################################
+# Build global options                                                         #
+# NOTE: Can be overridden externally.                                          #
+#                                                                              #
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+  USE_OPT = -O2 -fomit-frame-pointer -falign-functions=16 -fstack-usage
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+  USE_COPT = -std=c99
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+  USE_CPPOPT = -fno-rtti -std=c++14
+endif
+
+# Enable this if you want the linker to remove unused code and data
+ifeq ($(USE_LINK_GC),)
+  USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+  USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO)
+ifeq ($(USE_LTO),)
+  USE_LTO = yes
+endif
+
+# If enabled, this option allows to compile the application in THUMB mode.
+ifeq ($(USE_THUMB),)
+  USE_THUMB = yes
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+  USE_VERBOSE_COMPILE = no
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+  USE_SMART_BUILD = yes
+endif
+
+#                                                                              #
+# Build global options                                                         #
+################################################################################
+
+################################################################################
+# Architecture or project specific options                                     #
+#                                                                              #
+
+# Stack size to be allocated to the Cortex-M process stack. This stack is
+# the stack used by the main() thread.
+ifneq ($(MAIN_STACKSIZE_DIWHEELDRIVE),)
+  USE_PROCESS_STACKSIZE = $(MAIN_STACKSIZE_DIWHEELDRIVE)
+endif
+ifeq ($(USE_PROCESS_STACKSIZE),)
+  USE_PROCESS_STACKSIZE = 0x400
+endif
+
+# Stack size to the allocated to the Cortex-M main/exceptions stack. This
+# stack is used for processing interrupts and exceptions.
+ifneq ($(EXCEPTIONS_STACKSIZE_DIWHEELDRIVE),)
+  USE_PROCESS_STACKSIZE = $(EXCEPTIONS_STACKSIZE_DIWHEELDRIVE)
+endif
+ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
+  USE_EXCEPTIONS_STACKSIZE = 0x400
+endif
+
+# Enables the use of FPU on Cortex-M4.
+# Possible selections are:
+#   no     - no FPU is used (propably equals 'soft')
+#   soft   - does not use the FPU, thus all floating point operations are emulated
+#   softfp - uses the FPU, but uses the integer registers only
+#   hard   - uses the FPU and passes data via the FPU registers
+ifeq ($(USE_FPU),)
+  USE_FPU = no
+endif
+
+#                                                                              #
+# Architecture or project specific options                                     #
+################################################################################
+
+################################################################################
+# Project, sources and paths                                                   #
+#                                                                              #
+
+# Define project name here
+PROJECT := $(patsubst $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))..)/%,%,$(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
+
+# Imported source files and paths
+include ../../../kernel/kernel.mk
+CHIBIOS := $(AMIROOS_KERNEL)
+AMIROOS = ../..
+# Startup files
+include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f1xx.mk
+# HAL-OSAL files
+include $(CHIBIOS)/os/hal/hal.mk
+include $(AMIROOS)/hal/hal.mk
+include $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/platform.mk
+include $(AMIROOS)/hal/ports/STM32/platform.mk
+include ./board.mk
+include $(CHIBIOS)/os/hal/osal/rt/osal.mk
+# RTOS files
+include $(CHIBIOS)/os/rt/rt.mk
+include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
+# Other files (optional).
+include $(CHIBIOS)/test/rt/test.mk
+# AMiRo-BLT files
+include ../../../bootloader/bootloader.mk
+# AMiRo-LLD files
+include ../../../periphery-lld/periphery-lld.mk
+# AMiRo-OS files
+include $(AMIROOS)/modules/modules.mk
+include $(AMIROOS)/core/core.mk
+include $(AMIROOS)/unittests/unittests.mk
+
+# Define linker script file here
+LDSCRIPT= $(BOARDLD)/STM32F103xE.ld
+
+# C sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CSRC = $(STARTUPSRC) \
+       $(KERNSRC) \
+       $(PORTSRC) \
+       $(OSALSRC) \
+       $(HALSRC) \
+       $(PLATFORMSRC) \
+       $(BOARDSRC) \
+       $(MODULESCSRC) \
+       $(TESTSRC) \
+       $(PERIPHERYLLDCSRC) \
+       $(AMIROOSCORECSRC) \
+       $(UNITTESTSCSRC) \
+       $(CHIBIOS)/os/various/evtimer.c \
+       $(CHIBIOS)/os/various/syscalls.c \
+       $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
+       module.c \
+       $(APPSCSRC_DIWHEELDRIVE)
+
+# C++ sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CPPSRC = $(APPSCPPSRC_DIWHEELDRIVE)
+
+# C sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACSRC =
+
+# C++ sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACPPSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCPPSRC =
+
+# List ASM source files here
+ASMSRC =
+ASMXSRC = $(STARTUPASM) \
+          $(PORTASM) \
+          $(OSALASM)
+
+INCDIR = $(CHIBIOS)/os/license \
+         $(STARTUPINC) \
+         $(KERNINC) \
+         $(PORTINC) \
+         $(OSALINC) \
+         $(HALINC) \
+         $(PLATFORMINC) \
+         $(BOARDINC) \
+         $(MODULESINC) \
+         $(TESTINC) \
+         $(BOOTLOADERINC) \
+         $(CHIBIOS)/os/hal/lib/streams \
+         $(CHIBIOS)/os/various \
+         $(PERIPHERYLLDINC) \
+         $(AMIROOS) \
+         $(AMIROOSCOREINC) \
+         $(UNITTESTSINC) \
+         $(APPSINC_DIWHEELDRIVE)
+
+#                                                                              #
+# Project, sources and paths                                                   #
+################################################################################
+
+################################################################################
+# Compiler settings                                                            #
+# NOTE: Some can be overridden externally.                                     #
+#                                                                              #
+
+MCU  = cortex-m3
+
+#TRGT = arm-elf-
+TRGT = arm-none-eabi-
+CC   = $(TRGT)gcc
+CPPC = $(TRGT)g++
+# Enable loading with g++ only if you need C++ runtime support.
+# NOTE: You can use C++ even without C++ support if you are careful. C++
+#       runtime support makes code size explode.
+LD   = $(TRGT)gcc
+#LD   = $(TRGT)g++
+CP   = $(TRGT)objcopy
+AS   = $(TRGT)gcc -x assembler-with-cpp
+AR   = $(TRGT)ar
+OD   = $(TRGT)objdump
+SZ   = $(TRGT)size
+HEX  = $(CP) -O ihex
+BIN  = $(CP) -O binary
+SREC = $(CP) -O srec --srec-len=248
+
+# ARM-specific options here
+ifeq ($(AOPT),)
+  AOPT =
+endif
+
+# THUMB-specific options here
+ifeq ($(TOPT),)
+  TOPT = -mthumb -DTHUMB
+endif
+
+# Define C warning options here
+ifeq ($(CWARN),)
+  CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
+endif
+
+# Define C++ warning options here
+ifeq ($(CPPWARN),)
+  CPPWARN = -Wall -Wextra -Wundef
+endif
+
+#                                                                              #
+# Compiler settings                                                            #
+################################################################################
+
+################################################################################
+# Start of user section                                                        #
+#                                                                              #
+
+# List all user C define here, like -D_DEBUG=1
+UDEFS +=
+
+# Define ASM defines here
+UADEFS +=
+
+# List all user directories here
+UINCDIR +=
+
+# List the user directory to look for the libraries here
+ULIBDIR +=
+
+# List all user libraries here
+ULIBS +=
+
+#                                                                              #
+# End of user defines                                                          #
+################################################################################
+
+RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
+include $(RULESPATH)/rules.mk
+
+include $(AMIROOS)/modules/flash.mk
diff --git a/os/modules/DiWheelDrive_1-1/alldconf.h b/os/modules/DiWheelDrive_1-1/alldconf.h
new file mode 100644
index 0000000..5b810a1
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/alldconf.h
@@ -0,0 +1,84 @@
+/*
+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 _ALLDCONF_H_
+#define _ALLDCONF_H_
+
+/*
+ * compatibility guards
+ */
+#define _AMIRO_LLD_CFG_
+#define AMIRO_LLD_CFG_VERSION_MAJOR         1
+#define AMIRO_LLD_CFG_VERSION_MINOR         0
+
+/**
+ * @brief   Enable flag for the A3906 motor driver.
+ */
+#define AMIROLLD_CFG_USE_A3906
+
+/**
+ * @brief   Enable flag for the AT24C01BN-SH-B EEPROM.
+ */
+#define AMIROLLD_CFG_USE_AT24C01BN
+
+/**
+ * @brief   Enable flag for the MHC5883L compass.
+ */
+#define AMIROLLD_CFG_USE_HMC5883L
+
+/**
+ * @brief   Enable flag for the INA219 power monitor.
+ */
+#define AMIROLLD_CFG_USE_INA219
+
+/**
+ * @brief   Enable flag for the L3G4200D gyroscope.
+ */
+#define AMIROLLD_CFG_USE_L3G4200D
+
+/**
+ * @brief   Enable flag for the status LED.
+ */
+#define AMIROLLD_CFG_USE_LED
+
+/**
+ * @brief   Enable flag for the LIS331DLH accelerometer.
+ */
+#define AMIROLLD_CFG_USE_LIS331DLH
+
+/**
+ * @brief   Enable flag for the LTC4412 power path controller.
+ */
+#define AMIROLLD_CFG_USE_LTC4412
+
+/**
+ * @brief   Enable flag for the PCA9544A I2C multiplexer.
+ */
+#define AMIROLLD_CFG_USE_PCA9544A
+
+/**
+ * @brief   Enable flag for the TPS62113 step-down converter.
+ */
+#define AMIROLLD_CFG_USE_TPS62113
+
+/**
+ * @brief   Enable flag for the VCNL4020 proximity sensor.
+ */
+#define AMIROLLD_CFG_USE_VCNL4020
+
+#endif /* _ALLDCONF_H_ */
diff --git a/os/modules/DiWheelDrive_1-1/aosconf.h b/os/modules/DiWheelDrive_1-1/aosconf.h
new file mode 100644
index 0000000..6233284
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/aosconf.h
@@ -0,0 +1,152 @@
+/*
+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 _AOSCONF_H_
+#define _AOSCONF_H_
+
+/*
+ * compatibility guards
+ */
+#define _AMIRO_OS_CFG_
+#define _AMIRO_OS_CFG_VERSION_MAJOR_            2
+#define _AMIRO_OS_CFG_VERSION_MINOR_            0
+
+#include <stdbool.h>
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/*
+ * Include an external configuration file to override the following default settings only if required.
+ */
+#if defined(AMIRO_APPS) && (AMIRO_APPS == true)
+  #include <osconf.h>
+#endif
+
+/**
+ * @brief   Flag to set the module as SSSP master.
+ */
+#if !defined(OS_CFG_SSSP_MASTER)
+  #define AMIROOS_CFG_SSSP_MASTER               false
+#else
+  #define AMIROOS_CFG_SSSP_MASTER               OS_CFG_SSSP_MASTER
+#endif
+
+/**
+ * @brief   Time boundary for robot wide clock synchronization in microseconds.
+ * @details Whenever the SSSP S (snychronization) signal gets logically deactivated,
+ *          All modules need to align their local uptime to the nearest multiple of this value.
+ */
+#if !defined(OS_CFG_SSSP_SYSSYNCPERIOD)
+  #define AMIROOS_CFG_SSSP_SYSSYNCPERIOD        1000000
+#else
+  #define AMIROOS_CFG_SSSP_SYSSYNCPERIOD        OS_CFG_SSSP_SYSSYNCPERIOD
+#endif
+
+/**
+ * @brief   Flag to enable/disable debug API.
+ */
+#if !defined(OS_CFG_DBG)
+  #define AMIROOS_CFG_DBG                       true
+#else
+  #define AMIROOS_CFG_DBG                       OS_CFG_DBG
+#endif
+
+/**
+ * @brief   Flag to enable/disable unit tests.
+ */
+#if !defined(OS_CFG_TESTS_ENABLE)
+  #define AMIROOS_CFG_TESTS_ENABLE              true
+#else
+  #define AMIROOS_CFG_TESTS_ENABLE              OS_CFG_TESTS_ENABLE
+#endif
+
+/**
+ * @brief   Flag to enable/disable profiling API.
+ */
+#if !defined(OS_CFG_PROFILE)
+  #define AMIROOS_CFG_PROFILE                   true
+#else
+  #define AMIROOS_CFG_PROFILE                   OS_CFG_PROFILE
+#endif
+
+/**
+ * @brief   Timeout value when waiting for events in the main loop in microseconds.
+ * @details A value of 0 deactivates the timeout.
+ */
+#if !defined(OS_CFG_MAIN_LOOP_TIMEOUT)
+  #define AMIROOS_CFG_MAIN_LOOP_TIMEOUT         0
+#else
+  #define AMIROOS_CFG_MAIN_LOOP_TIMEOUT         OS_CFG_MAIN_LOOP_TIMEOUT
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name System shell options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Shell enable flag.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE == false) && !defined(OS_CFG_SHELL_ENABLE)
+  #define AMIROOS_CFG_SHELL_ENABLE              true
+#elif (AMIROOS_CFG_TESTS_ENABLE == true)
+  #define AMIROOS_CFG_SHELL_ENABLE              true
+#else
+  #define AMIROOS_CFG_SHELL_ENABLE              OS_CFG_SHELL_ENABLE
+#endif
+
+/**
+ * @brief   Shell thread stack size.
+ */
+#if !defined(OS_CFG_SHELL_STACKSIZE)
+  #define AMIROOS_CFG_SHELL_STACKSIZE           1024
+#else
+  #define AMIROOS_CFG_SHELL_STACKSIZE           OS_CFG_SHELL_STACKSIZE
+#endif
+
+/**
+ * @brief   Shell maximum input line length.
+ */
+#if !defined(OS_CFG_SHELL_LINEWIDTH)
+  #define AMIROOS_CFG_SHELL_LINEWIDTH           64
+#else
+  #define AMIROOS_CFG_SHELL_LINEWIDTH           OS_CFG_SHELL_LINEWIDTH
+#endif
+
+/**
+ * @brief   Shell maximum number of arguments.
+ */
+#if !defined(OS_CFG_SHELL_MAXARGS)
+  #define AMIROOS_CFG_SHELL_MAXARGS             4
+#else
+  #define AMIROOS_CFG_SHELL_MAXARGS             OS_CFG_SHELL_MAXARGS
+#endif
+
+/** @} */
+
+#endif // _AOSCONF_H_
+
diff --git a/os/modules/DiWheelDrive_1-1/board.c b/os/modules/DiWheelDrive_1-1/board.c
new file mode 100644
index 0000000..7ce79b5
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/board.c
@@ -0,0 +1,80 @@
+/*
+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 <hal.h>
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+#if STM32_HAS_GPIOA
+  {VAL_GPIOAODR, VAL_GPIOACRL, VAL_GPIOACRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOFODR, VAL_GPIOFCRL, VAL_GPIOFCRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOGODR, VAL_GPIOGCRL, VAL_GPIOGCRH},
+#endif
+};
+#endif
+
+/**
+ * @brief   Early initialization code.
+ * @details This initialization must be performed just after stack setup
+ *          and before any other initialization.
+ */
+void __early_init(void) {
+
+  stm32_clock_init();
+}
+
+/**
+ * @brief   Board-specific initialization code.
+ * @todo    Add your board-specific code, if any.
+ */
+void boardInit(void) {
+  /*
+   * Several I/O pins are re-mapped:
+   *   JTAG disabled and SWJ enabled
+   *   TIM2 to the PA15/PB3/PA2/PA3 pins.
+   *   TIM3 to PC6/PC7 pins.
+   *   USART3 to the PC10/PC11 pins.
+   *   I2C1 to the PB8/PB9 pins.
+   */
+  AFIO->MAPR = AFIO_MAPR_SWJ_CFG_DISABLE |
+               AFIO_MAPR_TIM2_REMAP_PARTIALREMAP1 |
+               AFIO_MAPR_TIM3_REMAP_FULLREMAP |
+               AFIO_MAPR_USART3_REMAP_PARTIALREMAP |
+               AFIO_MAPR_I2C1_REMAP;
+}
diff --git a/os/modules/DiWheelDrive_1-1/board.h b/os/modules/DiWheelDrive_1-1/board.h
new file mode 100644
index 0000000..0515eac
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/board.h
@@ -0,0 +1,629 @@
+/*
+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 _BOARD_H_
+#define _BOARD_H_
+
+/*
+ * Setup for AMiRo DiWheelDrive board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_DIWHEELDRIVE
+#define BOARD_NAME              "AMiRo DiWheelDrive"
+#define BOARD_VERSION           "1.1"
+
+/*
+ * Board oscillators-related settings.
+ * NOTE: LSE not fitted.
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                0U
+#endif
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                8000000U
+#endif
+
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   330U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define STM32F103xE
+
+/*
+ * IO pins assignments.
+ */
+#define GPIOA_WKUP                  0U
+#define GPIOA_LED                   1U
+#define GPIOA_DRIVE_PWM1A           2U
+#define GPIOA_DRIVE_PWM1B           3U
+#define GPIOA_PIN4                  4U
+#define GPIOA_MOTION_SCLK           5U
+#define GPIOA_MOTION_MISO           6U
+#define GPIOA_MOTION_MOSI           7U
+#define GPIOA_PIN8                  8U
+#define GPIOA_PROG_RX               9U
+#define GPIOA_PROG_TX               10U
+#define GPIOA_CAN_RX                11U
+#define GPIOA_CAN_TX                12U
+#define GPIOA_SWDIO                 13U
+#define GPIOA_SWCLK                 14U
+#define GPIOA_DRIVE_PWM2B           15U
+
+#define GPIOB_PIN0                  0U
+#define GPIOB_DRIVE_SENSE2          1U
+#define GPIOB_POWER_EN              2U
+#define GPIOB_DRIVE_PWM2A           3U
+#define GPIOB_PIN4                  4U
+#define GPIOB_COMPASS_DRDY          5U
+#define GPIOB_DRIVE_ENC1A           6U
+#define GPIOB_DRIVE_ENC1B           7U
+#define GPIOB_COMPASS_SCL           8U
+#define GPIOB_COMPASS_SDA           9U
+#define GPIOB_IR_SCL                10U
+#define GPIOB_IR_SDA                11U
+#define GPIOB_IR_INT                12U
+#define GPIOB_GYRO_DRDY             13U
+#define GPIOB_SYS_UART_UP           14U
+#define GPIOB_ACCEL_INT_N           15U
+
+#define GPIOC_DRIVE_SENSE1          0U
+#define GPIOC_SYS_INT_N             1U
+#define GPIOC_PIN2                  2U
+#define GPIOC_PATH_DCSTAT           3U
+#define GPIOC_PIN4                  4U
+#define GPIOC_PATH_DCEN             5U
+#define GPIOC_DRIVE_ENC2B           6U
+#define GPIOC_DRIVE_ENC2A           7U
+#define GPIOC_SYS_PD_N              8U
+#define GPIOC_SYS_REG_EN            9U
+#define GPIOC_SYS_UART_RX           10U
+#define GPIOC_SYS_UART_TX           11U
+#define GPIOC_PIN12                 12U
+#define GPIOC_ACCEL_SS_N            13U
+#define GPIOC_GYRO_SS_N             14U
+#define GPIOC_PIN15                 15U
+
+#define GPIOD_OSC_IN                0U
+#define GPIOD_OSC_OUT               1U
+#define GPIOD_SYS_WARMRST_N         2U
+#define GPIOD_PIN3                  3U
+#define GPIOD_PIN4                  4U
+#define GPIOD_PIN5                  5U
+#define GPIOD_PIN6                  6U
+#define GPIOD_PIN7                  7U
+#define GPIOD_PIN8                  8U
+#define GPIOD_PIN9                  9U
+#define GPIOD_PIN10                 10U
+#define GPIOD_PIN11                 11U
+#define GPIOD_PIN12                 12U
+#define GPIOD_PIN13                 13U
+#define GPIOD_PIN14                 14U
+#define GPIOD_PIN15                 15U
+
+#define GPIOE_PIN0                  0U
+#define GPIOE_PIN1                  1U
+#define GPIOE_PIN2                  2U
+#define GPIOE_PIN3                  3U
+#define GPIOE_PIN4                  4U
+#define GPIOE_PIN5                  5U
+#define GPIOE_PIN6                  6U
+#define GPIOE_PIN7                  7U
+#define GPIOE_PIN8                  8U
+#define GPIOE_PIN9                  9U
+#define GPIOE_PIN10                 10U
+#define GPIOE_PIN11                 11U
+#define GPIOE_PIN12                 12U
+#define GPIOE_PIN13                 13U
+#define GPIOE_PIN14                 14U
+#define GPIOE_PIN15                 15U
+
+#define GPIOF_PIN0                  0U
+#define GPIOF_PIN1                  1U
+#define GPIOF_PIN2                  2U
+#define GPIOF_PIN3                  3U
+#define GPIOF_PIN4                  4U
+#define GPIOF_PIN5                  5U
+#define GPIOF_PIN6                  6U
+#define GPIOF_PIN7                  7U
+#define GPIOF_PIN8                  8U
+#define GPIOF_PIN9                  9U
+#define GPIOF_PIN10                 10U
+#define GPIOF_PIN11                 11U
+#define GPIOF_PIN12                 12U
+#define GPIOF_PIN13                 13U
+#define GPIOF_PIN14                 14U
+#define GPIOF_PIN15                 15U
+
+#define GPIOG_PIN0                  0U
+#define GPIOG_PIN1                  1U
+#define GPIOG_PIN2                  2U
+#define GPIOG_PIN3                  3U
+#define GPIOG_PIN4                  4U
+#define GPIOG_PIN5                  5U
+#define GPIOG_PIN6                  6U
+#define GPIOG_PIN7                  7U
+#define GPIOG_PIN8                  8U
+#define GPIOG_PIN9                  9U
+#define GPIOG_PIN10                 10U
+#define GPIOG_PIN11                 11U
+#define GPIOG_PIN12                 12U
+#define GPIOG_PIN13                 13U
+#define GPIOG_PIN14                 14U
+#define GPIOG_PIN15                 15U
+
+/*
+ * IO lines assignments.
+ */
+#define LINE_WKUP                   PAL_LINE(GPIOA, GPIOA_WKUP)
+#define LINE_LED                    PAL_LINE(GPIOA, GPIOA_LED)
+#define LINE_DRIVE_PWM1A            PAL_LINE(GPIOA, GPIOA_DRIVE_PWM1A)
+#define LINE_DRIVE_PWM1B            PAL_LINE(GPIOA, GPIOA_DRIVE_PWM1B)
+#define LINE_MOTION_SCLK            PAL_LINE(GPIOA, GPIOA_MOTION_SCLK)
+#define LINE_MOTION_MISO            PAL_LINE(GPIOA, GPIOA_MOTION_MISO)
+#define LINE_MOTION_MOSI            PAL_LINE(GPIOA, GPIOA_MOTION_MOSI)
+#define LINE_PROG_RX                PAL_LINE(GPIOA, GPIOA_PROG_RX)
+#define LINE_PROG_TX                PAL_LINE(GPIOA, GPIOA_PROG_TX)
+#define LINE_CAN_RX                 PAL_LINE(GPIOA, GPIOA_CAN_RX)
+#define LINE_CAN_TX                 PAL_LINE(GPIOA, GPIOA_CAN_TX)
+#define LINE_SWDIO                  PAL_LINE(GPIOA, GPIOA_SWDIO)
+#define LINE_SWCLK                  PAL_LINE(GPIOA, GPIOA_SWCLK)
+#define LINE_DRIVE_PWM2B            PAL_LINE(GPIOA, GPIOA_DRIVE_PWM2B)
+
+#define LINE_DRIVE_SENSE2           PAL_LINE(GPIOB, GPIOB_DRIVE_SENSE2)
+#define LINE_POWER_EN               PAL_LINE(GPIOB, GPIOB_POWER_EN)
+#define LINE_DRIVE_PWM2A            PAL_LINE(GPIOB, GPIOB_DRIVE_PWM2A)
+#define LINE_COMPASS_DRDY           PAL_LINE(GPIOB, GPIOB_COMPASS_DRDY)
+#define LINE_DRIVE_ENC1A            PAL_LINE(GPIOB, GPIOB_DRIVE_ENC1A)
+#define LINE_DRIVE_ENC1B            PAL_LINE(GPIOB, GPIOB_DRIVE_ENC1B)
+#define LINE_COMPASS_SCL            PAL_LINE(GPIOB, GPIOB_COMPASS_SCL)
+#define LINE_COMPASS_SDA            PAL_LINE(GPIOB, GPIOB_COMPASS_SDA)
+#define LINE_IR_SCL                 PAL_LINE(GPIOB, GPIOB_IR_SCL)
+#define LINE_IR_SDA                 PAL_LINE(GPIOB, GPIOB_IR_SDA)
+#define LINE_IR_INT                 PAL_LINE(GPIOB, GPIOB_IR_INT)
+#define LINE_GYRO_DRDY              PAL_LINE(GPIOB, GPIOB_GYRO_DRDY)
+#define LINE_SYS_UART_UP            PAL_LINE(GPIOB, GPIOB_SYS_UART_UP)
+#define LINE_ACCEL_INT_N            PAL_LINE(GPIOB, GPIOB_ACCEL_INT_N)
+
+#define LINE_DRIVE_SENSE1           PAL_LINE(GPIOC, GPIOC_DRIVE_SENSE1)
+#define LINE_SYS_INT_N              PAL_LINE(GPIOC, GPIOC_SYS_INT_N)
+#define LINE_PATH_DCSTAT            PAL_LINE(GPIOC, GPIOC_PATH_DCSTAT)
+#define LINE_PATH_DCEN              PAL_LINE(GPIOC, GPIOC_PATH_DCEN)
+#define LINE_DRIVE_ENC2B            PAL_LINE(GPIOC, GPIOC_DRIVE_ENC2B)
+#define LINE_DRIVE_ENC2A            PAL_LINE(GPIOC, GPIOC_DRIVE_ENC2A)
+#define LINE_SYS_PD_N               PAL_LINE(GPIOC, GPIOC_SYS_PD_N)
+#define LINE_SYS_REG_EN             PAL_LINE(GPIOC, GPIOC_SYS_REG_EN)
+#define LINE_SYS_UART_RX            PAL_LINE(GPIOC, GPIOC_SYS_UART_RX)
+#define LINE_SYS_UART_TX            PAL_LINE(GPIOC, GPIOC_SYS_UART_TX)
+#define LINE_ACCEL_SS_N             PAL_LINE(GPIOC, GPIOC_ACCEL_SS_N)
+#define LINE_GYRO_SS_N              PAL_LINE(GPIOC, GPIOC_GYRO_SS_N)
+
+#define LINE_OSC_IN                 PAL_LINE(GPIOD, GPIOD_OSC_IN)
+#define LINE_OSC_OUT                PAL_LINE(GPIOD, GPIOD_OSC_OUT)
+#define LINE_SYS_WARMRST_N          PAL_LINE(GPIOD, GPIOD_SYS_WARMRST_N)
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT              0U
+#define PIN_MODE_OUTPUT_2M          2U
+#define PIN_MODE_OUTPUT_10M         1U
+#define PIN_MODE_OUTPUT_50M         3U
+#define PIN_CNF_INPUT_ANALOG        0U
+#define PIN_CNF_INPUT_FLOATING      1U
+#define PIN_CNF_INPUT_PULLX         2U
+#define PIN_CNF_OUTPUT_PUSHPULL     0U
+#define PIN_CNF_OUTPUT_OPENDRAIN    1U
+#define PIN_CNF_ALTERNATE_PUSHPULL  2U
+#define PIN_CNF_ALTERNATE_OPENDRAIN 3U
+#define PIN_CR(pin, mode, cnf)      (((mode) | ((cnf) << 2U)) << (((pin) % 8U) * 4U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+
+/*
+ * GPIOA setup:
+ *
+ * PA0  - WKUP                      (input floating)
+ * PA1  - LED                       (output opendrain high 50MHz)
+ * PA2  - DRIVE_PWM1A               (alternate pushpull 50MHz)
+ * PA3  - DRIVE_PWM1B               (alternate pushpull 50MHz)
+ * PA4  - PIN4                      (input floating)
+ * PA5  - MOTION_SCLK               (alternate pushpull 50MHz)
+ * PA6  - MOTION_MISO               (input pullup)
+ * PA7  - MOTION_MOSI               (alternate pushpull 50MHz)
+ * PA8  - PIN8                      (input floating)
+ * PA9  - PROG_RX                   (alternate pushpull 50MHz)
+ * PA10 - PROG_TX                   (input pullup)
+ * PA11 - CAN_RX                    (input pullup)
+ * PA12 - CAN_TX                    (input floating)
+ * PA13 - SWDIO                     (input pullup)
+ * PA14 - SWCLK                     (input pullup)
+ * PA15 - DRIVE_PWM2B               (alternate pushpull 50MHz)
+ */
+#define VAL_GPIOACRL                (PIN_CR(GPIOA_WKUP, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOA_LED, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |            \
+                                     PIN_CR(GPIOA_DRIVE_PWM1A, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |  \
+                                     PIN_CR(GPIOA_DRIVE_PWM1B, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |  \
+                                     PIN_CR(GPIOA_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOA_MOTION_SCLK, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |  \
+                                     PIN_CR(GPIOA_MOTION_MISO, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |              \
+                                     PIN_CR(GPIOA_MOTION_MOSI, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL))
+#define VAL_GPIOACRH                (PIN_CR(GPIOA_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOA_PROG_RX, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |      \
+                                     PIN_CR(GPIOA_PROG_TX, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                  \
+                                     PIN_CR(GPIOA_CAN_RX, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                   \
+                                     PIN_CR(GPIOA_CAN_TX, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOA_SWDIO, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                    \
+                                     PIN_CR(GPIOA_SWCLK, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                    \
+                                     PIN_CR(GPIOA_DRIVE_PWM2B, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL))
+#define VAL_GPIOAODR                (PIN_ODR_HIGH(GPIOA_WKUP) |                                                    \
+                                     PIN_ODR_HIGH(GPIOA_LED) |                                                     \
+                                     PIN_ODR_HIGH(GPIOA_DRIVE_PWM1A) |                                             \
+                                     PIN_ODR_HIGH(GPIOA_DRIVE_PWM1B) |                                             \
+                                     PIN_ODR_LOW(GPIOA_PIN4) |                                                     \
+                                     PIN_ODR_HIGH(GPIOA_MOTION_SCLK) |                                             \
+                                     PIN_ODR_HIGH(GPIOA_MOTION_MISO) |                                             \
+                                     PIN_ODR_HIGH(GPIOA_MOTION_MOSI) |                                             \
+                                     PIN_ODR_LOW(GPIOA_PIN8) |                                                     \
+                                     PIN_ODR_HIGH(GPIOA_PROG_RX) |                                                 \
+                                     PIN_ODR_HIGH(GPIOA_PROG_TX) |                                                 \
+                                     PIN_ODR_HIGH(GPIOA_CAN_RX) |                                                  \
+                                     PIN_ODR_HIGH(GPIOA_CAN_TX) |                                                  \
+                                     PIN_ODR_HIGH(GPIOA_SWDIO) |                                                   \
+                                     PIN_ODR_HIGH(GPIOA_SWCLK) |                                                   \
+                                     PIN_ODR_HIGH(GPIOA_DRIVE_PWM2B))
+
+/*
+ * GPIOB setup:
+ *
+ * PB0  - PIN0                      (input floating)
+ * PB1  - DRIVE_SENSE2              (input analog)
+ * PB2  - POWER_EN                  (output pushpull low 50MHz)
+ * PB3  - DRIVE_PWM2A               (alternate pushpull 50MHz)
+ * PB4  - PIN4                      (input floating)
+ * PB5  - COMPASS_DRDY              (input pullup)
+ * PB6  - DRIVE_ENC1A               (input floating)
+ * PB7  - DRIVE_ENC1B               (input floating)
+ * PB8  - COMPASS_SCL               (alternate opendrain 50MHz)
+ * PB9  - COMPASS_SDA               (alternate opendrain 50MHz)
+ * PB10 - IR_SCL                    (alternate opendrain 50MHz)
+ * PB11 - IR_SDA                    (alternate opendrain 50MHz)
+ * PB12 - IR_INT                    (input pullup)
+ * PB13 - GYRO_DRDY                 (input pullup)
+ * PB14 - SYS_UART_UP               (output opendrain high 50MHz)
+ * PB15 - ACCEL_INT_N               (input pullup)
+ */
+#define VAL_GPIOBCRL                (PIN_CR(GPIOB_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOB_DRIVE_SENSE2, PIN_MODE_INPUT, PIN_CNF_INPUT_ANALOG) |            \
+                                     PIN_CR(GPIOB_POWER_EN, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |        \
+                                     PIN_CR(GPIOB_DRIVE_PWM2A, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |  \
+                                     PIN_CR(GPIOB_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOB_COMPASS_DRDY, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |             \
+                                     PIN_CR(GPIOB_DRIVE_ENC1A, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |           \
+                                     PIN_CR(GPIOB_DRIVE_ENC1B, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOBCRH                (PIN_CR(GPIOB_COMPASS_SCL, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_OPENDRAIN) | \
+                                     PIN_CR(GPIOB_COMPASS_SDA, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_OPENDRAIN) | \
+                                     PIN_CR(GPIOB_IR_SCL, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_OPENDRAIN) |      \
+                                     PIN_CR(GPIOB_IR_SDA, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_OPENDRAIN) |      \
+                                     PIN_CR(GPIOB_IR_INT, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOB_GYRO_DRDY, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                \
+                                     PIN_CR(GPIOB_SYS_UART_UP, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |    \
+                                     PIN_CR(GPIOB_ACCEL_INT_N, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX))
+#define VAL_GPIOBODR                (PIN_ODR_LOW(GPIOB_PIN0) |                                                     \
+                                     PIN_ODR_HIGH(GPIOB_DRIVE_SENSE2) |                                            \
+                                     PIN_ODR_LOW(GPIOB_POWER_EN) |                                                 \
+                                     PIN_ODR_HIGH(GPIOB_DRIVE_PWM2A) |                                             \
+                                     PIN_ODR_LOW(GPIOB_PIN4) |                                                     \
+                                     PIN_ODR_HIGH(GPIOB_COMPASS_DRDY) |                                            \
+                                     PIN_ODR_HIGH(GPIOB_DRIVE_ENC1A) |                                             \
+                                     PIN_ODR_HIGH(GPIOB_DRIVE_ENC1B) |                                             \
+                                     PIN_ODR_HIGH(GPIOB_COMPASS_SCL) |                                             \
+                                     PIN_ODR_HIGH(GPIOB_COMPASS_SDA) |                                             \
+                                     PIN_ODR_HIGH(GPIOB_IR_SCL) |                                                  \
+                                     PIN_ODR_HIGH(GPIOB_IR_SDA) |                                                  \
+                                     PIN_ODR_HIGH(GPIOB_IR_INT) |                                                  \
+                                     PIN_ODR_HIGH(GPIOB_GYRO_DRDY) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_SYS_UART_UP) |                                             \
+                                     PIN_ODR_HIGH(GPIOB_ACCEL_INT_N))
+
+/*
+ * GPIOC setup:
+ *
+ * PC0  - DRIVE_SENSE1              (input analog)
+ * PC1  - SYS_INT_N                 (output opendrain low 50MHz)
+ * PC2  - PIN2                      (input floating)
+ * PC3  - PATH_DCSTAT               (input floating)
+ * PC4  - PIN4                      (input floating)
+ * PC5  - PATH_DCEN                 (output pushpull low 50MHz)
+ * PC6  - DRIVE_ENC2B               (input floating)
+ * PC7  - DRIVE_ENC2A               (input floating)
+ * PC8  - SYS_PD_N                  (output opendrain high 50MHz)
+ * PC9  - SYS_REG_EN                (input floating)
+ * PC10 - SYS_UART_RX               (input floating)
+ * PC11 - SYS_UART_TX               (input floating)
+ * PC12 - PIN12                     (input pullup)
+ * PC13 - ACCEL_SS_N                (output pushpull high 50MHz)
+ * PC14 - GYRO_SS_N                 (output pushpull high 50MHz)
+ * PC15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOCCRL                (PIN_CR(GPIOC_DRIVE_SENSE1, PIN_MODE_INPUT, PIN_CNF_INPUT_ANALOG) |            \
+                                     PIN_CR(GPIOC_SYS_INT_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |           \
+                                     PIN_CR(GPIOC_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOC_PATH_DCSTAT, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |           \
+                                     PIN_CR(GPIOC_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOC_PATH_DCEN, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |       \
+                                     PIN_CR(GPIOC_DRIVE_ENC2B, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |           \
+                                     PIN_CR(GPIOC_DRIVE_ENC2A, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOCCRH                (PIN_CR(GPIOC_SYS_PD_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |       \
+                                     PIN_CR(GPIOC_SYS_REG_EN, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |            \
+                                     PIN_CR(GPIOC_SYS_UART_RX, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |           \
+                                     PIN_CR(GPIOC_SYS_UART_TX, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |           \
+                                     PIN_CR(GPIOC_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOC_ACCEL_SS_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |      \
+                                     PIN_CR(GPIOC_GYRO_SS_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |       \
+                                     PIN_CR(GPIOC_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOCODR                (PIN_ODR_HIGH(GPIOC_DRIVE_SENSE1) |                                            \
+                                     PIN_ODR_LOW(GPIOC_SYS_INT_N) |                                                \
+                                     PIN_ODR_LOW(GPIOC_PIN2) |                                                     \
+                                     PIN_ODR_HIGH(GPIOC_PATH_DCSTAT) |                                             \
+                                     PIN_ODR_LOW(GPIOC_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOC_PATH_DCEN) |                                                \
+                                     PIN_ODR_HIGH(GPIOC_DRIVE_ENC2B) |                                             \
+                                     PIN_ODR_HIGH(GPIOC_DRIVE_ENC2A) |                                             \
+                                     PIN_ODR_HIGH(GPIOC_SYS_PD_N) |                                                \
+                                     PIN_ODR_HIGH(GPIOC_SYS_REG_EN) |                                              \
+                                     PIN_ODR_HIGH(GPIOC_SYS_UART_RX) |                                             \
+                                     PIN_ODR_HIGH(GPIOC_SYS_UART_TX) |                                             \
+                                     PIN_ODR_LOW(GPIOC_PIN12) |                                                    \
+                                     PIN_ODR_HIGH(GPIOC_ACCEL_SS_N) |                                              \
+                                     PIN_ODR_HIGH(GPIOC_GYRO_SS_N) |                                               \
+                                     PIN_ODR_LOW(GPIOC_PIN15))
+
+/*
+ * GPIOD setup:
+ *
+ * PD0  - OSC_IN                    (input floating)
+ * PD1  - OSC_OUT                   (input floating)
+ * PD2  - SYS_WARMRST_N             (output opendrain high 50MHz)
+ * PD3  - PIN3                      (input floating)
+ * PD4  - PIN4                      (input floating)
+ * PD5  - PIN5                      (input floating)
+ * PD6  - PIN6                      (input floating)
+ * PD7  - PIN7                      (input floating)
+ * PD8  - PIN8                      (input floating)
+ * PD9  - PIN9                      (input floating)
+ * PD10 - PIN10                     (input floating)
+ * PD11 - PIN11                     (input floating)
+ * PD12 - PIN12                     (input floating)
+ * PD13 - PIN13                     (input floating)
+ * PD14 - PIN14                     (input floating)
+ * PD15 - PIN15                     (input floating)
+ */
+#define VAL_GPIODCRL                (PIN_CR(GPIOD_OSC_IN, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_OSC_OUT, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOD_SYS_WARMRST_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |  \
+                                     PIN_CR(GPIOD_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOD_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOD_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOD_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOD_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIODCRH                (PIN_CR(GPIOD_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOD_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOD_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOD_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOD_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOD_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOD_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOD_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIODODR                (PIN_ODR_HIGH(GPIOD_OSC_IN) |                                                  \
+                                     PIN_ODR_HIGH(GPIOD_OSC_OUT) |                                                 \
+                                     PIN_ODR_HIGH(GPIOD_SYS_WARMRST_N) |                                           \
+                                     PIN_ODR_LOW(GPIOD_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOD_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOD_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOD_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOD_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOD_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOD_PIN15))
+
+/*
+ * GPIOE setup:
+ *
+ * PE0  - PIN0                      (input floating)
+ * PE1  - PIN1                      (input floating)
+ * PE2  - PIN2                      (input floating)
+ * PE3  - PIN3                      (input floating)
+ * PE4  - PIN4                      (input floating)
+ * PE5  - PIN5                      (input floating)
+ * PE6  - PIN6                      (input floating)
+ * PE7  - PIN7                      (input floating)
+ * PE8  - PIN8                      (input floating)
+ * PE9  - PIN9                      (input floating)
+ * PE10 - PIN10                     (input floating)
+ * PE11 - PIN11                     (input floating)
+ * PE12 - PIN12                     (input floating)
+ * PE13 - PIN13                     (input floating)
+ * PE14 - PIN14                     (input floating)
+ * PE15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOECRL                (PIN_CR(GPIOE_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOECRH                (PIN_CR(GPIOE_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOEODR                (PIN_ODR_LOW(GPIOE_PIN0) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN1) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN2) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN15))
+
+/*
+ * GPIOF setup:
+ *
+ * PF0  - PIN0                      (input floating)
+ * PF1  - PIN1                      (input floating)
+ * PF2  - PIN2                      (input floating)
+ * PF3  - PIN3                      (input floating)
+ * PF4  - PIN4                      (input floating)
+ * PF5  - PIN5                      (input floating)
+ * PF6  - PIN6                      (input floating)
+ * PF7  - PIN7                      (input floating)
+ * PF8  - PIN8                      (input floating)
+ * PF9  - PIN9                      (input floating)
+ * PF10 - PIN10                     (input floating)
+ * PF11 - PIN11                     (input floating)
+ * PF12 - PIN12                     (input floating)
+ * PF13 - PIN13                     (input floating)
+ * PF14 - PIN14                     (input floating)
+ * PF15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOFCRL                (PIN_CR(GPIOF_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOFCRH                (PIN_CR(GPIOF_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOFODR                (PIN_ODR_LOW(GPIOF_PIN0) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN1) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN2) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN15))
+
+/*
+ * GPIOG setup:
+ *
+ * PG0  - PIN0                      (input floating)
+ * PG1  - PIN1                      (input floating)
+ * PG2  - PIN2                      (input floating)
+ * PG3  - PIN3                      (input floating)
+ * PG4  - PIN4                      (input floating)
+ * PG5  - PIN5                      (input floating)
+ * PG6  - PIN6                      (input floating)
+ * PG7  - PIN7                      (input floating)
+ * PG8  - PIN8                      (input floating)
+ * PG9  - PIN9                      (input floating)
+ * PG10 - PIN10                     (input floating)
+ * PG11 - PIN11                     (input floating)
+ * PG12 - PIN12                     (input floating)
+ * PG13 - PIN13                     (input floating)
+ * PG14 - PIN14                     (input floating)
+ * PG15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOGCRL                (PIN_CR(GPIOG_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOGCRH                (PIN_CR(GPIOG_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOGODR                (PIN_ODR_LOW(GPIOG_PIN0) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN1) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN2) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN15))
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* _BOARD_H_ */
diff --git a/os/modules/DiWheelDrive_1-1/board.mk b/os/modules/DiWheelDrive_1-1/board.mk
new file mode 100644
index 0000000..075d14d
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/board.mk
@@ -0,0 +1,36 @@
+################################################################################
+# 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
+BOARD_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# include paths
+BOARDINC = $(BOARD_DIR)
+
+# C source files
+BOARDSRC = $(BOARD_DIR)board.c
+
+# linker path
+BOARDLD = $(AMIROOS)/hal/ports
diff --git a/os/modules/DiWheelDrive_1-1/chconf.h b/os/modules/DiWheelDrive_1-1/chconf.h
new file mode 100644
index 0000000..4c3d495
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/chconf.h
@@ -0,0 +1,593 @@
+/*
+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    os/modules/DiWheelDrive/chconf.h
+ * @brief   ChibiOS Configuration file for the DiWheelDrive module.
+ * @details Contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef _CHCONF_H_
+#define _CHCONF_H_
+
+#define _CHIBIOS_RT_CONF_
+
+#include <aosconf.h>
+
+/*===========================================================================*/
+/**
+ * @name System timers settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   System time counter resolution.
+ * @note    Allowed values are 16 or 32 bits.
+ */
+#define CH_CFG_ST_RESOLUTION                16
+
+/**
+ * @brief   System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ *          setting also defines the system tick time unit.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE != true) || defined(__DOXYGEN__)
+#define CH_CFG_ST_FREQUENCY                 1000000UL
+#else
+#define CH_CFG_ST_FREQUENCY                 100000UL
+#endif
+
+/**
+ * @brief   Time delta constant for the tick-less mode.
+ * @note    If this value is zero then the system uses the classic
+ *          periodic tick. This value represents the minimum number
+ *          of ticks that is safe to specify in a timeout directive.
+ *          The value one is not valid, timeouts are rounded up to
+ *          this value.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE != true) || defined(__DOXYGEN__)
+#define CH_CFG_ST_TIMEDELTA                 10
+#else
+#define CH_CFG_ST_TIMEDELTA                 2
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ *          threads before preemption occurs. Setting this value to zero
+ *          disables the preemption for threads with equal priority and the
+ *          round robin becomes cooperative. Note that higher priority
+ *          threads can still preempt, the kernel is always preemptive.
+ * @note    Disabling the round robin preemption makes the kernel more compact
+ *          and generally faster.
+ * @note    The round robin preemption is not supported in tickless mode and
+ *          must be set to zero in that case.
+ */
+#define CH_CFG_TIME_QUANTUM                 0
+
+/**
+ * @brief   Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ *          then the whole available RAM is used. The core memory is made
+ *          available to the heap allocator and/or can be used directly through
+ *          the simplified core memory allocator.
+ *
+ * @note    In order to let the OS manage the whole RAM the linker script must
+ *          provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note    Requires @p CH_CFG_USE_MEMCORE.
+ */
+#define CH_CFG_MEMCORE_SIZE                 0
+
+/**
+ * @brief   Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ *          does not spawn the idle thread. The application @p main()
+ *          function becomes the idle thread and must implement an
+ *          infinite loop.
+ */
+#define CH_CFG_NO_IDLE_THREAD               FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ *          is used when two possible implementations exist.
+ *
+ * @note    This is not related to the compiler optimization options.
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_OPTIMIZE_SPEED               TRUE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Time Measurement APIs.
+ * @details If enabled then the time measurement APIs are included in
+ *          the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_TM                       FALSE
+
+/**
+ * @brief   Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_REGISTRY                 FALSE
+
+/**
+ * @brief   Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ *          the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_WAITEXIT                 TRUE
+
+/**
+ * @brief   Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_SEMAPHORES               FALSE
+
+/**
+ * @brief   Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ *          priority rather than in FIFO order.
+ *
+ * @note    The default is @p FALSE. Enable this if you have special
+ *          requirements.
+ * @note    Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_SEMAPHORES_PRIORITY      FALSE
+
+/**
+ * @brief   Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MUTEXES                  TRUE
+
+/**
+ * @brief   Enables recursive behavior on mutexes.
+ * @note    Recursive mutexes are heavier and have an increased
+ *          memory footprint.
+ *
+ * @note    The default is @p FALSE.
+ * @note    Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_MUTEXES_RECURSIVE        FALSE
+
+/**
+ * @brief   Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_CONDVARS                 FALSE
+
+/**
+ * @brief   Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ *          specification are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_CONDVARS.
+ */
+#define CH_CFG_USE_CONDVARS_TIMEOUT         FALSE
+
+/**
+ * @brief   Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_EVENTS                   TRUE
+
+/**
+ * @brief   Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ *          are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_EVENTS.
+ */
+#define CH_CFG_USE_EVENTS_TIMEOUT           TRUE
+
+/**
+ * @brief   Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MESSAGES                 FALSE
+
+/**
+ * @brief   Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ *          FIFO order.
+ *
+ * @note    The default is @p FALSE. Enable this if you have special
+ *          requirements.
+ * @note    Requires @p CH_CFG_USE_MESSAGES.
+ */
+#define CH_CFG_USE_MESSAGES_PRIORITY        FALSE
+
+/**
+ * @brief   Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ *          included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_MAILBOXES                FALSE
+
+/**
+ * @brief   I/O Queues APIs.
+ * @details If enabled then the I/O queues APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_QUEUES                   FALSE
+
+/**
+ * @brief   Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMCORE                  FALSE
+
+/**
+ * @brief   Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
+ *          @p CH_CFG_USE_SEMAPHORES.
+ * @note    Mutexes are recommended.
+ */
+#define CH_CFG_USE_HEAP                     FALSE
+
+/**
+ * @brief   Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMPOOLS                 FALSE
+
+/**
+ * @brief   Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_WAITEXIT.
+ * @note    Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
+ */
+#define CH_CFG_USE_DYNAMIC                  FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Debug option, kernel statistics.
+ *
+ * @note    The default is @p FALSE.
+ */
+#define CH_DBG_STATISTICS                   FALSE
+
+/**
+ * @brief   Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ *          at runtime.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_SYSTEM_STATE_CHECK           TRUE
+#else
+#define CH_DBG_SYSTEM_STATE_CHECK           FALSE
+#endif
+
+/**
+ * @brief   Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ *          parameters are activated.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_CHECKS                TRUE
+#else
+#define CH_DBG_ENABLE_CHECKS                FALSE
+#endif
+
+/**
+ * @brief   Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ *          activated. This includes consistency checks inside the kernel,
+ *          runtime anomalies and port-defined checks.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_ASSERTS               TRUE
+#else
+#define CH_DBG_ENABLE_ASSERTS               FALSE
+#endif
+
+/**
+ * @brief   Debug option, trace buffer.
+ * @details If enabled then the trace buffer is activated.
+ *
+ * @note    The default is @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#define CH_DBG_TRACE_MASK                   CH_DBG_TRACE_MASK_DISABLED
+
+/**
+ * @brief   Trace buffer entries.
+ * @note    The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
+ *          different from @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#define CH_DBG_TRACE_BUFFER_SIZE            128
+
+/**
+ * @brief   Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note    The default is @p FALSE.
+ * @note    The stack check is performed in a architecture/port dependent way.
+ *          It may not be implemented or some ports.
+ * @note    The default failure mode is to halt the system with the global
+ *          @p panic_msg variable set to @p NULL.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_STACK_CHECK           TRUE
+#else
+#define CH_DBG_ENABLE_STACK_CHECK           FALSE
+#endif
+
+/**
+ * @brief   Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ *          value when a thread is created. This can be useful for the
+ *          runtime measurement of the used stack.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_PROFILE == true) || defined(__DOXYGEN__)
+#define CH_DBG_FILL_THREADS                 TRUE
+#else
+#define CH_DBG_FILL_THREADS                 FALSE
+#endif
+
+/**
+ * @brief   Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p thread_t structure that
+ *          counts the system ticks occurred while executing the thread.
+ *
+ * @note    The default is @p FALSE.
+ * @note    This debug option is not currently compatible with the
+ *          tickless mode.
+ */
+#if ((CH_CFG_ST_TIMEDELTA == 0) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+  #define CH_DBG_THREADS_PROFILING          TRUE
+#else
+  #define CH_DBG_THREADS_PROFILING          FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXTRA_FIELDS                                          \
+  /* Add threads custom fields here.*/
+
+/**
+ * @brief   Threads initialization hook.
+ * @details User initialization code added to the @p chThdInit() API.
+ *
+ * @note    It is invoked from within @p chThdInit() and implicitly from all
+ *          the threads creation APIs.
+ */
+#define CH_CFG_THREAD_INIT_HOOK(tp) {                                       \
+  /* Add threads initialization code here.*/                                \
+}
+
+/**
+ * @brief   Threads finalization hook.
+ * @details User finalization code added to the @p chThdExit() API.
+ *
+ * @note    It is inserted into lock zone.
+ * @note    It is also invoked when the threads simply return in order to
+ *          terminate.
+ */
+#define CH_CFG_THREAD_EXIT_HOOK(tp) {                                       \
+  /* Add threads finalization code here.*/                                  \
+}
+
+/**
+ * @brief   Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
+  /* Context switch code here.*/                                            \
+}
+
+/**
+ * @brief   ISR enter hook.
+ */
+#define CH_CFG_IRQ_PROLOGUE_HOOK() {                                        \
+  /* IRQ prologue code here.*/                                              \
+}
+
+/**
+ * @brief   ISR exit hook.
+ */
+#define CH_CFG_IRQ_EPILOGUE_HOOK() {                                        \
+  /* IRQ epilogue code here.*/                                              \
+}
+
+/**
+ * @brief   Idle thread enter hook.
+ * @note    This hook is invoked within a critical zone, no OS functions
+ *          should be invoked from here.
+ * @note    This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() {                                          \
+  /* Idle-enter code here.*/                                                \
+}
+
+/**
+ * @brief   Idle thread leave hook.
+ * @note    This hook is invoked within a critical zone, no OS functions
+ *          should be invoked from here.
+ * @note    This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() {                                          \
+  /* Idle-leave code here.*/                                                \
+}
+
+/**
+ * @brief   Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#define CH_CFG_IDLE_LOOP_HOOK() {                                           \
+  /* Idle loop code here.*/                                                 \
+}
+
+/**
+ * @brief   System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ *          after processing the virtual timers queue.
+ */
+#define CH_CFG_SYSTEM_TICK_HOOK() {                                         \
+  /* System tick event code here.*/                                         \
+}
+
+/**
+ * @brief   System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ *          the system is halted.
+ */
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) {                                   \
+  extern void aosPrintHaltErrorCode(const char* reason);                       \
+  aosPrintHaltErrorCode(reason);                                               \
+}
+
+/**
+ * @brief   Trace hook.
+ * @details This hook is invoked each time a new record is written in the
+ *          trace buffer.
+ */
+#define CH_CFG_TRACE_HOOK(tep) {                                            \
+  /* Trace code here.*/                                                     \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Port specific settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   NVIC VTOR initialization offset.
+ * @details On initialization, the code at this address in the flash memory will be executed.
+ */
+#define CORTEX_VTOR_INIT 0x00006000U
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name other
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Flag to enable/disable floating point support in chprinf()
+ */
+#define CHPRINTF_USE_FLOAT                  TRUE
+
+/** @} */
+
+#endif  /* _CHCONF_H_ */
+
+/** @} */
diff --git a/os/modules/DiWheelDrive_1-1/halconf.h b/os/modules/DiWheelDrive_1-1/halconf.h
new file mode 100644
index 0000000..c3ff1ba
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/halconf.h
@@ -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    os/modules/DiWheelDrive/halconf.h
+ * @brief   HAL configuration header for the DiWheelDrive module.
+ * @details HAL configuration file, this file allows to enable or disable the
+ *          various device drivers from your application. You may also use
+ *          this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef _HALCONF_H_
+#define _HALCONF_H_
+
+/**
+ * @brief   Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL                 TRUE
+#endif
+
+/**
+ * @brief   Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN                 TRUE
+#endif
+
+/**
+ * @brief   Enables the DAC subsystem.
+ */
+#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
+#define HAL_USE_DAC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the EXT subsystem.
+ */
+#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
+#define HAL_USE_EXT                 TRUE
+#endif
+
+/**
+ * @brief   Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT                 FALSE
+#endif
+
+/**
+ * @brief   Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C                 TRUE
+#endif
+
+/**
+ * @brief   Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S                 FALSE
+#endif
+
+/**
+ * @brief   Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU                 FALSE
+#endif
+
+/**
+ * @brief   Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI             FALSE
+#endif
+
+/**
+ * @brief   Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM                 TRUE
+#endif
+
+/**
+ * @brief   Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC                 TRUE
+#endif
+
+/**
+ * @brief   Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL              TRUE
+#endif
+
+/**
+ * @brief   Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB          FALSE
+#endif
+
+/**
+ * @brief   Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI                 TRUE
+#endif
+
+/**
+ * @brief   Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART                FALSE
+#endif
+
+/**
+ * @brief   Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB                 FALSE
+#endif
+
+/**
+ * @brief   Enables the WDG subsystem.
+ */
+#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
+#define HAL_USE_WDG                 FALSE
+#endif
+
+/**
+ * @brief   Enables the QEI subsystem.
+ */
+#if !defined(HAL_USE_QEI) || defined(__DOXYGEN__)
+#define HAL_USE_QEI                 TRUE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT                FALSE
+#endif
+
+/**
+ * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION    FALSE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE          FALSE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION    TRUE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY           FALSE
+#endif
+
+/**
+ * @brief   Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS              FALSE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings.                                          */
+/*===========================================================================*/
+
+/**
+ * @brief   Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ *          routines releasing some extra CPU time for the threads with
+ *          lower priority, this may slow down the driver a bit however.
+ *          This option is recommended also if the SPI driver does not
+ *          use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING            FALSE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Number of initialization attempts before rejecting the card.
+ * @note    Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY              100
+#endif
+
+/**
+ * @brief   Include support for MMC cards.
+ * @note    MMC support is not yet implemented so this option must be kept
+ *          at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT             FALSE
+#endif
+
+/**
+ * @brief   Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ *          routines releasing some extra CPU time for the threads with
+ *          lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING            FALSE
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings.                                           */
+/*===========================================================================*/
+
+/**
+ * @brief   Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ *          default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE      115200
+#endif
+
+/**
+ * @brief   Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ *          buffers depending on the requirements of your application.
+ * @note    The default is 16 bytes for both the transmission and receive
+ *          buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE         16
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting.                                        */
+/*===========================================================================*/
+
+/**
+ * @brief   Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ *          the USB data endpoint maximum packet size.
+ * @note    The default is 256 bytes for both the transmission and receive
+ *          buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE     256
+#endif
+
+/**
+ * @brief   Serial over USB number of buffers.
+ * @note    The default is 2 buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_NUMBER   2
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT                TRUE
+#endif
+
+/**
+ * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION    TRUE
+#endif
+
+/*===========================================================================*/
+/* UART driver related settings.                                             */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT               FALSE
+#endif
+
+/**
+ * @brief   Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION   FALSE
+#endif
+
+/*===========================================================================*/
+/* USB driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
+#define USB_USE_WAIT                FALSE
+#endif
+
+#endif /* _HALCONF_H_ */
+
+/** @} */
diff --git a/os/modules/DiWheelDrive_1-1/mcuconf.h b/os/modules/DiWheelDrive_1-1/mcuconf.h
new file mode 100644
index 0000000..272beb0
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/mcuconf.h
@@ -0,0 +1,227 @@
+/*
+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 _MCUCONF_H_
+#define _MCUCONF_H_
+
+#define STM32F103_MCUCONF
+
+/*
+ * STM32F103 drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 15...0       Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3        Lowest...Highest.
+ */
+
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT                       FALSE
+#define STM32_HSI_ENABLED                   TRUE
+#define STM32_LSI_ENABLED                   FALSE
+#define STM32_HSE_ENABLED                   TRUE
+#define STM32_LSE_ENABLED                   FALSE
+#define STM32_SW                            STM32_SW_PLL
+#define STM32_PLLSRC                        STM32_PLLSRC_HSE
+#define STM32_PLLXTPRE                      STM32_PLLXTPRE_DIV1
+#define STM32_PLLMUL_VALUE                  9
+#define STM32_HPRE                          STM32_HPRE_DIV1
+#define STM32_PPRE1                         STM32_PPRE1_DIV2
+#define STM32_PPRE2                         STM32_PPRE2_DIV2
+#define STM32_ADCPRE                        STM32_ADCPRE_DIV4
+#define STM32_USB_CLOCK_REQUIRED            TRUE
+#define STM32_USBPRE                        STM32_USBPRE_DIV1P5
+#define STM32_MCOSEL                        STM32_MCOSEL_NOCLOCK
+#define STM32_RTCSEL                        STM32_RTCSEL_HSEDIV
+#define STM32_PVD_ENABLE                    FALSE
+#define STM32_PLS                           STM32_PLS_LEV0
+
+/*
+ * ADC driver system settings.
+ */
+#define STM32_ADC_USE_ADC1                  FALSE
+#define STM32_ADC_ADC1_DMA_PRIORITY         2
+#define STM32_ADC_ADC1_IRQ_PRIORITY         6
+
+/*
+ * CAN driver system settings.
+ */
+#define STM32_CAN_USE_CAN1                  TRUE
+#define STM32_CAN_CAN1_IRQ_PRIORITY         11
+
+/*
+ * EXT driver system settings.
+ */
+#define STM32_EXT_EXTI0_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI1_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI2_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI3_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI4_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI5_9_IRQ_PRIORITY      6
+#define STM32_EXT_EXTI10_15_IRQ_PRIORITY    6
+#define STM32_EXT_EXTI16_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI17_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI18_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI19_IRQ_PRIORITY       6
+
+/*
+ * GPT driver system settings.
+ */
+#define STM32_GPT_USE_TIM1                  FALSE
+#define STM32_GPT_USE_TIM2                  FALSE
+#define STM32_GPT_USE_TIM3                  FALSE
+#define STM32_GPT_USE_TIM4                  FALSE
+#define STM32_GPT_USE_TIM5                  FALSE
+#define STM32_GPT_USE_TIM8                  FALSE
+#define STM32_GPT_TIM1_IRQ_PRIORITY         7
+#define STM32_GPT_TIM2_IRQ_PRIORITY         7
+#define STM32_GPT_TIM3_IRQ_PRIORITY         7
+#define STM32_GPT_TIM4_IRQ_PRIORITY         7
+#define STM32_GPT_TIM5_IRQ_PRIORITY         7
+#define STM32_GPT_TIM8_IRQ_PRIORITY         7
+
+/*
+ * I2C driver system settings.
+ */
+#define STM32_I2C_USE_I2C1                  TRUE
+#define STM32_I2C_USE_I2C2                  TRUE
+#define STM32_I2C_BUSY_TIMEOUT              50
+#define STM32_I2C_I2C1_IRQ_PRIORITY         5
+#define STM32_I2C_I2C2_IRQ_PRIORITY         5
+#define STM32_I2C_I2C1_DMA_PRIORITY         3
+#define STM32_I2C_I2C2_DMA_PRIORITY         3
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp)      osalSysHalt("DMA failure")
+#define STM32_I2C_USE_DMA                   FALSE
+
+/*
+ * ICU driver system settings.
+ */
+#define STM32_ICU_USE_TIM1                  FALSE
+#define STM32_ICU_USE_TIM2                  FALSE
+#define STM32_ICU_USE_TIM3                  FALSE
+#define STM32_ICU_USE_TIM4                  FALSE
+#define STM32_ICU_USE_TIM5                  FALSE
+#define STM32_ICU_USE_TIM8                  FALSE
+#define STM32_ICU_TIM1_IRQ_PRIORITY         7
+#define STM32_ICU_TIM2_IRQ_PRIORITY         7
+#define STM32_ICU_TIM3_IRQ_PRIORITY         7
+#define STM32_ICU_TIM4_IRQ_PRIORITY         7
+#define STM32_ICU_TIM5_IRQ_PRIORITY         7
+#define STM32_ICU_TIM8_IRQ_PRIORITY         7
+
+/*
+ * PWM driver system settings.
+ */
+#define STM32_PWM_USE_ADVANCED              FALSE
+#define STM32_PWM_USE_TIM1                  FALSE
+#define STM32_PWM_USE_TIM2                  TRUE
+#define STM32_PWM_USE_TIM3                  FALSE
+#define STM32_PWM_USE_TIM4                  FALSE
+#define STM32_PWM_USE_TIM5                  FALSE
+#define STM32_PWM_USE_TIM8                  FALSE
+#define STM32_PWM_TIM1_IRQ_PRIORITY         7
+#define STM32_PWM_TIM2_IRQ_PRIORITY         7
+#define STM32_PWM_TIM3_IRQ_PRIORITY         7
+#define STM32_PWM_TIM4_IRQ_PRIORITY         7
+#define STM32_PWM_TIM5_IRQ_PRIORITY         7
+#define STM32_PWM_TIM8_IRQ_PRIORITY         7
+
+/*
+ * RTC driver system settings.
+ */
+#define STM32_RTC_IRQ_PRIORITY              15
+
+/*
+ * SERIAL driver system settings.
+ */
+#define STM32_SERIAL_USE_USART1             TRUE
+#define STM32_SERIAL_USE_USART2             FALSE
+#define STM32_SERIAL_USE_USART3             FALSE
+#define STM32_SERIAL_USE_UART4              FALSE
+#define STM32_SERIAL_USE_UART5              FALSE
+#define STM32_SERIAL_USART1_PRIORITY        12
+#define STM32_SERIAL_USART2_PRIORITY        12
+#define STM32_SERIAL_USART3_PRIORITY        12
+#define STM32_SERIAL_UART4_PRIORITY         12
+#define STM32_SERIAL_UART5_PRIORITY         12
+
+/*
+ * SPI driver system settings.
+ */
+#define STM32_SPI_USE_SPI1                  TRUE
+#define STM32_SPI_USE_SPI2                  FALSE
+#define STM32_SPI_USE_SPI3                  FALSE
+#define STM32_SPI_SPI1_DMA_PRIORITY         1
+#define STM32_SPI_SPI2_DMA_PRIORITY         1
+#define STM32_SPI_SPI3_DMA_PRIORITY         1
+#define STM32_SPI_SPI1_IRQ_PRIORITY         10
+#define STM32_SPI_SPI2_IRQ_PRIORITY         10
+#define STM32_SPI_SPI3_IRQ_PRIORITY         10
+#define STM32_SPI_DMA_ERROR_HOOK(spip)      osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define STM32_ST_IRQ_PRIORITY               8
+#define STM32_ST_USE_TIMER                  5
+
+/*
+ * UART driver system settings.
+ */
+#define STM32_UART_USE_USART1               FALSE
+#define STM32_UART_USE_USART2               FALSE
+#define STM32_UART_USE_USART3               FALSE
+#define STM32_UART_USART1_IRQ_PRIORITY      12
+#define STM32_UART_USART2_IRQ_PRIORITY      12
+#define STM32_UART_USART3_IRQ_PRIORITY      12
+#define STM32_UART_USART1_DMA_PRIORITY      0
+#define STM32_UART_USART2_DMA_PRIORITY      0
+#define STM32_UART_USART3_DMA_PRIORITY      0
+#define STM32_UART_DMA_ERROR_HOOK(uartp)    osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_USB1                  FALSE
+#define STM32_USB_LOW_POWER_ON_SUSPEND      FALSE
+#define STM32_USB_USB1_HP_IRQ_PRIORITY      13
+#define STM32_USB_USB1_LP_IRQ_PRIORITY      14
+
+/*
+ * WDG driver system settings.
+ */
+#define STM32_WDG_USE_IWDG                  FALSE
+
+/*
+ * QEI driver system settings.
+ */
+#define STM32_QEI_USE_TIM1                  FALSE
+#define STM32_QEI_USE_TIM2                  FALSE
+#define STM32_QEI_USE_TIM3                  TRUE
+#define STM32_QEI_USE_TIM4                  TRUE
+#define STM32_QEI_USE_TIM5                  FALSE
+#define STM32_QEI_USE_TIM8                  FALSE
+
+#endif /* _MCUCONF_H_ */
diff --git a/os/modules/DiWheelDrive_1-1/module.c b/os/modules/DiWheelDrive_1-1/module.c
new file mode 100644
index 0000000..989186d
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/module.c
@@ -0,0 +1,778 @@
+/*
+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 "module.h"
+
+/*===========================================================================*/
+/**
+ * @name Module specific functions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiroos.h>
+
+/**
+ * @brief   Interrupt service routine callback for I/O interrupt signals.
+ *
+ * @param   extp      EXT driver to handle the ISR.
+ * @param   channel   Channel on which the interrupt was encountered.
+ */
+static void _moduleIsrCallback(EXTDriver* extp, expchannel_t channel) {
+  (void)extp;
+
+  chSysLockFromISR();
+  chEvtBroadcastFlagsI(&aos.events.io.source, (1 << channel));
+  chSysUnlockFromISR();
+
+  return;
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name ChibiOS/HAL configuration
+ * @{
+ */
+/*===========================================================================*/
+
+CANConfig moduleHalCanConfig = {
+  /* mcr  */ CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
+  /* btr  */ CAN_BTR_SJW(1) | CAN_BTR_TS2(2) | CAN_BTR_TS1(13) | CAN_BTR_BRP(1),
+};
+
+EXTConfig moduleHalExtConfig = {
+  /* channel configrations */ {
+    /* channel  0 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  1 */ { // SYS_INT_N/SYS_SYNC_N: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  2 */ { // SYS_WARMRST_N: automatic interrupt when activated
+      /* mode     */ EXT_MODE_GPIOD | EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  3 */ { // PATH_DCSTAT: must be enabled explicitely when charging is in progress to detect unexpected voltage drop
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_FALLING_EDGE,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  4 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  5 */ { // COMPASS_DRDY: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | APAL2CH_EDGE(HMC5883L_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  6 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  7 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  8 */ { // SYS_PD_N: automatic interrupt when activated
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  9 */ { // SYS_REG_EN: automatic interrupt when activated
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 10 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 11 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 12 */ { // IR_INT: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | APAL2CH_EDGE(VCNL4020_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 13 */ { // GYRO_DRDY: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | APAL2CH_EDGE(L3G4200D_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 14 */ { // SYS_UART_UP: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 15 */ { // ACCEL_INT_N: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | APAL2CH_EDGE(LIS331DLH_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 16 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 17 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 18 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+  },
+};
+
+I2CConfig moduleHalI2cCompassConfig = {
+  /* I²C mode   */ OPMODE_I2C,
+  /* frequency  */ 400000,
+  /* duty cycle */ FAST_DUTY_CYCLE_2,
+};
+
+I2CConfig moduleHalI2cProxEepromPwrmtrConfig = {
+  /* I²C mode   */ OPMODE_I2C,
+  /* frequency  */ 400000,
+  /* duty cycle */ FAST_DUTY_CYCLE_2,
+};
+
+PWMConfig moduleHalPwmDriveConfig = {
+  /* frequency              */ 7200000,
+  /* period                 */ 360,
+  /* callback               */ NULL,
+  /* channel configurations */ {
+    /* channel 0              */ {
+      /* mode                   */ PWM_OUTPUT_ACTIVE_HIGH,
+      /* callback               */ NULL
+    },
+    /* channel 1              */ {
+      /* mode                   */ PWM_OUTPUT_ACTIVE_HIGH,
+      /* callback               */ NULL
+    },
+    /* channel 2              */ {
+      /* mode                   */ PWM_OUTPUT_ACTIVE_HIGH,
+      /* callback               */ NULL
+    },
+    /* channel 3              */ {
+      /* mode                   */ PWM_OUTPUT_ACTIVE_HIGH,
+      /* callback               */ NULL
+    },
+  },
+  /* TIM CR2 register       */ 0,
+#if STM32_PWM_USE_ADVANCED
+  /* TIM BDTR register      */ 0,
+#endif
+  /* TIM DIER register      */ 0
+};
+
+QEIConfig moduleHalQeiConfig = {
+  /* mode           */ QEI_COUNT_BOTH,
+  /* channel config */ {
+    /* channel 0 */ {
+      /* input mode */ QEI_INPUT_NONINVERTED,
+    },
+    /* channel 1 */ {
+      /* input mode */ QEI_INPUT_NONINVERTED,
+    },
+  },
+  /* encoder range  */  0x10000u,
+};
+
+SerialConfig moduleHalProgIfConfig = {
+  /* bit rate */ 115200,
+  /* CR1      */ 0,
+  /* CR1      */ 0,
+  /* CR1      */ 0,
+};
+
+SPIConfig moduleHalSpiAccelerometerConfig = {
+  /* callback function pointer    */ NULL,
+  /* chip select line port        */ GPIOC,
+  /* chip select line pad number  */ GPIOC_ACCEL_SS_N,
+  /* CR1                          */ SPI_CR1_BR_0,
+  /* CR2                          */ SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN,
+};
+
+SPIConfig moduleHalSpiGyroscopeConfig = {
+  /* callback function pointer    */ NULL,
+  /* chip select line port        */ GPIOC,
+  /* chip select line pad number  */ GPIOC_GYRO_SS_N,
+  /* CR1                          */ SPI_CR1_BR_0,
+  /* CR2                          */ SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+
+apalGpio_t moduleGpioLed = {
+  /* port */ GPIOA,
+  /* pad  */ GPIOA_LED,
+};
+
+apalGpio_t moduleGpioPowerEn = {
+  /* port */GPIOB,
+  /* pad  */  GPIOB_POWER_EN,
+};
+
+apalGpio_t moduleGpioCompassDrdy = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_COMPASS_DRDY,
+};
+
+ apalGpio_t moduleGpioIrInt = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_IR_INT,
+};
+
+apalGpio_t moduleGpioGyroDrdy = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_GYRO_DRDY,
+};
+
+apalGpio_t moduleGpioSysUartUp = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_SYS_UART_UP,
+};
+
+apalGpio_t moduleGpioAccelInt = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_ACCEL_INT_N,
+};
+
+apalGpio_t moduleGpioSysSync = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_INT_N,
+};
+
+apalGpio_t moduleGpioPathDcStat = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_PATH_DCSTAT,
+};
+
+apalGpio_t moduleGpioPathDcEn = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_PATH_DCEN,
+};
+
+apalGpio_t moduleGpioSysPd = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_PD_N,
+};
+
+apalGpio_t moduleGpioSysRegEn = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_REG_EN,
+};
+
+apalGpio_t moduleGpioSysWarmrst = {
+  /* port */ GPIOD,
+  /* pad  */ GPIOD_SYS_WARMRST_N,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name AMiRo-OS core configurations
+ * @{
+ */
+/*===========================================================================*/
+
+apalControlGpio_t moduleSsspPd = {
+  /* GPIO */ &moduleGpioSysPd,
+  /* meta */ {
+    /* active state */ APAL_GPIO_ACTIVE_LOW,
+    /* edge         */ APAL_GPIO_EDGE_FALLING,
+    /* direction    */ APAL_GPIO_DIRECTION_BIDIRECTIONAL,
+  },
+};
+
+apalControlGpio_t moduleSsspSync = {
+  /* GPIO */ &moduleGpioSysSync,
+  /* meta */ {
+    /* active state */ APAL_GPIO_ACTIVE_LOW,
+    /* edge         */ APAL_GPIO_EDGE_FALLING,
+    /* direction    */ APAL_GPIO_DIRECTION_BIDIRECTIONAL,
+  },
+};
+
+const char* moduleShellPrompt = "DiWheelDrive";
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+
+A3906Driver moduleLldMotors = {
+  /* power enable GPIO  */ {
+    /* GPIO */& moduleGpioPowerEn,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+};
+
+AT24C01BNDriver moduleLldEeprom = {
+  /* I2C driver   */ &MODULE_HAL_I2C_PROX_EEPROM_PWRMTR,
+  /* I²C address  */ AT24C01BN_LLD_I2C_ADDR_FIXED,
+};
+
+HMC5883LDriver moduleLldCompass = {
+  /* I²C Driver */ &MODULE_HAL_I2C_COMPASS,
+};
+
+INA219Driver moduleLldPowerMonitorVdd = {
+  /* I2C Driver       */ &MODULE_HAL_I2C_PROX_EEPROM_PWRMTR,
+  /* I²C address      */ INA219_LLD_I2C_ADDR_FIXED,
+  /* current LSB (uA) */ 0x00u,
+  /* configuration    */ NULL,
+};
+
+L3G4200DDriver moduleLldGyroscope = {
+  /* SPI Driver */ &MODULE_HAL_SPI_MOTION,
+};
+
+LEDDriver moduleLldStatusLed = {
+  /* LED enable Gpio */ {
+    /* GPIO       */ &moduleGpioLed,
+    /* GPIO meta  */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+};
+
+LIS331DLHDriver moduleLldAccelerometer = {
+  /* SPI Driver */ &MODULE_HAL_SPI_MOTION,
+};
+
+LTC4412Driver moduleLldPowerPathController = {
+  /* Control GPIO */ {
+    /* GPIO       */ &moduleGpioPathDcEn,
+    /* GPIO meta  */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+  /* Status GPIO */ {
+    /* GPIO       */ &moduleGpioPathDcStat,
+    /* GPIO meta  */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+};
+
+PCA9544ADriver moduleLldI2cMultiplexer = {
+  /* I²C driver   */ &MODULE_HAL_I2C_PROX_EEPROM_PWRMTR,
+  /* I²C address  */ PCA9544A_LLD_I2C_ADDR_FIXED | PCA9544A_LLD_I2C_ADDR_A0 | PCA9544A_LLD_I2C_ADDR_A1 | PCA9544A_LLD_I2C_ADDR_A2,
+};
+
+TPS62113Driver moduleLldStepDownConverterVdrive = {
+  /* Power enable Gpio */ {
+    /* GPIO       */ &moduleGpioPowerEn,
+    /* GPIO meta  */ {
+      /* 'power on' state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge             */ APAL_GPIO_EDGE_NONE,
+      /* direction        */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+};
+
+VCNL4020Driver moduleLldProximity = {
+  /* I²C Driver */ &MODULE_HAL_I2C_PROX_EEPROM_PWRMTR,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Unit tests (UT)
+ * @{
+ */
+/*===========================================================================*/
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <string.h>
+#include <chprintf.h>
+
+/* A3906 (motor driver) */
+static int _utShellCmdCb_AlldA3906(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldA3906, NULL);
+  return AOS_OK;
+}
+static ut_a3906data_t _utA3906Data = {
+  /* driver           */ &moduleLldMotors,
+  /* PWM information  */ {
+    /* driver   */ &MODULE_HAL_PWM_DRIVE,
+    /* channels */ {
+      /* left wheel forward   */ MODULE_HAL_PWM_DRIVE_CHANNEL_LEFT_FORWARD,
+      /* left wheel backward  */ MODULE_HAL_PWM_DRIVE_CHANNEL_LEFT_BACKWARD,
+      /* right wheel forward  */ MODULE_HAL_PWM_DRIVE_CHANNEL_RIGHT_FORWARD,
+      /* right wheel backward */ MODULE_HAL_PWM_DRIVE_CHANNEL_RIGHT_BACKWARD,
+    },
+  },
+  /* QEI information  */ {
+    /* left wheel               */ &MODULE_HAL_QEI_LEFT_WHEEL,
+    /* right wheel              */ &MODULE_HAL_QEI_RIGHT_WHEEL,
+    /* increment per revolution */ MODULE_HAL_QEI_INCREMENTS_PER_REVOLUTION,
+  },
+  /* Wheel diameter   */ 0.05571f,
+  /* timeout          */ 10* MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldA3906  = {
+  /* name           */ "A3906",
+  /* info           */ "motor driver",
+  /* test function  */ utAlldA3906Func,
+  /* shell command  */ {
+    /* name     */ "unittest:MotorDriver",
+    /* callback */ _utShellCmdCb_AlldA3906,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utA3906Data,
+};
+
+/* AT24C01BN (EEPROM) */
+static int _utShellCmdCb_AlldAt24c01bn(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldAt24c01bn, NULL);
+  return AOS_OK;
+}
+static ut_at24c01bndata_t _utAt24c01bnData = {
+  /* driver   */ &moduleLldEeprom,
+  /* timeout  */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldAt24c01bn = {
+  /* name           */ "AT24C01BN-SH-B",
+  /* info           */ "1kbit EEPROM",
+  /* test function  */ utAlldAt24c01bnFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:EEPROM",
+    /* callback */ _utShellCmdCb_AlldAt24c01bn,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAt24c01bnData,
+};
+
+/* HMC5883L (compass) */
+static int _utShellCmdCb_AlldHmc5883l(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_COMPASSDRDY);
+  aosUtRun(stream, &moduleUtAlldHmc5883l, NULL);
+  return AOS_OK;
+}
+static ut_hmc5883ldata_t _utHmc5883lData = {
+  /* HMC driver   */ &moduleLldCompass,
+  /* event source */ &aos.events.io.source,
+  /* event flags  */ (1 << MODULE_GPIO_EXTCHANNEL_COMPASSDRDY),
+  /* timeout      */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldHmc5883l = {
+  /* name           */ "HMC5883L",
+  /* info           */ "compass",
+  /* test function  */ utAlldHmc5883lFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:Compass",
+    /* callback */ _utShellCmdCb_AlldHmc5883l,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utHmc5883lData,
+};
+
+/* INA219 (power monitor) */
+static int _utShellCmdCb_AlldIna219(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldIna219, "VDD (3.3V)");
+  return AOS_OK;
+}
+static ut_ina219data_t _utIna219Data = {
+  /* driver           */ &moduleLldPowerMonitorVdd,
+  /* expected voltage */ 3.3f,
+  /* tolerance        */ 0.05f,
+  /* timeout */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldIna219 = {
+  /* name           */ "INA219",
+  /* info           */ "power monitor",
+  /* test function  */ utAlldIna219Func,
+  /* shell command  */ {
+    /* name     */ "unittest:PowerMonitor",
+    /* callback */ _utShellCmdCb_AlldIna219,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utIna219Data,
+};
+
+/* L3G4200D (gyroscope) */
+static int _utShellCmdCb_AlldL3g4200d(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_GYRODRDY);
+  spiStart(((ut_l3g4200ddata_t*)moduleUtAlldL3g4200d.data)->l3gd->spid, ((ut_l3g4200ddata_t*)moduleUtAlldL3g4200d.data)->spiconf);
+  aosUtRun(stream, &moduleUtAlldL3g4200d, NULL);
+  spiStop(((ut_l3g4200ddata_t*)moduleUtAlldL3g4200d.data)->l3gd->spid);
+  return AOS_OK;
+}
+static ut_l3g4200ddata_t _utL3g4200dData = {
+  /* driver            */ &moduleLldGyroscope,
+  /* SPI configuration */ &moduleHalSpiGyroscopeConfig,
+  /* event source */ &aos.events.io.source,
+  /* event flags  */ (1 << MODULE_GPIO_EXTCHANNEL_GYRODRDY),
+};
+aos_unittest_t moduleUtAlldL3g4200d = {
+  /* name           */ "L3G4200D",
+  /* info           */ "Gyroscope",
+  /* test function  */ utAlldL3g4200dFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:Gyroscope",
+    /* callback */ _utShellCmdCb_AlldL3g4200d,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utL3g4200dData,
+};
+
+/* Status LED */
+static int _utShellCmdCb_AlldLed(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldLed, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldLed = {
+  /* name           */ "LED",
+  /* info           */ NULL,
+  /* test function  */ utAlldLedFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:StatusLED",
+    /* callback */ _utShellCmdCb_AlldLed,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldStatusLed,
+};
+
+/* LIS331DLH (accelerometer) */
+static int _utShellCmdCb_AlldLis331dlh(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_ACCELINT);
+  spiStart(((ut_lis331dlhdata_t*)moduleUtAlldLis331dlh.data)->lisd->spid, ((ut_lis331dlhdata_t*)moduleUtAlldLis331dlh.data)->spiconf);
+  aosUtRun(stream, &moduleUtAlldLis331dlh, NULL);
+  spiStop(((ut_lis331dlhdata_t*)moduleUtAlldLis331dlh.data)->lisd->spid);
+  return AOS_OK;
+}
+static ut_lis331dlhdata_t _utLis331dlhData = {
+  /* driver            */ &moduleLldAccelerometer,
+  /* SPI configuration */ &moduleHalSpiAccelerometerConfig,
+  /* event source */ &aos.events.io.source,
+  /* event flags  */ (1 << MODULE_GPIO_EXTCHANNEL_ACCELINT),
+};
+aos_unittest_t moduleUtAlldLis331dlh = {
+  /* name           */ "LIS331DLH",
+  /* info           */ "Accelerometer",
+  /* test function  */ utAlldLis331dlhFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:Accelerometer",
+    /* callback */ _utShellCmdCb_AlldLis331dlh,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utLis331dlhData,
+};
+
+/* LTC4412 (power path controller) */
+static int _utShellCmdCb_AlldLtc4412(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldLtc4412, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldLtc4412 = {
+  /* name           */ "LTC4412",
+  /* info           */ "Power path controller",
+  /* test function  */ utAlldLtc4412Func,
+  /* shell command  */ {
+    /* name     */ "unittest:PowerPathController",
+    /* callback */ _utShellCmdCb_AlldLtc4412,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldPowerPathController,
+};
+
+/* PCA9544A (I2C multiplexer) */
+static int _utShellCmdCb_AlldPca9544a(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldPca9544a, NULL);
+  return AOS_OK;
+}
+static ut_pca9544adata_t _utPca9544aData = {
+  /* driver  */ &moduleLldI2cMultiplexer,
+  /* timeout */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldPca9544a = {
+  /* name           */ "PCA9544A",
+  /* info           */ "I2C multiplexer",
+  /* test function  */ utAlldPca9544aFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:I2CMultiplexer",
+    /* callback */ _utShellCmdCb_AlldPca9544a,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utPca9544aData,
+};
+
+/* TPS62113 (step-down converter) */
+static int _utShellCmdCb_AlldTps62113(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldTps62113, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldTps62113 = {
+  /* name           */ "TPS62113",
+  /* info           */ "Step down converter",
+  /* test function  */ utAlldTps62113Func,
+  /* shell command  */ {
+    /* name     */ "unittest:StepDownConverter",
+    /* callback */ _utShellCmdCb_AlldTps62113,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldStepDownConverterVdrive,
+};
+
+/* VCNL4020 (proximity sensor) */
+static void _utAlldVcnl4020_disableInterrupt(VCNL4020Driver* vcnl)
+{
+  uint8_t intstatus;
+  vcnl4020_lld_writereg(vcnl, VCNL4020_LLD_REGADDR_INTCTRL, 0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+  vcnl4020_lld_readreg(vcnl, VCNL4020_LLD_REGADDR_INTSTATUS, &intstatus, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+  if (intstatus) {
+    vcnl4020_lld_writereg(vcnl, VCNL4020_LLD_REGADDR_INTSTATUS, intstatus, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+  }
+  return;
+}
+static int _utShellCmdCb_AlldVcnl4020(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  enum {
+    UNKNOWN,
+    FL, FR, WL, WR,
+  } sensor = UNKNOWN;
+  // evaluate arguments
+  if (argc == 2) {
+    if (strcmp(argv[1], "--frontleft") == 0 || strcmp(argv[1], "-fl") == 0) {
+      sensor = FL;
+    } else if (strcmp(argv[1], "--frontright") == 0 || strcmp(argv[1], "-fr") == 0) {
+      sensor = FR;
+    } else if (strcmp(argv[1], "--wheelleft") == 0 || strcmp(argv[1], "-wl") == 0) {
+      sensor = WL;
+    } else if (strcmp(argv[1], "--wheelright") == 0 || strcmp(argv[1], "-wr") == 0) {
+      sensor = WR;
+    }
+  }
+  if (sensor != UNKNOWN) {
+    pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH1, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH2, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH3, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_IRINT);
+    switch (sensor) {
+      case FL:
+        pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH3, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "front left snesor");
+        break;
+      case FR:
+        pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "front right sensor");
+        break;
+      case WL:
+        pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH2, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "left wheel sensor");
+        break;
+      case WR:
+        pca9544a_lld_setchannel(&moduleLldI2cMultiplexer, PCA9544A_LLD_CH1, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "right wheel sensor");
+        break;
+      default:
+        break;
+    }
+    return AOS_OK;
+  }
+  // print help
+  chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+  chprintf(stream, "Options:\n");
+  chprintf(stream, "  --frontleft, -fl\n");
+  chprintf(stream, "    Test front left proximity sensor.\n");
+  chprintf(stream, "  --frontrigt, -fr\n");
+  chprintf(stream, "    Test front right proximity sensor.\n");
+  chprintf(stream, "  --wheelleft, -wl\n");
+  chprintf(stream, "    Test left wheel proximity sensor.\n");
+  chprintf(stream, "  --wheelright, -wr\n");
+  chprintf(stream, "    Test right wheel proximity sensor.\n");
+  return AOS_INVALID_ARGUMENTS;
+}
+static ut_vcnl4020data_t _utVcnl4020Data = {
+  /* driver       */ &moduleLldProximity,
+  /* timeout      */ MICROSECONDS_PER_SECOND,
+  /* event source */ &aos.events.io.source,
+  /* event flags  */ (1 << MODULE_GPIO_EXTCHANNEL_IRINT),
+};
+aos_unittest_t moduleUtAlldVcnl4020 = {
+  /* name           */ "VCNL4020",
+  /* info           */ "proximity sensor",
+  /* test function  */ utAlldVcnl4020Func,
+  /* shell command  */ {
+    /* name     */ "unittest:Proximity",
+    /* callback */ _utShellCmdCb_AlldVcnl4020,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utVcnl4020Data,
+};
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
diff --git a/os/modules/DiWheelDrive_1-1/module.h b/os/modules/DiWheelDrive_1-1/module.h
new file mode 100644
index 0000000..a4a0e7b
--- /dev/null
+++ b/os/modules/DiWheelDrive_1-1/module.h
@@ -0,0 +1,587 @@
+/*
+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
+ * @{
+ */
+/*===========================================================================*/
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name ChibiOS/HAL configuration
+ * @{
+ */
+/*===========================================================================*/
+#include <hal.h>
+#include <hal_qei.h>
+
+/**
+ * @brief   CAN driver to use.
+ */
+#define MODULE_HAL_CAN                          CAND1
+
+/**
+ * @brief   Configuration for the CAN driver.
+ */
+extern CANConfig moduleHalCanConfig;
+
+/**
+ * @brief   Interrupt driver to use.
+ */
+#define MODULE_HAL_EXT                          EXTD1
+
+/**
+ * @brief   Interrupt driver configuration.
+ */
+extern EXTConfig moduleHalExtConfig;
+
+/**
+ * @brief   I2C driver to access the compass.
+ */
+#define MODULE_HAL_I2C_COMPASS                  I2CD1
+
+/**
+ * @brief   Configuration for the compass I2C driver.
+ */
+extern I2CConfig moduleHalI2cCompassConfig;
+
+/**
+ * @brief   I2C driver to access multiplexer, proximity sensors, EEPROM and power monitor.
+ */
+#define MODULE_HAL_I2C_PROX_EEPROM_PWRMTR       I2CD2
+
+/**
+ * @brief   Configuration for the multiplexer, proximity, EEPROM and power monitor I2C driver.
+ */
+extern I2CConfig moduleHalI2cProxEepromPwrmtrConfig;
+
+/**
+ * @brief   PWM driver to use.
+ */
+#define MODULE_HAL_PWM_DRIVE                    PWMD2
+
+/**
+ * @brief   Configuration for the PWM driver.
+ */
+extern PWMConfig moduleHalPwmDriveConfig;
+
+/**
+ * @brief   Drive PWM channel for the left wheel forward direction.
+ */
+#define MODULE_HAL_PWM_DRIVE_CHANNEL_LEFT_FORWARD     0
+
+/**
+ * @brief   Drive PWM channel for the left wheel backward direction.
+ */
+#define MODULE_HAL_PWM_DRIVE_CHANNEL_LEFT_BACKWARD    1
+
+/**
+ * @brief   Drive PWM channel for the right wheel forward direction.
+ */
+#define MODULE_HAL_PWM_DRIVE_CHANNEL_RIGHT_FORWARD    2
+
+/**
+ * @brief   Drive PWM channel for the right wheel backward direction.
+ */
+#define MODULE_HAL_PWM_DRIVE_CHANNEL_RIGHT_BACKWARD   3
+
+/**
+ * @brief   Quadrature encooder for the left wheel.
+ */
+#define MODULE_HAL_QEI_LEFT_WHEEL               QEID3
+
+/**
+ * @brief   Quadrature encooder for the right wheel.
+ */
+#define MODULE_HAL_QEI_RIGHT_WHEEL              QEID4
+
+/**
+ * @brief   Configuration for both quadrature encoders.
+ */
+extern QEIConfig moduleHalQeiConfig;
+
+/**
+ * @brief   QEI increments per wheel revolution.
+ * @details 2 signal edges per pulse * 2 signals * 16 pulses per motor revolution * 22:1 gearbox
+ */
+#define MODULE_HAL_QEI_INCREMENTS_PER_REVOLUTION  (apalQEICount_t)(2 * 2 * 16 * 22)
+
+/**
+ * @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_MOTION                   SPID1
+
+/**
+ * @brief   Configuration for the motion sensor SPI interface  driver to communicate with the accelerometer.
+ */
+extern SPIConfig moduleHalSpiAccelerometerConfig;
+
+/**
+ * @brief   Configuration for the motion sensor SPI interface  driver to communicate with the gyroscope.
+ */
+extern SPIConfig moduleHalSpiGyroscopeConfig;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiro-lld.h>
+
+/**
+ * @brief   Interrupt channel for the SYS_SYNC signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSSYNC          ((expchannel_t)1)
+
+/**
+ * @brief   Interrupt channel for the SYS_WARMRST signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSWARMRST       ((expchannel_t)2)
+
+/**
+ * @brief   Interrupt channel for the PATH_DCSTAT signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_PATHDCSTAT       ((expchannel_t)3)
+
+/**
+ * @brief   Interrupt channel for the COMPASS_DRDY signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_COMPASSDRDY      ((expchannel_t)5)
+
+/**
+ * @brief   Interrupt channel for the SYS_PD signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSPD            ((expchannel_t)7)
+
+/**
+ * @brief   Interrupt channel for the SYS_REG_EN signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSREGEN         ((expchannel_t)8)
+
+/**
+ * @brief   Interrupt channel for the IR_INT signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_IRINT            ((expchannel_t)12)
+
+/**
+ * @brief   Interrupt channel for the GYRO_DRDY signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_GYRODRDY         ((expchannel_t)13)
+
+/**
+ * @brief   Interrupt channel for the SYS_UART_UP signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSUARTUP        ((expchannel_t)14)
+
+/**
+ * @brief   Interrupt channel for the ACCEL_INT signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_ACCELINT         ((expchannel_t)15)
+
+/**
+ * @brief   LED output signal GPIO.
+ */
+extern apalGpio_t moduleGpioLed;
+
+/**
+ * @brief   POWER_EN output signal GPIO.
+ */
+extern apalGpio_t moduleGpioPowerEn;
+
+/**
+ * @brief   COMPASS_DRDY input signal GPIO.
+ */
+extern apalGpio_t moduleGpioCompassDrdy;
+
+/**
+ * @brief   IR_INT input signal GPIO.
+ */
+extern apalGpio_t moduleGpioIrInt;
+
+/**
+ * @brief   GYRO_DRDY input signal GPIO.
+ */
+extern apalGpio_t moduleGpioGyroDrdy;
+
+/**
+ * @brief   SYS_UART_UP bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysUartUp;
+
+/**
+ * @brief   ACCEL_INT input signal GPIO.
+ */
+extern apalGpio_t moduleGpioAccelInt;
+
+/**
+ * @brief   SYS_SNYC bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysSync;
+
+/**
+ * @brief   PATH_DCSTAT input signal GPIO.
+ */
+extern apalGpio_t moduleGpioPathDcStat;
+
+/**
+ * @brief   PATH_DCEN output signal GPIO.
+ */
+extern apalGpio_t moduleGpioPathDcEn;
+
+/**
+ * @brief   SYS_PD bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysPd;
+
+/**
+ * @brief   SYS_REG_EN input signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysRegEn;
+
+/**
+ * @brief   SYS_WARMRST bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysWarmrst;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name AMiRo-OS core configurations
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Event flag to be set on a SYS_SYNC interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSSYNC          ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSSYNC))
+
+/**
+ * @brief   Event flag to be set on a SYS_WARMRST interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSWARMRST       ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSWARMRST))
+
+/**
+ * @brief   Event flag to be set on a PATH_DCSTAT interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_PATHDCSTAT       ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_PATHDCSTAT))
+
+/**
+ * @brief   Event flag to be set on a COMPASS_DRDY interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_COMPASSDRDY      ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_COMPASSDRDY))
+
+/**
+ * @brief   Event flag to be set on a SYS_PD interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSPD            ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSPD))
+
+/**
+ * @brief   Event flag to be set on a SYS_REG_EN interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSREGEN         ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSREGEN))
+
+/**
+ * @brief   Event flag to be set on a IR_INT interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_IRINT            ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_IRINT))
+
+/**
+ * @brief   Event flag to be set on a GYRO_DRDY interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_GYRODRDY         ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_GYRODRDY))
+
+/**
+ * @brief   Event flag to be set on a SYS_UART_UP interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSUARTUP        ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSUARTUP))
+
+/**
+ * @brief   Event flag to be set on a ACCEL_INT interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_ACCELINT         ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_ACCELINT))
+
+/**
+ * @brief   PD signal for SSSP.
+ */
+extern apalControlGpio_t moduleSsspPd;
+
+/**
+ * @brief   SYNC signal for SSSP.
+ */
+extern apalControlGpio_t moduleSsspSync;
+
+/**
+ * @brief   Shell prompt text.
+ */
+extern const char* moduleShellPrompt;
+
+/**
+ * @brief   Additional HAL initialization hook.
+ */
+#define MODULE_INIT_HAL_EXTRA() {                                             \
+  qeiInit();                                                                  \
+}
+
+/**
+ * @brief   Unit test initialization hook.
+ */
+#define MODULE_INIT_TESTS() {                                                 \
+  /* add unit-test shell commands */                                          \
+  aosShellAddCommand(aos.shell, &moduleUtAlldA3906.shellcmd);                 \
+  aosShellAddCommand(aos.shell, &moduleUtAlldAt24c01bn.shellcmd);             \
+  aosShellAddCommand(aos.shell, &moduleUtAlldHmc5883l.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldIna219.shellcmd);                \
+  aosShellAddCommand(aos.shell, &moduleUtAlldL3g4200d.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldLed.shellcmd);                   \
+  aosShellAddCommand(aos.shell, &moduleUtAlldLis331dlh.shellcmd);             \
+  aosShellAddCommand(aos.shell, &moduleUtAlldLtc4412.shellcmd);               \
+  aosShellAddCommand(aos.shell, &moduleUtAlldPca9544a.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldTps62113.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldVcnl4020.shellcmd);              \
+}
+
+/**
+ * @brief   Periphery communication interfaces initialization hook.
+ */
+#define MODULE_INIT_PERIPHERY_COMM() {                                        \
+  /* serial driver */                                                         \
+  sdStart(&MODULE_HAL_PROGIF, &moduleHalProgIfConfig);                        \
+  /* I2C */                                                                   \
+  moduleHalI2cCompassConfig.clock_speed = (HMC5883L_LLD_I2C_MAXFREQUENCY < moduleHalI2cCompassConfig.clock_speed) ? HMC5883L_LLD_I2C_MAXFREQUENCY : moduleHalI2cCompassConfig.clock_speed;  \
+  moduleHalI2cCompassConfig.duty_cycle = (moduleHalI2cCompassConfig.clock_speed <= 100000) ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2;  \
+  i2cStart(&MODULE_HAL_I2C_COMPASS, &moduleHalI2cCompassConfig);              \
+  moduleHalI2cProxEepromPwrmtrConfig.clock_speed = (PCA9544A_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxEepromPwrmtrConfig.clock_speed) ? PCA9544A_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxEepromPwrmtrConfig.clock_speed; \
+  moduleHalI2cProxEepromPwrmtrConfig.clock_speed = (VCNL4020_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxEepromPwrmtrConfig.clock_speed) ? VCNL4020_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxEepromPwrmtrConfig.clock_speed; \
+  moduleHalI2cProxEepromPwrmtrConfig.clock_speed = (AT24C01BN_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxEepromPwrmtrConfig.clock_speed) ? AT24C01BN_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxEepromPwrmtrConfig.clock_speed; \
+  moduleHalI2cProxEepromPwrmtrConfig.clock_speed = (INA219_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxEepromPwrmtrConfig.clock_speed) ? INA219_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxEepromPwrmtrConfig.clock_speed; \
+  moduleHalI2cProxEepromPwrmtrConfig.duty_cycle = (moduleHalI2cProxEepromPwrmtrConfig.clock_speed <= 100000) ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2;  \
+  i2cStart(&MODULE_HAL_I2C_PROX_EEPROM_PWRMTR, &moduleHalI2cProxEepromPwrmtrConfig);  \
+  /* SPI is shared between accelerometer and gyroscope and needs to be restarted for each transmission */ \
+  /* PWM */                                                                   \
+  pwmStart(&MODULE_HAL_PWM_DRIVE, &moduleHalPwmDriveConfig);                  \
+  /* QEI */                                                                   \
+  qeiStart(&MODULE_HAL_QEI_LEFT_WHEEL, &moduleHalQeiConfig);                  \
+  qeiStart(&MODULE_HAL_QEI_RIGHT_WHEEL, &moduleHalQeiConfig);                 \
+  qeiEnable(&MODULE_HAL_QEI_LEFT_WHEEL);                                      \
+  qeiEnable(&MODULE_HAL_QEI_RIGHT_WHEEL);                                     \
+}
+
+/**
+ * @brief   Hook to handle IO events during SSSP startup synchronization.
+ */
+#define MODULE_SSP_STARTUP_OUTRO_IO_EVENT(mask, flags) {                      \
+  /* ignore all events */                                                     \
+  (void)mask;                                                                 \
+  (void)flags;                                                                \
+}
+
+/**
+ * @brief   Periphery communication interface deinitialization hook.
+ */
+#define MODULE_SHUTDOWN_PERIPHERY_COMM() {                                    \
+  /* PWM */                                                                   \
+  pwmStop(&MODULE_HAL_PWM_DRIVE);                                             \
+  /* QEI */                                                                   \
+  qeiDisable(&MODULE_HAL_QEI_LEFT_WHEEL);                                     \
+  qeiDisable(&MODULE_HAL_QEI_RIGHT_WHEEL);                                    \
+  qeiStop(&MODULE_HAL_QEI_LEFT_WHEEL);                                        \
+  qeiStop(&MODULE_HAL_QEI_RIGHT_WHEEL);                                       \
+  /* I2C */                                                                   \
+  i2cStop(&MODULE_HAL_I2C_COMPASS);                                           \
+  i2cStop(&MODULE_HAL_I2C_PROX_EEPROM_PWRMTR);                                \
+  /* don't stop the serial driver so messages can still be printed */         \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+#include <alld_a3906.h>
+#include <alld_at24c01bn-sh-b.h>
+#include <alld_hmc5883l.h>
+#include <alld_ina219.h>
+#include <alld_l3g4200d.h>
+#include <alld_led.h>
+#include <alld_lis331dlh.h>
+#include <alld_ltc4412.h>
+#include <alld_pca9544a.h>
+#include <alld_tps62113.h>
+#include <alld_vcnl4020.h>
+
+/**
+ * @brief   Motor driver.
+ */
+extern A3906Driver moduleLldMotors;
+
+/**
+ * @brief   EEPROM driver.
+ */
+extern AT24C01BNDriver moduleLldEeprom;
+
+/**
+ * @brief   Compass driver.
+ */
+extern HMC5883LDriver moduleLldCompass;
+
+/**
+ * @brief   Power monitor (VDD) driver.
+ */
+extern INA219Driver moduleLldPowerMonitorVdd;
+
+/**
+ * @brief   Gyroscope driver.
+ */
+extern L3G4200DDriver moduleLldGyroscope;
+
+/**
+ * @brief   Status LED driver.
+ */
+extern LEDDriver moduleLldStatusLed;
+
+/**
+ * @brief   Accelerometer driver.
+ */
+extern LIS331DLHDriver moduleLldAccelerometer;
+
+/**
+ * @brief   Power path controler (charging pins) driver.
+ */
+extern LTC4412Driver moduleLldPowerPathController;
+
+/**
+ * @brief   I2C multiplexer driver.
+ */
+extern PCA9544ADriver moduleLldI2cMultiplexer;
+
+/**
+ * @brief   Step down converter (VDRIVE) driver.
+ */
+extern TPS62113Driver moduleLldStepDownConverterVdrive;
+
+/**
+ * @brief   Proximity sensor driver.
+ */
+extern VCNL4020Driver moduleLldProximity;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Unit tests (UT)
+ * @{
+ */
+/*===========================================================================*/
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <ut_alld_a3906.h>
+#include <ut_alld_at24c01bn-sh-b.h>
+#include <ut_alld_hmc5883l.h>
+#include <ut_alld_ina219.h>
+#include <ut_alld_l3g4200d.h>
+#include <ut_alld_led.h>
+#include <ut_alld_lis331dlh.h>
+#include <ut_alld_ltc4412.h>
+#include <ut_alld_pca9544a.h>
+#include <ut_alld_tps62113.h>
+#include <ut_alld_vcnl4020.h>
+
+/**
+ * @brief   A3906 (motor driver) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldA3906;
+
+/**
+ * @brief   AT24C01BN-SH-B (EEPROM) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldAt24c01bn;
+
+/**
+ * @brief   HMC5883L (compass) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldHmc5883l;
+
+/**
+ * @brief   INA219 (power monitor) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldIna219;
+
+/**
+ * @brief   L3G4200D (gyroscope) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldL3g4200d;
+
+/**
+ * @brief   Status LED unit test object.
+ */
+extern aos_unittest_t moduleUtAlldLed;
+
+/**
+ * @brief   LIS331DLH (accelerometer) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldLis331dlh;
+
+/**
+ * @brief   LTC4412 (power path controller) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldLtc4412;
+
+/**
+ * @brief   PCA9544A (I2C multiplexer) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldPca9544a;
+
+/**
+ * @brief   TPS62113 (step-down converter) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldTps62113;
+
+/**
+ * @brief   VCNL4020 (proximity sensor) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldVcnl4020;
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
+
+#endif /* _AMIROOS_MODULE_H_ */
diff --git a/os/modules/LightRing_1-0/Makefile b/os/modules/LightRing_1-0/Makefile
new file mode 100644
index 0000000..31a1bc1
--- /dev/null
+++ b/os/modules/LightRing_1-0/Makefile
@@ -0,0 +1,302 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+
+
+################################################################################
+# Build global options                                                         #
+# NOTE: Can be overridden externally.                                          #
+#                                                                              #
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+  USE_OPT = -O2 -fomit-frame-pointer -falign-functions=16 -fstack-usage
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+  USE_COPT = -std=c99
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+  USE_CPPOPT = -fno-rtti -std=c++14
+endif
+
+# Enable this if you want the linker to remove unused code and data
+ifeq ($(USE_LINK_GC),)
+  USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+  USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO)
+ifeq ($(USE_LTO),)
+  USE_LTO = yes
+endif
+
+# If enabled, this option allows to compile the application in THUMB mode.
+ifeq ($(USE_THUMB),)
+  USE_THUMB = yes
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+  USE_VERBOSE_COMPILE = no
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+  USE_SMART_BUILD = yes
+endif
+
+#                                                                              #
+# Build global options                                                         #
+################################################################################
+
+################################################################################
+# Architecture or project specific options                                     #
+#                                                                              #
+
+# Stack size to be allocated to the Cortex-M process stack. This stack is
+# the stack used by the main() thread.
+ifneq ($(MAIN_STACKSIZE_LIGHTRING),)
+  USE_PROCESS_STACKSIZE = $(MAIN_STACKSIZE_LIGHTRING)
+endif
+ifeq ($(USE_PROCESS_STACKSIZE),)
+  USE_PROCESS_STACKSIZE = 0x400
+endif
+
+# Stack size to the allocated to the Cortex-M main/exceptions stack. This
+# stack is used for processing interrupts and exceptions.
+ifneq ($(EXCEPTIONS_STACKSIZE_LIGHTRING),)
+  USE_PROCESS_STACKSIZE = $(EXCEPTIONS_STACKSIZE_LIGHTRING)
+endif
+ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
+  USE_EXCEPTIONS_STACKSIZE = 0x400
+endif
+
+# Enables the use of FPU on Cortex-M4.
+# Possible selections are:
+#   no     - no FPU is used (propably equals 'soft')
+#   soft   - does not use the FPU, thus all floating point operations are emulated
+#   softfp - uses the FPU, but uses the integer registers only
+#   hard   - uses the FPU and passes data via the FPU registers
+ifeq ($(USE_FPU),)
+  USE_FPU = no
+endif
+
+#                                                                              #
+# Architecture or project specific options                                     #
+################################################################################
+
+################################################################################
+# Project, sources and paths                                                   #
+#                                                                              #
+
+# Define project name here
+PROJECT := $(patsubst $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))..)/%,%,$(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
+
+# Imported source files and paths
+include ../../../kernel/kernel.mk
+CHIBIOS := $(AMIROOS_KERNEL)
+AMIROOS = ../..
+# Startup files
+include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f1xx.mk
+# HAL-OSAL files
+include $(CHIBIOS)/os/hal/hal.mk
+include $(AMIROOS)/hal/hal.mk
+include $(CHIBIOS)/os/hal/ports/STM32/STM32F1xx/platform.mk
+include $(AMIROOS)/hal/ports/STM32/platform.mk
+include ./board.mk
+include $(CHIBIOS)/os/hal/osal/rt/osal.mk
+# RTOS files
+include $(CHIBIOS)/os/rt/rt.mk
+include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
+# Other files (optional).
+include $(CHIBIOS)/test/rt/test.mk
+# AMiRo-BLT files
+include ../../../bootloader/bootloader.mk
+# AMiRo-LLD files
+include ../../../periphery-lld/periphery-lld.mk
+# AMiRo-OS files
+include $(AMIROOS)/modules/modules.mk
+include $(AMIROOS)/core/core.mk
+include $(AMIROOS)/unittests/unittests.mk
+
+# Define linker script file here
+LDSCRIPT= $(BOARDLD)/STM32F103xE.ld
+
+# C sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CSRC = $(STARTUPSRC) \
+       $(KERNSRC) \
+       $(PORTSRC) \
+       $(OSALSRC) \
+       $(HALSRC) \
+       $(PLATFORMSRC) \
+       $(BOARDSRC) \
+       $(MODULESCSRC) \
+       $(TESTSRC) \
+       $(PERIPHERYLLDCSRC) \
+       $(AMIROOSCORECSRC) \
+       $(UNITTESTSCSRC) \
+       $(CHIBIOS)/os/various/evtimer.c \
+       $(CHIBIOS)/os/various/syscalls.c \
+       $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
+       module.c \
+       $(APPSCSRC_LIGHTRING)
+
+# C++ sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CPPSRC = $(APPSCPPSRC_LIGHTRING)
+
+# C sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACSRC =
+
+# C++ sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACPPSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCPPSRC =
+
+# List ASM source files here
+ASMSRC =
+ASMXSRC = $(STARTUPASM) \
+          $(PORTASM) \
+          $(OSALASM)
+
+INCDIR = $(CHIBIOS)/os/license \
+         $(STARTUPINC) \
+         $(KERNINC) \
+         $(PORTINC) \
+         $(OSALINC) \
+         $(HALINC) \
+         $(PLATFORMINC) \
+         $(BOARDINC) \
+         $(MODULESINC) \
+         $(TESTINC) \
+         $(BOOTLOADERINC) \
+         $(CHIBIOS)/os/hal/lib/streams \
+         $(CHIBIOS)/os/various \
+         $(PERIPHERYLLDINC) \
+         $(AMIROOS) \
+         $(AMIROOSCOREINC) \
+         $(UNITTESTSINC) \
+         $(APPSINC_LIGHTRING)
+
+#                                                                              #
+# Project, sources and paths                                                   #
+################################################################################
+
+################################################################################
+# Compiler settings                                                            #
+# NOTE: Some can be overridden externally.                                     #
+#                                                                              #
+
+MCU  = cortex-m3
+
+#TRGT = arm-elf-
+TRGT = arm-none-eabi-
+CC   = $(TRGT)gcc
+CPPC = $(TRGT)g++
+# Enable loading with g++ only if you need C++ runtime support.
+# NOTE: You can use C++ even without C++ support if you are careful. C++
+#       runtime support makes code size explode.
+LD   = $(TRGT)gcc
+#LD   = $(TRGT)g++
+CP   = $(TRGT)objcopy
+AS   = $(TRGT)gcc -x assembler-with-cpp
+AR   = $(TRGT)ar
+OD   = $(TRGT)objdump
+SZ   = $(TRGT)size
+HEX  = $(CP) -O ihex
+BIN  = $(CP) -O binary
+SREC = $(CP) -O srec --srec-len=248
+
+# ARM-specific options here
+ifeq ($(AOPT),)
+  AOPT =
+endif
+
+# THUMB-specific options here
+ifeq ($(TOPT),)
+  TOPT = -mthumb -DTHUMB
+endif
+
+# Define C warning options here
+ifeq ($(CWARN),)
+  CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
+endif
+
+# Define C++ warning options here
+ifeq ($(CPPWARN),)
+  CPPWARN = -Wall -Wextra -Wundef
+endif
+
+#                                                                              #
+# Compiler settings                                                            #
+################################################################################
+
+################################################################################
+# Start of user section                                                        #
+#                                                                              #
+
+# List all user C define here, like -D_DEBUG=1
+UDEFS +=
+
+# Define ASM defines here
+UADEFS +=
+
+# List all user directories here
+UINCDIR +=
+
+# List the user directory to look for the libraries here
+ULIBDIR +=
+
+# List all user libraries here
+ULIBS +=
+
+#                                                                              #
+# End of user defines                                                          #
+################################################################################
+
+RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
+include $(RULESPATH)/rules.mk
+
+include $(AMIROOS)/modules/flash.mk
diff --git a/os/modules/LightRing_1-0/alldconf.h b/os/modules/LightRing_1-0/alldconf.h
new file mode 100644
index 0000000..d3445af
--- /dev/null
+++ b/os/modules/LightRing_1-0/alldconf.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/>.
+*/
+
+#ifndef _ALLDCONF_H_
+#define _ALLDCONF_H_
+
+/*
+ * compatibility guards
+ */
+#define _AMIRO_LLD_CFG_
+#define AMIRO_LLD_CFG_VERSION_MAJOR         1
+#define AMIRO_LLD_CFG_VERSION_MINOR         0
+
+/**
+ * @brief   Enable flag for the AT24C01BN-SH-B EEPROM.
+ */
+#define AMIROLLD_CFG_USE_AT24C01BN
+
+/**
+ * @brief   Enable flag for the TLC5947 LED driver.
+ */
+#define AMIROLLD_CFG_USE_TLC5947
+
+/**
+ * @brief   Enable flag for the TPS2051BDBV power switch.
+ */
+#define AMIROLLD_CFG_USE_TPS2051BDBV
+
+#endif /* _ALLDCONF_H_ */
diff --git a/os/modules/LightRing_1-0/aosconf.h b/os/modules/LightRing_1-0/aosconf.h
new file mode 100644
index 0000000..6233284
--- /dev/null
+++ b/os/modules/LightRing_1-0/aosconf.h
@@ -0,0 +1,152 @@
+/*
+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 _AOSCONF_H_
+#define _AOSCONF_H_
+
+/*
+ * compatibility guards
+ */
+#define _AMIRO_OS_CFG_
+#define _AMIRO_OS_CFG_VERSION_MAJOR_            2
+#define _AMIRO_OS_CFG_VERSION_MINOR_            0
+
+#include <stdbool.h>
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/*
+ * Include an external configuration file to override the following default settings only if required.
+ */
+#if defined(AMIRO_APPS) && (AMIRO_APPS == true)
+  #include <osconf.h>
+#endif
+
+/**
+ * @brief   Flag to set the module as SSSP master.
+ */
+#if !defined(OS_CFG_SSSP_MASTER)
+  #define AMIROOS_CFG_SSSP_MASTER               false
+#else
+  #define AMIROOS_CFG_SSSP_MASTER               OS_CFG_SSSP_MASTER
+#endif
+
+/**
+ * @brief   Time boundary for robot wide clock synchronization in microseconds.
+ * @details Whenever the SSSP S (snychronization) signal gets logically deactivated,
+ *          All modules need to align their local uptime to the nearest multiple of this value.
+ */
+#if !defined(OS_CFG_SSSP_SYSSYNCPERIOD)
+  #define AMIROOS_CFG_SSSP_SYSSYNCPERIOD        1000000
+#else
+  #define AMIROOS_CFG_SSSP_SYSSYNCPERIOD        OS_CFG_SSSP_SYSSYNCPERIOD
+#endif
+
+/**
+ * @brief   Flag to enable/disable debug API.
+ */
+#if !defined(OS_CFG_DBG)
+  #define AMIROOS_CFG_DBG                       true
+#else
+  #define AMIROOS_CFG_DBG                       OS_CFG_DBG
+#endif
+
+/**
+ * @brief   Flag to enable/disable unit tests.
+ */
+#if !defined(OS_CFG_TESTS_ENABLE)
+  #define AMIROOS_CFG_TESTS_ENABLE              true
+#else
+  #define AMIROOS_CFG_TESTS_ENABLE              OS_CFG_TESTS_ENABLE
+#endif
+
+/**
+ * @brief   Flag to enable/disable profiling API.
+ */
+#if !defined(OS_CFG_PROFILE)
+  #define AMIROOS_CFG_PROFILE                   true
+#else
+  #define AMIROOS_CFG_PROFILE                   OS_CFG_PROFILE
+#endif
+
+/**
+ * @brief   Timeout value when waiting for events in the main loop in microseconds.
+ * @details A value of 0 deactivates the timeout.
+ */
+#if !defined(OS_CFG_MAIN_LOOP_TIMEOUT)
+  #define AMIROOS_CFG_MAIN_LOOP_TIMEOUT         0
+#else
+  #define AMIROOS_CFG_MAIN_LOOP_TIMEOUT         OS_CFG_MAIN_LOOP_TIMEOUT
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name System shell options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Shell enable flag.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE == false) && !defined(OS_CFG_SHELL_ENABLE)
+  #define AMIROOS_CFG_SHELL_ENABLE              true
+#elif (AMIROOS_CFG_TESTS_ENABLE == true)
+  #define AMIROOS_CFG_SHELL_ENABLE              true
+#else
+  #define AMIROOS_CFG_SHELL_ENABLE              OS_CFG_SHELL_ENABLE
+#endif
+
+/**
+ * @brief   Shell thread stack size.
+ */
+#if !defined(OS_CFG_SHELL_STACKSIZE)
+  #define AMIROOS_CFG_SHELL_STACKSIZE           1024
+#else
+  #define AMIROOS_CFG_SHELL_STACKSIZE           OS_CFG_SHELL_STACKSIZE
+#endif
+
+/**
+ * @brief   Shell maximum input line length.
+ */
+#if !defined(OS_CFG_SHELL_LINEWIDTH)
+  #define AMIROOS_CFG_SHELL_LINEWIDTH           64
+#else
+  #define AMIROOS_CFG_SHELL_LINEWIDTH           OS_CFG_SHELL_LINEWIDTH
+#endif
+
+/**
+ * @brief   Shell maximum number of arguments.
+ */
+#if !defined(OS_CFG_SHELL_MAXARGS)
+  #define AMIROOS_CFG_SHELL_MAXARGS             4
+#else
+  #define AMIROOS_CFG_SHELL_MAXARGS             OS_CFG_SHELL_MAXARGS
+#endif
+
+/** @} */
+
+#endif // _AOSCONF_H_
+
diff --git a/os/modules/LightRing_1-0/board.c b/os/modules/LightRing_1-0/board.c
new file mode 100644
index 0000000..1880ef6
--- /dev/null
+++ b/os/modules/LightRing_1-0/board.c
@@ -0,0 +1,73 @@
+/*
+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 <hal.h>
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+#if STM32_HAS_GPIOA
+  {VAL_GPIOAODR, VAL_GPIOACRL, VAL_GPIOACRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOBODR, VAL_GPIOBCRL, VAL_GPIOBCRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOCODR, VAL_GPIOCCRL, VAL_GPIOCCRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIODODR, VAL_GPIODCRL, VAL_GPIODCRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOEODR, VAL_GPIOECRL, VAL_GPIOECRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOFODR, VAL_GPIOFCRL, VAL_GPIOFCRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOGODR, VAL_GPIOGCRL, VAL_GPIOGCRH},
+#endif
+};
+#endif
+
+/**
+ * @brief   Early initialization code.
+ * @details This initialization must be performed just after stack setup
+ *          and before any other initialization.
+ */
+void __early_init(void) {
+
+  stm32_clock_init();
+}
+
+/**
+ * @brief   Board-specific initialization code.
+ * @todo    Add your board-specific code, if any.
+ */
+void boardInit(void) {
+  /*
+   * Several I/O pins are re-mapped:
+   *   JTAG disabled and SWD enabled
+   */
+  AFIO->MAPR = AFIO_MAPR_SWJ_CFG_JTAGDISABLE |
+               AFIO_MAPR_USART3_REMAP_PARTIALREMAP;
+}
diff --git a/os/modules/LightRing_1-0/board.h b/os/modules/LightRing_1-0/board.h
new file mode 100644
index 0000000..36e1f12
--- /dev/null
+++ b/os/modules/LightRing_1-0/board.h
@@ -0,0 +1,613 @@
+/*
+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 _BOARD_H_
+#define _BOARD_H_
+
+/*
+ * Setup for AMiRo LightRing board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_LIGHTRING
+#define BOARD_NAME              "AMiRo LightRing"
+#define BOARD_VERSION           "1.0"
+
+/*
+ * Board oscillators-related settings.
+ * NOTE: LSE not fitted.
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                0U
+#endif
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                8000000U
+#endif
+
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                   330U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define STM32F103xE
+
+/*
+ * IO pins assignments.
+ */
+#define GPIOA_PIN0                  0U
+#define GPIOA_PIN1                  1U
+#define GPIOA_LASER_RX              2U
+#define GPIOA_LASER_TX              3U
+#define GPIOA_LIGHT_BLANK           4U
+#define GPIOA_LIGHT_SCLK            5U
+#define GPIOA_PIN6                  6U
+#define GPIOA_LIGHT_MOSI            7U
+#define GPIOA_PIN8                  8U
+#define GPIOA_PROG_RX               9U
+#define GPIOA_PROG_TX               10U
+#define GPIOA_CAN_RX                11U
+#define GPIOA_CAN_TX                12U
+#define GPIOA_SWDIO                 13U
+#define GPIOA_SWCLK                 14U
+#define GPIOA_PIN15                 15U
+
+#define GPIOB_PIN0                  0U
+#define GPIOB_PIN1                  1U
+#define GPIOB_LASER_EN              2U
+#define GPIOB_PIN3                  3U
+#define GPIOB_PIN4                  4U
+#define GPIOB_LASER_OC_N            5U
+#define GPIOB_SYS_UART_DN           6U
+#define GPIOB_PIN7                  7U
+#define GPIOB_WL_GDO2               8U
+#define GPIOB_WL_GDO0               9U
+#define GPIOB_MEM_SCL               10U
+#define GPIOB_MEM_SDA               11U
+#define GPIOB_WL_SS_N               12U
+#define GPIOB_WL_SCLK               13U
+#define GPIOB_WL_MISO               14U
+#define GPIOB_WL_MOSI               15U
+
+#define GPIOC_PIN0                  0U
+#define GPIOC_PIN1                  1U
+#define GPIOC_PIN2                  2U
+#define GPIOC_PIN3                  3U
+#define GPIOC_LIGHT_XLAT            4U
+#define GPIOC_PIN5                  5U
+#define GPIOC_PIN6                  6U
+#define GPIOC_PIN7                  7U
+#define GPIOC_PIN8                  8U
+#define GPIOC_PIN9                  9U
+#define GPIOC_SYS_UART_RX           10U
+#define GPIOC_SYS_UART_TX           11U
+#define GPIOC_PIN12                 12U
+#define GPIOC_PIN13                 13U
+#define GPIOC_SYS_PD_N              14U
+#define GPIOC_PIN15                 15U
+
+#define GPIOD_OSC_IN                0U
+#define GPIOD_OSC_OUT               1U
+#define GPIOD_SYS_INT_N             2U
+#define GPIOD_PIN3                  3U
+#define GPIOD_PIN4                  4U
+#define GPIOD_PIN5                  5U
+#define GPIOD_PIN6                  6U
+#define GPIOD_PIN7                  7U
+#define GPIOD_PIN8                  8U
+#define GPIOD_PIN9                  9U
+#define GPIOD_PIN10                 10U
+#define GPIOD_PIN11                 11U
+#define GPIOD_PIN12                 12U
+#define GPIOD_PIN13                 13U
+#define GPIOD_PIN14                 14U
+#define GPIOD_PIN15                 15U
+
+#define GPIOE_PIN0                  0U
+#define GPIOE_PIN1                  1U
+#define GPIOE_PIN2                  2U
+#define GPIOE_PIN3                  3U
+#define GPIOE_PIN4                  4U
+#define GPIOE_PIN5                  5U
+#define GPIOE_PIN6                  6U
+#define GPIOE_PIN7                  7U
+#define GPIOE_PIN8                  8U
+#define GPIOE_PIN9                  9U
+#define GPIOE_PIN10                 10U
+#define GPIOE_PIN11                 11U
+#define GPIOE_PIN12                 12U
+#define GPIOE_PIN13                 13U
+#define GPIOE_PIN14                 14U
+#define GPIOE_PIN15                 15U
+
+#define GPIOF_PIN0                  0U
+#define GPIOF_PIN1                  1U
+#define GPIOF_PIN2                  2U
+#define GPIOF_PIN3                  3U
+#define GPIOF_PIN4                  4U
+#define GPIOF_PIN5                  5U
+#define GPIOF_PIN6                  6U
+#define GPIOF_PIN7                  7U
+#define GPIOF_PIN8                  8U
+#define GPIOF_PIN9                  9U
+#define GPIOF_PIN10                 10U
+#define GPIOF_PIN11                 11U
+#define GPIOF_PIN12                 12U
+#define GPIOF_PIN13                 13U
+#define GPIOF_PIN14                 14U
+#define GPIOF_PIN15                 15U
+
+#define GPIOG_PIN0                  0U
+#define GPIOG_PIN1                  1U
+#define GPIOG_PIN2                  2U
+#define GPIOG_PIN3                  3U
+#define GPIOG_PIN4                  4U
+#define GPIOG_PIN5                  5U
+#define GPIOG_PIN6                  6U
+#define GPIOG_PIN7                  7U
+#define GPIOG_PIN8                  8U
+#define GPIOG_PIN9                  9U
+#define GPIOG_PIN10                 10U
+#define GPIOG_PIN11                 11U
+#define GPIOG_PIN12                 12U
+#define GPIOG_PIN13                 13U
+#define GPIOG_PIN14                 14U
+#define GPIOG_PIN15                 15U
+
+/*
+ * IO lines assignments.
+ */
+#define LINE_LASER_RX               PAL_LINE(GPIOA, GPIOA_LASER_RX)
+#define LINE_LASER_TX               PAL_LINE(GPIOA, GPIOA_LASER_TX)
+#define LINE_LIGHT_BLANK            PAL_LINE(GPIOA, GPIOA_LIGHT_BLANK)
+#define LINE_LIGHT_SCLK             PAL_LINE(GPIOA, GPIOA_LIGHT_SCLK)
+#define LINE_LIGHT_MOSI             PAL_LINE(GPIOA, GPIOA_LIGHT_MOSI)
+#define LINE_PROG_RX                PAL_LINE(GPIOA, GPIOA_PROG_RX)
+#define LINE_PROG_TX                PAL_LINE(GPIOA, GPIOA_PROG_TX)
+#define LINE_CAN_RX                 PAL_LINE(GPIOA, GPIOA_CAN_RX)
+#define LINE_CAN_TX                 PAL_LINE(GPIOA, GPIOA_CAN_TX)
+#define LINE_SWDIO                  PAL_LINE(GPIOA, GPIOA_SWDIO)
+#define LINE_SWCLK                  PAL_LINE(GPIOA, GPIOA_SWCLK)
+
+#define LINE_LASER_EN               PAL_LINE(GPIOB, GPIOB_LASER_EN)
+#define LINE_LASER_OC_N             PAL_LINE(GPIOB, GPIOB_LASER_OC_N)
+#define LINE_SYS_UART_DN            PAL_LINE(GPIOB, GPIOB_SYS_UART_DN)
+#define LINE_WL_GDO2                PAL_LINE(GPIOB, GPIOB_WL_GDO2)
+#define LINE_WL_GDO0                PAL_LINE(GPIOB, GPIOB_WL_GDO0)
+#define LINE_MEM_SCL                PAL_LINE(GPIOB, GPIOB_MEM_SCL)
+#define LINE_MEM_SDA                PAL_LINE(GPIOB, GPIOB_MEM_SDA)
+#define LINE_WL_SS_N                PAL_LINE(GPIOB, GPIOB_WL_SS_N)
+#define LINE_WL_SCLK                PAL_LINE(GPIOB, GPIOB_WL_SCLK)
+#define LINE_WL_MISO                PAL_LINE(GPIOB, GPIOB_WL_MISO)
+#define LINE_WL_MOSI                PAL_LINE(GPIOB, GPIOB_WL_MOSI)
+
+#define LINE_LIGHT_XLAT             PAL_LINE(GPIOC, GPIOC_LIGHT_XLAT)
+#define LINE_SYS_UART_RX            PAL_LINE(GPIOC, GPIOC_SYS_UART_RX)
+#define LINE_SYS_UART_TX            PAL_LINE(GPIOC, GPIOC_SYS_UART_TX)
+#define LINE_SYS_PD_N               PAL_LINE(GPIOC, GPIOC_SYS_PD_N)
+
+#define LINE_SYS_INT_N              PAL_LINE(GPIOD, GPIOD_SYS_INT_N)
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT              0U
+#define PIN_MODE_OUTPUT_2M          2U
+#define PIN_MODE_OUTPUT_10M         1U
+#define PIN_MODE_OUTPUT_50M         3U
+#define PIN_CNF_INPUT_ANALOG        0U
+#define PIN_CNF_INPUT_FLOATING      1U
+#define PIN_CNF_INPUT_PULLX         2U
+#define PIN_CNF_OUTPUT_PUSHPULL     0U
+#define PIN_CNF_OUTPUT_OPENDRAIN    1U
+#define PIN_CNF_ALTERNATE_PUSHPULL  2U
+#define PIN_CNF_ALTERNATE_OPENDRAIN 3U
+#define PIN_CR(pin, mode, cnf)      (((mode) | ((cnf) << 2U)) << (((pin) % 8U) * 4U))
+#define PIN_ODR_LOW(n)              (0U << (n))
+#define PIN_ODR_HIGH(n)             (1U << (n))
+
+/*
+ * GPIOA setup:
+ *
+ * PA0  - PIN0                      (input floating)
+ * PA1  - PIN1                      (input floating)
+ * PA2  - LASER_RX                  (alternate pushpull high 50MHz)
+ * PA3  - LASER_TX                  (input pullup)
+ * PA4  - LIGHT_BLANK               (output pushpull high 50MHz)
+ * PA5  - LIGHT_SCLK                (alternate pushpull 50MHz)
+ * PA6  - PIN6                      (input foating)
+ * PA7  - LIGHT_MOSI                (alternate pushpull 50MHz)
+ * PA8  - PIN8                      (input floating)
+ * PA9  - PROG_RX                   (alternate pushpull 50MHz)
+ * PA10 - PROG_TX                   (input pullup)
+ * PA11 - CAN_RX                    (input floating)
+ * PA12 - CAN_TX                    (alternate pushpull 50MHz)
+ * PA13 - SWDIO                     (input pullup)
+ * PA14 - SWCLK                     (input pullup)
+ * PA15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOACRL                (PIN_CR(GPIOA_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOA_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOA_LASER_RX, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |   \
+                                     PIN_CR(GPIOA_LASER_TX, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |               \
+                                     PIN_CR(GPIOA_LIGHT_BLANK, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |   \
+                                     PIN_CR(GPIOA_LIGHT_SCLK, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) | \
+                                     PIN_CR(GPIOA_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOA_LIGHT_MOSI, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL))
+#define VAL_GPIOACRH                (PIN_CR(GPIOA_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOA_PROG_RX, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |    \
+                                     PIN_CR(GPIOA_PROG_TX, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                \
+                                     PIN_CR(GPIOA_CAN_RX, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |              \
+                                     PIN_CR(GPIOA_CAN_TX, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |     \
+                                     PIN_CR(GPIOA_SWDIO, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                  \
+                                     PIN_CR(GPIOA_SWCLK, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                  \
+                                     PIN_CR(GPIOA_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOAODR                (PIN_ODR_LOW(GPIOA_PIN0) |                                                   \
+                                     PIN_ODR_LOW(GPIOA_PIN1) |                                                   \
+                                     PIN_ODR_HIGH(GPIOA_LASER_RX) |                                              \
+                                     PIN_ODR_HIGH(GPIOA_LASER_TX) |                                              \
+                                     PIN_ODR_HIGH(GPIOA_LIGHT_BLANK) |                                           \
+                                     PIN_ODR_HIGH(GPIOA_LIGHT_SCLK) |                                            \
+                                     PIN_ODR_LOW(GPIOA_PIN6) |                                                   \
+                                     PIN_ODR_HIGH(GPIOA_LIGHT_MOSI) |                                            \
+                                     PIN_ODR_LOW(GPIOA_PIN8) |                                                   \
+                                     PIN_ODR_HIGH(GPIOA_PROG_RX) |                                               \
+                                     PIN_ODR_HIGH(GPIOA_PROG_TX) |                                               \
+                                     PIN_ODR_HIGH(GPIOA_CAN_RX) |                                                \
+                                     PIN_ODR_HIGH(GPIOA_CAN_TX) |                                                \
+                                     PIN_ODR_HIGH(GPIOA_SWDIO) |                                                 \
+                                     PIN_ODR_HIGH(GPIOA_SWCLK) |                                                 \
+                                     PIN_ODR_LOW(GPIOA_PIN15))
+
+/*
+ * GPIOB setup:
+ *
+ * PB0  - PIN0                      (input floating)
+ * PB1  - PIN1                      (input floating)
+ * PB2  - LASER_EN                  (output pushpull low 50MHz)
+ * PB3  - PIN3                      (input floating)
+ * PB4  - PIN4                      (input floating)
+ * PB5  - LASER_OC_N                (input floating)
+ * PB6  - SYS_UART_DN               (output opendrain high 50MHz)
+ * PB7  - PIN7                      (input foating)
+ * PB8  - WL_GDO2                   (input pullup)
+ * PB9  - WL_GDO0                   (input pullup)
+ * PB10 - MEM_SCL                   (alternate opendrain 50MHz)
+ * PB11 - MEM_SDA                   (alternate opendrain 50MHz)
+ * PB12 - WL_SS_N                   (output pushpull high 50MHz)
+ * PB13 - WL_SCLK                   (alternate pushpull 50MHz)
+ * PB14 - WL_MISO                   (input pullup)
+ * PB15 - WL_MOSI                   (alternate pushpull 50MHz)
+ */
+#define VAL_GPIOBCRL                (PIN_CR(GPIOB_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOB_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOB_LASER_EN, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |      \
+                                     PIN_CR(GPIOB_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOB_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOB_LASER_OC_N, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |          \
+                                     PIN_CR(GPIOB_SYS_UART_DN, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |  \
+                                     PIN_CR(GPIOB_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOBCRH                (PIN_CR(GPIOB_WL_GDO2, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                \
+                                     PIN_CR(GPIOB_WL_GDO0, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                \
+                                     PIN_CR(GPIOB_MEM_SCL, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_OPENDRAIN) |   \
+                                     PIN_CR(GPIOB_MEM_SDA, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_OPENDRAIN) |   \
+                                     PIN_CR(GPIOB_WL_SS_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_PUSHPULL) |       \
+                                     PIN_CR(GPIOB_WL_SCLK, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL) |    \
+                                     PIN_CR(GPIOB_WL_MISO, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |                \
+                                     PIN_CR(GPIOB_WL_MOSI, PIN_MODE_OUTPUT_50M, PIN_CNF_ALTERNATE_PUSHPULL))
+#define VAL_GPIOBODR                (PIN_ODR_LOW(GPIOB_PIN0) |                                                   \
+                                     PIN_ODR_LOW(GPIOB_PIN1) |                                                   \
+                                     PIN_ODR_LOW(GPIOB_LASER_EN) |                                               \
+                                     PIN_ODR_LOW(GPIOB_PIN3) |                                                   \
+                                     PIN_ODR_LOW(GPIOB_PIN4) |                                                   \
+                                     PIN_ODR_HIGH(GPIOB_LASER_OC_N) |                                            \
+                                     PIN_ODR_HIGH(GPIOB_SYS_UART_DN) |                                           \
+                                     PIN_ODR_LOW(GPIOB_PIN7) |                                                   \
+                                     PIN_ODR_HIGH(GPIOB_WL_GDO2) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_WL_GDO0) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_MEM_SCL) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_MEM_SDA) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_WL_SS_N) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_WL_SCLK) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_WL_MISO) |                                               \
+                                     PIN_ODR_HIGH(GPIOB_WL_MOSI))
+
+/*
+ * GPIOC setup:
+ *
+ * PC0  - PIN0                      (input floating)
+ * PC1  - PIN1                      (input floating)
+ * PC2  - PIN2                      (input floating)
+ * PC3  - PIN3                      (input floating)
+ * PC4  - LIGHT_XLAT                (output pushpull high 10MHz)
+ * PC5  - PIN5                      (input floating)
+ * PC6  - PIN6                      (input floating)
+ * PC7  - PIN7                      (input floating)
+ * PC8  - PIN8                      (input floating)
+ * PC9  - PIN9                      (input floating)
+ * PC10 - SYS_UART_RX               (input pullup)
+ * PC11 - SYS_UART_TX               (input pullup)
+ * PC12 - PIN12                     (input floating)
+ * PC13 - PIN13                     (input floating)
+ * PC14 - SYS_PD_N                  (output opendrain high 50MHz)
+ * PC15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOCCRL                (PIN_CR(GPIOC_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_LIGHT_XLAT, PIN_MODE_OUTPUT_10M, PIN_CNF_OUTPUT_PUSHPULL) |    \
+                                     PIN_CR(GPIOC_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOCCRH                (PIN_CR(GPIOC_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOC_SYS_UART_RX, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |            \
+                                     PIN_CR(GPIOC_SYS_UART_TX, PIN_MODE_INPUT, PIN_CNF_INPUT_PULLX) |            \
+                                     PIN_CR(GPIOC_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOC_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOC_SYS_PD_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |     \
+                                     PIN_CR(GPIOC_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOCODR                (PIN_ODR_LOW(GPIOC_PIN0) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN1) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN2) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN3) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_LIGHT_XLAT) |                                             \
+                                     PIN_ODR_LOW(GPIOC_PIN5) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN6) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN7) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN8) |                                                   \
+                                     PIN_ODR_LOW(GPIOC_PIN9) |                                                   \
+                                     PIN_ODR_HIGH(GPIOC_SYS_UART_RX) |                                           \
+                                     PIN_ODR_HIGH(GPIOC_SYS_UART_TX) |                                           \
+                                     PIN_ODR_LOW(GPIOC_PIN12) |                                                  \
+                                     PIN_ODR_LOW(GPIOC_PIN13) |                                                  \
+                                     PIN_ODR_HIGH(GPIOC_SYS_PD_N) |                                              \
+                                     PIN_ODR_LOW(GPIOC_PIN15))
+
+/*
+ * GPIOD setup:
+ *
+ * PD0  - OSC_IN                    (input floating)
+ * PD1  - OSC_OUT                   (input floating)
+ * PD2  - SYS_INT_N                 (output opendrain low 50MHz)
+ * PD3  - PIN3                      (input floating)
+ * PD4  - PIN4                      (input floating)
+ * PD5  - PIN5                      (input floating)
+ * PD6  - PIN6                      (input floating)
+ * PD7  - PIN7                      (input floating)
+ * PD8  - PIN8                      (input floating)
+ * PD9  - PIN9                      (input floating)
+ * PD10 - PIN10                     (input floating)
+ * PD11 - PIN11                     (input floating)
+ * PD12 - PIN12                     (input floating)
+ * PD13 - PIN13                     (input floating)
+ * PD14 - PIN14                     (input floating)
+ * PD15 - PIN15                     (input floating)
+ */
+#define VAL_GPIODCRL                (PIN_CR(GPIOD_OSC_IN, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |              \
+                                     PIN_CR(GPIOD_OSC_OUT, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |             \
+                                     PIN_CR(GPIOD_SYS_INT_N, PIN_MODE_OUTPUT_50M, PIN_CNF_OUTPUT_OPENDRAIN) |    \
+                                     PIN_CR(GPIOD_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIODCRH                (PIN_CR(GPIOD_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                \
+                                     PIN_CR(GPIOD_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOD_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOD_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOD_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOD_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |               \
+                                     PIN_CR(GPIOD_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIODODR                (PIN_ODR_HIGH(GPIOD_OSC_IN) |                                                \
+                                     PIN_ODR_HIGH(GPIOD_OSC_OUT) |                                               \
+                                     PIN_ODR_LOW(GPIOD_SYS_INT_N) |                                             \
+                                     PIN_ODR_LOW(GPIOD_PIN3) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN4) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN5) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN6) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN7) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN8) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN9) |                                                   \
+                                     PIN_ODR_LOW(GPIOD_PIN10) |                                                  \
+                                     PIN_ODR_LOW(GPIOD_PIN11) |                                                  \
+                                     PIN_ODR_LOW(GPIOD_PIN12) |                                                  \
+                                     PIN_ODR_LOW(GPIOD_PIN13) |                                                  \
+                                     PIN_ODR_LOW(GPIOD_PIN14) |                                                  \
+                                     PIN_ODR_LOW(GPIOD_PIN15))
+
+/*
+ * GPIOE setup:
+ *
+ * PE0  - PIN0                      (input floating)
+ * PE1  - PIN1                      (input floating)
+ * PE2  - PIN2                      (input floating)
+ * PE3  - PIN3                      (input floating)
+ * PE4  - PIN4                      (input floating)
+ * PE5  - PIN5                      (input floating)
+ * PE6  - PIN6                      (input floating)
+ * PE7  - PIN7                      (input floating)
+ * PE8  - PIN8                      (input floating)
+ * PE9  - PIN9                      (input floating)
+ * PE10 - PIN10                     (input floating)
+ * PE11 - PIN11                     (input floating)
+ * PE12 - PIN12                     (input floating)
+ * PE13 - PIN13                     (input floating)
+ * PE14 - PIN14                     (input floating)
+ * PE15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOECRL                (PIN_CR(GPIOE_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOECRH                (PIN_CR(GPIOE_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOE_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOE_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOEODR                (PIN_ODR_LOW(GPIOE_PIN0) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN1) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN2) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOE_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOE_PIN15))
+
+/*
+ * GPIOF setup:
+ *
+ * PF0  - PIN0                      (input floating)
+ * PF1  - PIN1                      (input floating)
+ * PF2  - PIN2                      (input floating)
+ * PF3  - PIN3                      (input floating)
+ * PF4  - PIN4                      (input floating)
+ * PF5  - PIN5                      (input floating)
+ * PF6  - PIN6                      (input floating)
+ * PF7  - PIN7                      (input floating)
+ * PF8  - PIN8                      (input floating)
+ * PF9  - PIN9                      (input floating)
+ * PF10 - PIN10                     (input floating)
+ * PF11 - PIN11                     (input floating)
+ * PF12 - PIN12                     (input floating)
+ * PF13 - PIN13                     (input floating)
+ * PF14 - PIN14                     (input floating)
+ * PF15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOFCRL                (PIN_CR(GPIOF_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOFCRH                (PIN_CR(GPIOF_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOF_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOF_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOFODR                (PIN_ODR_LOW(GPIOF_PIN0) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN1) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN2) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOF_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOF_PIN15))
+
+/*
+ * GPIOG setup:
+ *
+ * PG0  - PIN0                      (input floating)
+ * PG1  - PIN1                      (input floating)
+ * PG2  - PIN2                      (input floating)
+ * PG3  - PIN3                      (input floating)
+ * PG4  - PIN4                      (input floating)
+ * PG5  - PIN5                      (input floating)
+ * PG6  - PIN6                      (input floating)
+ * PG7  - PIN7                      (input floating)
+ * PG8  - PIN8                      (input floating)
+ * PG9  - PIN9                      (input floating)
+ * PG10 - PIN10                     (input floating)
+ * PG11 - PIN11                     (input floating)
+ * PG12 - PIN12                     (input floating)
+ * PG13 - PIN13                     (input floating)
+ * PG14 - PIN14                     (input floating)
+ * PG15 - PIN15                     (input floating)
+ */
+#define VAL_GPIOGCRL                (PIN_CR(GPIOG_PIN0, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN1, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN2, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN3, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN4, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN5, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN6, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN7, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOGCRH                (PIN_CR(GPIOG_PIN8, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN9, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                  \
+                                     PIN_CR(GPIOG_PIN10, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN11, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN12, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN13, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN14, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING) |                 \
+                                     PIN_CR(GPIOG_PIN15, PIN_MODE_INPUT, PIN_CNF_INPUT_FLOATING))
+#define VAL_GPIOGODR                (PIN_ODR_LOW(GPIOG_PIN0) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN1) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN2) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN3) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN4) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN5) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN6) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN7) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN8) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN9) |                                                     \
+                                     PIN_ODR_LOW(GPIOG_PIN10) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN11) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN12) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN13) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN14) |                                                    \
+                                     PIN_ODR_LOW(GPIOG_PIN15))
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* _BOARD_H_ */
diff --git a/os/modules/LightRing_1-0/board.mk b/os/modules/LightRing_1-0/board.mk
new file mode 100644
index 0000000..075d14d
--- /dev/null
+++ b/os/modules/LightRing_1-0/board.mk
@@ -0,0 +1,36 @@
+################################################################################
+# 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
+BOARD_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# include paths
+BOARDINC = $(BOARD_DIR)
+
+# C source files
+BOARDSRC = $(BOARD_DIR)board.c
+
+# linker path
+BOARDLD = $(AMIROOS)/hal/ports
diff --git a/os/modules/LightRing_1-0/chconf.h b/os/modules/LightRing_1-0/chconf.h
new file mode 100644
index 0000000..54561b4
--- /dev/null
+++ b/os/modules/LightRing_1-0/chconf.h
@@ -0,0 +1,593 @@
+/*
+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    os/modules/LightRing/chconf.h
+ * @brief   ChibiOS Configuration file for the LightRing module.
+ * @details Contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef _CHCONF_H_
+#define _CHCONF_H_
+
+#define _CHIBIOS_RT_CONF_
+
+#include <aosconf.h>
+
+/*===========================================================================*/
+/**
+ * @name System timers settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   System time counter resolution.
+ * @note    Allowed values are 16 or 32 bits.
+ */
+#define CH_CFG_ST_RESOLUTION                16
+
+/**
+ * @brief   System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ *          setting also defines the system tick time unit.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE != true) || defined(__DOXYGEN__)
+#define CH_CFG_ST_FREQUENCY                 1000000UL
+#else
+#define CH_CFG_ST_FREQUENCY                 100000UL
+#endif
+
+/**
+ * @brief   Time delta constant for the tick-less mode.
+ * @note    If this value is zero then the system uses the classic
+ *          periodic tick. This value represents the minimum number
+ *          of ticks that is safe to specify in a timeout directive.
+ *          The value one is not valid, timeouts are rounded up to
+ *          this value.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE != true) || defined(__DOXYGEN__)
+#define CH_CFG_ST_TIMEDELTA                 10
+#else
+#define CH_CFG_ST_TIMEDELTA                 2
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ *          threads before preemption occurs. Setting this value to zero
+ *          disables the preemption for threads with equal priority and the
+ *          round robin becomes cooperative. Note that higher priority
+ *          threads can still preempt, the kernel is always preemptive.
+ * @note    Disabling the round robin preemption makes the kernel more compact
+ *          and generally faster.
+ * @note    The round robin preemption is not supported in tickless mode and
+ *          must be set to zero in that case.
+ */
+#define CH_CFG_TIME_QUANTUM                 0
+
+/**
+ * @brief   Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ *          then the whole available RAM is used. The core memory is made
+ *          available to the heap allocator and/or can be used directly through
+ *          the simplified core memory allocator.
+ *
+ * @note    In order to let the OS manage the whole RAM the linker script must
+ *          provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note    Requires @p CH_CFG_USE_MEMCORE.
+ */
+#define CH_CFG_MEMCORE_SIZE                 0
+
+/**
+ * @brief   Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ *          does not spawn the idle thread. The application @p main()
+ *          function becomes the idle thread and must implement an
+ *          infinite loop.
+ */
+#define CH_CFG_NO_IDLE_THREAD               FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ *          is used when two possible implementations exist.
+ *
+ * @note    This is not related to the compiler optimization options.
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_OPTIMIZE_SPEED               TRUE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Time Measurement APIs.
+ * @details If enabled then the time measurement APIs are included in
+ *          the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_TM                       FALSE
+
+/**
+ * @brief   Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_REGISTRY                 FALSE
+
+/**
+ * @brief   Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ *          the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_WAITEXIT                 TRUE
+
+/**
+ * @brief   Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_SEMAPHORES               FALSE
+
+/**
+ * @brief   Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ *          priority rather than in FIFO order.
+ *
+ * @note    The default is @p FALSE. Enable this if you have special
+ *          requirements.
+ * @note    Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_SEMAPHORES_PRIORITY      FALSE
+
+/**
+ * @brief   Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MUTEXES                  TRUE
+
+/**
+ * @brief   Enables recursive behavior on mutexes.
+ * @note    Recursive mutexes are heavier and have an increased
+ *          memory footprint.
+ *
+ * @note    The default is @p FALSE.
+ * @note    Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_MUTEXES_RECURSIVE        FALSE
+
+/**
+ * @brief   Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_CONDVARS                 FALSE
+
+/**
+ * @brief   Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ *          specification are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_CONDVARS.
+ */
+#define CH_CFG_USE_CONDVARS_TIMEOUT         FALSE
+
+/**
+ * @brief   Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_EVENTS                   TRUE
+
+/**
+ * @brief   Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ *          are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_EVENTS.
+ */
+#define CH_CFG_USE_EVENTS_TIMEOUT           TRUE
+
+/**
+ * @brief   Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MESSAGES                 FALSE
+
+/**
+ * @brief   Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ *          FIFO order.
+ *
+ * @note    The default is @p FALSE. Enable this if you have special
+ *          requirements.
+ * @note    Requires @p CH_CFG_USE_MESSAGES.
+ */
+#define CH_CFG_USE_MESSAGES_PRIORITY        FALSE
+
+/**
+ * @brief   Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ *          included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_MAILBOXES                FALSE
+
+/**
+ * @brief   I/O Queues APIs.
+ * @details If enabled then the I/O queues APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_QUEUES                   FALSE
+
+/**
+ * @brief   Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMCORE                  FALSE
+
+/**
+ * @brief   Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
+ *          @p CH_CFG_USE_SEMAPHORES.
+ * @note    Mutexes are recommended.
+ */
+#define CH_CFG_USE_HEAP                     FALSE
+
+/**
+ * @brief   Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMPOOLS                 FALSE
+
+/**
+ * @brief   Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_WAITEXIT.
+ * @note    Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
+ */
+#define CH_CFG_USE_DYNAMIC                  FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Debug option, kernel statistics.
+ *
+ * @note    The default is @p FALSE.
+ */
+#define CH_DBG_STATISTICS                   FALSE
+
+/**
+ * @brief   Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ *          at runtime.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_SYSTEM_STATE_CHECK           TRUE
+#else
+#define CH_DBG_SYSTEM_STATE_CHECK           FALSE
+#endif
+
+/**
+ * @brief   Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ *          parameters are activated.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_CHECKS                TRUE
+#else
+#define CH_DBG_ENABLE_CHECKS                FALSE
+#endif
+
+/**
+ * @brief   Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ *          activated. This includes consistency checks inside the kernel,
+ *          runtime anomalies and port-defined checks.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_ASSERTS               TRUE
+#else
+#define CH_DBG_ENABLE_ASSERTS               FALSE
+#endif
+
+/**
+ * @brief   Debug option, trace buffer.
+ * @details If enabled then the trace buffer is activated.
+ *
+ * @note    The default is @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#define CH_DBG_TRACE_MASK                   CH_DBG_TRACE_MASK_DISABLED
+
+/**
+ * @brief   Trace buffer entries.
+ * @note    The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
+ *          different from @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#define CH_DBG_TRACE_BUFFER_SIZE            128
+
+/**
+ * @brief   Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note    The default is @p FALSE.
+ * @note    The stack check is performed in a architecture/port dependent way.
+ *          It may not be implemented or some ports.
+ * @note    The default failure mode is to halt the system with the global
+ *          @p panic_msg variable set to @p NULL.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_STACK_CHECK           TRUE
+#else
+#define CH_DBG_ENABLE_STACK_CHECK           FALSE
+#endif
+
+/**
+ * @brief   Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ *          value when a thread is created. This can be useful for the
+ *          runtime measurement of the used stack.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_PROFILE == true) || defined(__DOXYGEN__)
+#define CH_DBG_FILL_THREADS                 TRUE
+#else
+#define CH_DBG_FILL_THREADS                 FALSE
+#endif
+
+/**
+ * @brief   Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p thread_t structure that
+ *          counts the system ticks occurred while executing the thread.
+ *
+ * @note    The default is @p FALSE.
+ * @note    This debug option is not currently compatible with the
+ *          tickless mode.
+ */
+#if ((CH_CFG_ST_TIMEDELTA == 0) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+  #define CH_DBG_THREADS_PROFILING          TRUE
+#else
+  #define CH_DBG_THREADS_PROFILING          FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXTRA_FIELDS                                          \
+  /* Add threads custom fields here.*/
+
+/**
+ * @brief   Threads initialization hook.
+ * @details User initialization code added to the @p chThdInit() API.
+ *
+ * @note    It is invoked from within @p chThdInit() and implicitly from all
+ *          the threads creation APIs.
+ */
+#define CH_CFG_THREAD_INIT_HOOK(tp) {                                       \
+  /* Add threads initialization code here.*/                                \
+}
+
+/**
+ * @brief   Threads finalization hook.
+ * @details User finalization code added to the @p chThdExit() API.
+ *
+ * @note    It is inserted into lock zone.
+ * @note    It is also invoked when the threads simply return in order to
+ *          terminate.
+ */
+#define CH_CFG_THREAD_EXIT_HOOK(tp) {                                       \
+  /* Add threads finalization code here.*/                                  \
+}
+
+/**
+ * @brief   Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
+  /* Context switch code here.*/                                            \
+}
+
+/**
+ * @brief   ISR enter hook.
+ */
+#define CH_CFG_IRQ_PROLOGUE_HOOK() {                                        \
+  /* IRQ prologue code here.*/                                              \
+}
+
+/**
+ * @brief   ISR exit hook.
+ */
+#define CH_CFG_IRQ_EPILOGUE_HOOK() {                                        \
+  /* IRQ epilogue code here.*/                                              \
+}
+
+/**
+ * @brief   Idle thread enter hook.
+ * @note    This hook is invoked within a critical zone, no OS functions
+ *          should be invoked from here.
+ * @note    This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() {                                          \
+  /* Idle-enter code here.*/                                                \
+}
+
+/**
+ * @brief   Idle thread leave hook.
+ * @note    This hook is invoked within a critical zone, no OS functions
+ *          should be invoked from here.
+ * @note    This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() {                                          \
+  /* Idle-leave code here.*/                                                \
+}
+
+/**
+ * @brief   Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#define CH_CFG_IDLE_LOOP_HOOK() {                                           \
+  /* Idle loop code here.*/                                                 \
+}
+
+/**
+ * @brief   System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ *          after processing the virtual timers queue.
+ */
+#define CH_CFG_SYSTEM_TICK_HOOK() {                                         \
+  /* System tick event code here.*/                                         \
+}
+
+/**
+ * @brief   System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ *          the system is halted.
+ */
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) {                                   \
+  extern void aosPrintHaltErrorCode(const char* reason);                       \
+  aosPrintHaltErrorCode(reason);                                               \
+}
+
+/**
+ * @brief   Trace hook.
+ * @details This hook is invoked each time a new record is written in the
+ *          trace buffer.
+ */
+#define CH_CFG_TRACE_HOOK(tep) {                                            \
+  /* Trace code here.*/                                                     \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Port specific settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   NVIC VTOR initialization offset.
+ * @details On initialization, the code at this address in the flash memory will be executed.
+ */
+#define CORTEX_VTOR_INIT 0x00006000U
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name other
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Flag to enable/disable floating point support in chprinf()
+ */
+#define CHPRINTF_USE_FLOAT                  TRUE
+
+/** @} */
+
+#endif  /* _CHCONF_H_ */
+
+/** @} */
diff --git a/os/modules/LightRing_1-0/halconf.h b/os/modules/LightRing_1-0/halconf.h
new file mode 100644
index 0000000..743da09
--- /dev/null
+++ b/os/modules/LightRing_1-0/halconf.h
@@ -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    os/modules/LightRing/halconf.h
+ * @brief   HAL configuration header for the LightRing module.
+ * @details HAL configuration file, this file allows to enable or disable the
+ *          various device drivers from your application. You may also use
+ *          this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef _HALCONF_H_
+#define _HALCONF_H_
+
+/**
+ * @brief   Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL                 TRUE
+#endif
+
+/**
+ * @brief   Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN                 TRUE
+#endif
+
+/**
+ * @brief   Enables the DAC subsystem.
+ */
+#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
+#define HAL_USE_DAC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the EXT subsystem.
+ */
+#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
+#define HAL_USE_EXT                 TRUE
+#endif
+
+/**
+ * @brief   Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT                 FALSE
+#endif
+
+/**
+ * @brief   Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C                 TRUE
+#endif
+
+/**
+ * @brief   Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S                 FALSE
+#endif
+
+/**
+ * @brief   Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU                 FALSE
+#endif
+
+/**
+ * @brief   Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI             FALSE
+#endif
+
+/**
+ * @brief   Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM                 FALSE
+#endif
+
+/**
+ * @brief   Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC                 TRUE
+#endif
+
+/**
+ * @brief   Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL              TRUE
+#endif
+
+/**
+ * @brief   Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB          FALSE
+#endif
+
+/**
+ * @brief   Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI                 TRUE
+#endif
+
+/**
+ * @brief   Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART                FALSE
+#endif
+
+/**
+ * @brief   Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB                 FALSE
+#endif
+
+/**
+ * @brief   Enables the WDG subsystem.
+ */
+#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
+#define HAL_USE_WDG                 FALSE
+#endif
+
+/**
+ * @brief   Enables the QEI subsystem.
+ */
+#if !defined(HAL_USE_QEI) || defined(__DOXYGEN__)
+#define HAL_USE_QEI                 FALSE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT                FALSE
+#endif
+
+/**
+ * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION    FALSE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE          FALSE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION    TRUE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY           FALSE
+#endif
+
+/**
+ * @brief   Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS              FALSE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings.                                          */
+/*===========================================================================*/
+
+/**
+ * @brief   Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ *          routines releasing some extra CPU time for the threads with
+ *          lower priority, this may slow down the driver a bit however.
+ *          This option is recommended also if the SPI driver does not
+ *          use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING            FALSE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Number of initialization attempts before rejecting the card.
+ * @note    Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY              100
+#endif
+
+/**
+ * @brief   Include support for MMC cards.
+ * @note    MMC support is not yet implemented so this option must be kept
+ *          at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT             FALSE
+#endif
+
+/**
+ * @brief   Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ *          routines releasing some extra CPU time for the threads with
+ *          lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING            FALSE
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings.                                           */
+/*===========================================================================*/
+
+/**
+ * @brief   Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ *          default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE      115200
+#endif
+
+/**
+ * @brief   Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ *          buffers depending on the requirements of your application.
+ * @note    The default is 16 bytes for both the transmission and receive
+ *          buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE         16
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting.                                        */
+/*===========================================================================*/
+
+/**
+ * @brief   Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ *          the USB data endpoint maximum packet size.
+ * @note    The default is 256 bytes for both the transmission and receive
+ *          buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE     256
+#endif
+
+/**
+ * @brief   Serial over USB number of buffers.
+ * @note    The default is 2 buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_NUMBER   2
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT                TRUE
+#endif
+
+/**
+ * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION    TRUE
+#endif
+
+/*===========================================================================*/
+/* UART driver related settings.                                             */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT               FALSE
+#endif
+
+/**
+ * @brief   Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION   FALSE
+#endif
+
+/*===========================================================================*/
+/* USB driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
+#define USB_USE_WAIT                FALSE
+#endif
+
+#endif /* _HALCONF_H_ */
+
+/** @} */
diff --git a/os/modules/LightRing_1-0/mcuconf.h b/os/modules/LightRing_1-0/mcuconf.h
new file mode 100644
index 0000000..6381f70
--- /dev/null
+++ b/os/modules/LightRing_1-0/mcuconf.h
@@ -0,0 +1,227 @@
+/*
+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 _MCUCONF_H_
+#define _MCUCONF_H_
+
+#define STM32F103_MCUCONF
+
+/*
+ * STM32F103 drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 15...0       Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3        Lowest...Highest.
+ */
+
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT                       FALSE
+#define STM32_HSI_ENABLED                   TRUE
+#define STM32_LSI_ENABLED                   FALSE
+#define STM32_HSE_ENABLED                   TRUE
+#define STM32_LSE_ENABLED                   FALSE
+#define STM32_SW                            STM32_SW_PLL
+#define STM32_PLLSRC                        STM32_PLLSRC_HSE
+#define STM32_PLLXTPRE                      STM32_PLLXTPRE_DIV1
+#define STM32_PLLMUL_VALUE                  9
+#define STM32_HPRE                          STM32_HPRE_DIV1
+#define STM32_PPRE1                         STM32_PPRE1_DIV2
+#define STM32_PPRE2                         STM32_PPRE2_DIV2
+#define STM32_ADCPRE                        STM32_ADCPRE_DIV4
+#define STM32_USB_CLOCK_REQUIRED            TRUE
+#define STM32_USBPRE                        STM32_USBPRE_DIV1P5
+#define STM32_MCOSEL                        STM32_MCOSEL_NOCLOCK
+#define STM32_RTCSEL                        STM32_RTCSEL_HSEDIV
+#define STM32_PVD_ENABLE                    FALSE
+#define STM32_PLS                           STM32_PLS_LEV0
+
+/*
+ * ADC driver system settings.
+ */
+#define STM32_ADC_USE_ADC1                  FALSE
+#define STM32_ADC_ADC1_DMA_PRIORITY         2
+#define STM32_ADC_ADC1_IRQ_PRIORITY         6
+
+/*
+ * CAN driver system settings.
+ */
+#define STM32_CAN_USE_CAN1                  TRUE
+#define STM32_CAN_CAN1_IRQ_PRIORITY         11
+
+/*
+ * EXT driver system settings.
+ */
+#define STM32_EXT_EXTI0_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI1_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI2_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI3_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI4_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI5_9_IRQ_PRIORITY      6
+#define STM32_EXT_EXTI10_15_IRQ_PRIORITY    6
+#define STM32_EXT_EXTI16_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI17_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI18_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI19_IRQ_PRIORITY       6
+
+/*
+ * GPT driver system settings.
+ */
+#define STM32_GPT_USE_TIM1                  TRUE
+#define STM32_GPT_USE_TIM2                  FALSE
+#define STM32_GPT_USE_TIM3                  FALSE
+#define STM32_GPT_USE_TIM4                  FALSE
+#define STM32_GPT_USE_TIM5                  FALSE
+#define STM32_GPT_USE_TIM8                  FALSE
+#define STM32_GPT_TIM1_IRQ_PRIORITY         7
+#define STM32_GPT_TIM2_IRQ_PRIORITY         7
+#define STM32_GPT_TIM3_IRQ_PRIORITY         7
+#define STM32_GPT_TIM4_IRQ_PRIORITY         7
+#define STM32_GPT_TIM5_IRQ_PRIORITY         7
+#define STM32_GPT_TIM8_IRQ_PRIORITY         7
+
+/*
+ * I2C driver system settings.
+ */
+#define STM32_I2C_USE_I2C1                  FALSE
+#define STM32_I2C_USE_I2C2                  TRUE
+#define STM32_I2C_BUSY_TIMEOUT              50
+#define STM32_I2C_I2C1_IRQ_PRIORITY         5
+#define STM32_I2C_I2C2_IRQ_PRIORITY         5
+#define STM32_I2C_I2C1_DMA_PRIORITY         3
+#define STM32_I2C_I2C2_DMA_PRIORITY         3
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp)      osalSysHalt("DMA failure")
+#define STM32_I2C_USE_DMA                   FALSE
+
+/*
+ * ICU driver system settings.
+ */
+#define STM32_ICU_USE_TIM1                  FALSE
+#define STM32_ICU_USE_TIM2                  FALSE
+#define STM32_ICU_USE_TIM3                  FALSE
+#define STM32_ICU_USE_TIM4                  FALSE
+#define STM32_ICU_USE_TIM5                  FALSE
+#define STM32_ICU_USE_TIM8                  FALSE
+#define STM32_ICU_TIM1_IRQ_PRIORITY         7
+#define STM32_ICU_TIM2_IRQ_PRIORITY         7
+#define STM32_ICU_TIM3_IRQ_PRIORITY         7
+#define STM32_ICU_TIM4_IRQ_PRIORITY         7
+#define STM32_ICU_TIM5_IRQ_PRIORITY         7
+#define STM32_ICU_TIM8_IRQ_PRIORITY         7
+
+/*
+ * PWM driver system settings.
+ */
+#define STM32_PWM_USE_ADVANCED              FALSE
+#define STM32_PWM_USE_TIM1                  FALSE
+#define STM32_PWM_USE_TIM2                  FALSE
+#define STM32_PWM_USE_TIM3                  FALSE
+#define STM32_PWM_USE_TIM4                  FALSE
+#define STM32_PWM_USE_TIM5                  FALSE
+#define STM32_PWM_USE_TIM8                  FALSE
+#define STM32_PWM_TIM1_IRQ_PRIORITY         7
+#define STM32_PWM_TIM2_IRQ_PRIORITY         7
+#define STM32_PWM_TIM3_IRQ_PRIORITY         7
+#define STM32_PWM_TIM4_IRQ_PRIORITY         7
+#define STM32_PWM_TIM5_IRQ_PRIORITY         7
+#define STM32_PWM_TIM8_IRQ_PRIORITY         7
+
+/*
+ * RTC driver system settings.
+ */
+#define STM32_RTC_IRQ_PRIORITY              15
+
+/*
+ * SERIAL driver system settings.
+ */
+#define STM32_SERIAL_USE_USART1             TRUE
+#define STM32_SERIAL_USE_USART2             TRUE
+#define STM32_SERIAL_USE_USART3             FALSE
+#define STM32_SERIAL_USE_UART4              FALSE
+#define STM32_SERIAL_USE_UART5              FALSE
+#define STM32_SERIAL_USART1_PRIORITY        12
+#define STM32_SERIAL_USART2_PRIORITY        12
+#define STM32_SERIAL_USART3_PRIORITY        12
+#define STM32_SERIAL_UART4_PRIORITY         12
+#define STM32_SERIAL_UART5_PRIORITY         12
+
+/*
+ * SPI driver system settings.
+ */
+#define STM32_SPI_USE_SPI1                  TRUE
+#define STM32_SPI_USE_SPI2                  TRUE
+#define STM32_SPI_USE_SPI3                  FALSE
+#define STM32_SPI_SPI1_DMA_PRIORITY         1
+#define STM32_SPI_SPI2_DMA_PRIORITY         1
+#define STM32_SPI_SPI3_DMA_PRIORITY         1
+#define STM32_SPI_SPI1_IRQ_PRIORITY         10
+#define STM32_SPI_SPI2_IRQ_PRIORITY         10
+#define STM32_SPI_SPI3_IRQ_PRIORITY         10
+#define STM32_SPI_DMA_ERROR_HOOK(spip)      osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define STM32_ST_IRQ_PRIORITY               8
+#define STM32_ST_USE_TIMER                  2
+
+/*
+ * UART driver system settings.
+ */
+#define STM32_UART_USE_USART1               FALSE
+#define STM32_UART_USE_USART2               FALSE
+#define STM32_UART_USE_USART3               FALSE
+#define STM32_UART_USART1_IRQ_PRIORITY      12
+#define STM32_UART_USART2_IRQ_PRIORITY      12
+#define STM32_UART_USART3_IRQ_PRIORITY      12
+#define STM32_UART_USART1_DMA_PRIORITY      0
+#define STM32_UART_USART2_DMA_PRIORITY      0
+#define STM32_UART_USART3_DMA_PRIORITY      0
+#define STM32_UART_DMA_ERROR_HOOK(uartp)    osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_USB1                  FALSE
+#define STM32_USB_LOW_POWER_ON_SUSPEND      FALSE
+#define STM32_USB_USB1_HP_IRQ_PRIORITY      13
+#define STM32_USB_USB1_LP_IRQ_PRIORITY      14
+
+/*
+ * WDG driver system settings.
+ */
+#define STM32_WDG_USE_IWDG                  FALSE
+
+/*
+ * QEI driver system settings.
+ */
+#define STM32_QEI_USE_TIM1                  FALSE
+#define STM32_QEI_USE_TIM2                  FALSE
+#define STM32_QEI_USE_TIM3                  FALSE
+#define STM32_QEI_USE_TIM4                  FALSE
+#define STM32_QEI_USE_TIM5                  FALSE
+#define STM32_QEI_USE_TIM8                  FALSE
+
+#endif /* _MCUCONF_H_ */
diff --git a/os/modules/LightRing_1-0/module.c b/os/modules/LightRing_1-0/module.c
new file mode 100644
index 0000000..e27dda3
--- /dev/null
+++ b/os/modules/LightRing_1-0/module.c
@@ -0,0 +1,371 @@
+/*
+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 "module.h"
+
+/*===========================================================================*/
+/**
+ * @name Module specific functions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiroos.h>
+
+/**
+ * @brief   Interrupt service routine callback for I/O interrupt signals.
+ *
+ * @param   extp      EXT driver to handle the ISR.
+ * @param   channel   Channel on which the interrupt was encountered.
+ */
+static void _moduleIsrCallback(EXTDriver* extp, expchannel_t channel) {
+  (void)extp;
+
+  chSysLockFromISR();
+  chEvtBroadcastFlagsI(&aos.events.io.source, (1 << channel));
+  chSysUnlockFromISR();
+
+  return;
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name ChibiOS/HAL configuration
+ * @{
+ */
+/*===========================================================================*/
+
+CANConfig moduleHalCanConfig = {
+  /* mcr  */ CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
+  /* btr  */ CAN_BTR_SJW(1) | CAN_BTR_TS2(2) | CAN_BTR_TS1(13) | CAN_BTR_BRP(1),
+};
+
+EXTConfig moduleHalExtConfig = {
+  /* channel configrations */ {
+    /* channel  0 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  1 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  2 */ { // SYS_SYNC_N: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOD | EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback
+    },
+    /* channel  3 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  4 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  5 */ { // LASER_OC_N: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_FALLING_EDGE,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  6 */ { // SYS_UART_DN: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  7 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel  8 */ { // WL_GDO0: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_BOTH_EDGES,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  9 */ { // WL_GDO2: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_BOTH_EDGES,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 10 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 11 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 12 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 13 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 14 */ { // SYS_PD_N: automatic interrupt when activated
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback
+    },
+    /* channel 15 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 16 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 17 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 18 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+  }
+};
+
+I2CConfig moduleHalI2cEepromConfig = {
+  /* I²C mode   */ OPMODE_I2C,
+  /* frequency  */ 400000, // TODO: replace with some macro (-> ChibiOS/HAL)
+  /* duty cycle */ FAST_DUTY_CYCLE_2,
+};
+
+SerialConfig moduleHalProgIfConfig = {
+  /* bit rate */ 115200,
+  /* CR1      */ 0,
+  /* CR1      */ 0,
+  /* CR1      */ 0,
+};
+
+SPIConfig moduleHalSpiLightConfig = {
+  /* callback function pointer   */ NULL,
+  /* chip select line port       */ GPIOC,
+  /* chip select line pad number */ GPIOC_LIGHT_XLAT,
+  /* CR1                         */ SPI_CR1_BR_0 | SPI_CR1_BR_1,
+  /* CR2                         */ SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN,
+};
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+
+apalGpio_t moduleGpioLightBlank = {
+  /* port */ GPIOA,
+  /* pad  */ GPIOA_LIGHT_BLANK,
+};
+
+apalGpio_t moduleGpioLaserEn = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_LASER_EN,
+};
+
+apalGpio_t moduleGpioLaserOc = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_LASER_OC_N,
+};
+
+apalGpio_t moduleGpioSysUartDn = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_SYS_UART_DN,
+};
+
+apalGpio_t moduleGpioWlGdo2 = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_WL_GDO2,
+};
+
+apalGpio_t moduleGpioWlGdo0= {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_WL_GDO0,
+};
+
+apalGpio_t moduleGpioLightXlat = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_LIGHT_XLAT,
+};
+
+apalGpio_t moduleGpioSysPd = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_PD_N,
+};
+
+apalGpio_t moduleGpioSysSync = {
+  /* port */ GPIOD,
+  /* pad  */ GPIOD_SYS_INT_N,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name AMiRo-OS core configurations
+ * @{
+ */
+/*===========================================================================*/
+
+apalControlGpio_t moduleSsspPd = {
+  /* GPIO */ &moduleGpioSysPd,
+  /* meta */ {
+    /* active state */ APAL_GPIO_ACTIVE_LOW,
+    /* edge         */ APAL_GPIO_EDGE_FALLING,
+    /* direction    */ APAL_GPIO_DIRECTION_BIDIRECTIONAL,
+  },
+};
+
+apalControlGpio_t moduleSsspSync = {
+  /* GPIO */ &moduleGpioSysSync,
+  /* meta */ {
+    /* active state */ APAL_GPIO_ACTIVE_LOW,
+    /* edge         */ APAL_GPIO_EDGE_FALLING,
+    /* direction    */ APAL_GPIO_DIRECTION_BIDIRECTIONAL,
+  },
+};
+
+const char* moduleShellPrompt = "LightRing";
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+
+AT24C01BNDriver moduleLldEeprom = {
+  /* I2C driver   */ &MODULE_HAL_I2C_EEPROM,
+  /* I2C address  */ 0x00u,
+};
+
+TLC5947Driver moduleLldLedPwm = {
+  /* SPI driver         */ &MODULE_HAL_SPI_LIGHT,
+  /* BLANK signal GPIO  */ {
+    /* GPIO */ &moduleGpioLightBlank,
+    /* meta */ {
+      /* active state */ TLC5947_LLD_BLANK_ACTIVE_STATE,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+  /* XLAT signal GPIO   */ {
+    /* GPIO */ &moduleGpioLightXlat,
+    /* meta */ {
+      /* active state */ TLC5947_LLD_XLAT_ACTIVE_STATE,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+};
+
+TPS2051BDriver moduleLldPowerSwitchLaser = {
+  /* laser enable gpio */ {
+    /* GPIO */ &moduleGpioLaserEn,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+  /* laser overcurrent gpio */ {
+    /* GPIO         */ &moduleGpioLaserOc,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Unit tests (UT)
+ * @{
+ */
+/*===========================================================================*/
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+
+/* EEPROM (AT24C01BN) */
+static int _utShellCmdCb_AlldAt24c01bn(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldAt24c01bn, NULL);
+  return AOS_OK;
+}
+static ut_at24c01bndata_t _utAt24c01bnData = {
+  /* driver   */ &moduleLldEeprom,
+  /* timeout  */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldAt24c01bn = {
+  /* name           */ "AT24C01BN-SH-B",
+  /* info           */ "1kbit EEPROM",
+  /* test function  */ utAlldAt24c01bnFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:EEPROM",
+    /* callback */ _utShellCmdCb_AlldAt24c01bn,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAt24c01bnData,
+};
+
+/* LED PWM driver (TLD5947) */
+static int _utShellCmdCb_Tlc5947(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldTlc5947, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldTlc5947 = {
+  /* info           */ "TLC5947",
+  /* name           */ "LED PWM driver",
+  /* test function  */ utAlldTlc5947Func,
+  /* shell command  */ {
+    /* name     */ "unittest:Lights",
+    /* callback */ _utShellCmdCb_Tlc5947,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldLedPwm,
+};
+
+/* power switch (Laser) */
+static int _utShellCmdCb_Tps2051bdbv(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream,&moduleUtAlldTps2051bdbv, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldTps2051bdbv = {
+  /* info           */ "TPS2051BDBV",
+  /* name           */ "current-limited power switch",
+  /* test function  */ utAlldTps2051bdbvFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:PowerSwitch",
+    /* callback */ _utShellCmdCb_Tps2051bdbv,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldPowerSwitchLaser,
+};
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
diff --git a/os/modules/LightRing_1-0/module.h b/os/modules/LightRing_1-0/module.h
new file mode 100644
index 0000000..5e06d5d
--- /dev/null
+++ b/os/modules/LightRing_1-0/module.h
@@ -0,0 +1,331 @@
+/*
+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
+ * @{
+ */
+/*===========================================================================*/
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @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   Interrupt driver to use.
+ */
+#define MODULE_HAL_EXT                          EXTD1
+
+/**
+ * @brief   Interrupt driver configuration.
+ */
+extern EXTConfig moduleHalExtConfig;
+
+/**
+ * @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   Configuration for the SPI interface driver to communicate with the LED driver.
+ */
+extern SPIConfig moduleHalSpiLightConfig;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiro-lld.h>
+
+/**
+ * @brief   Interrupt channel for the SYS_SYNC signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSSYNC          ((expchannel_t)2)
+
+/**
+ * @brief   Interrupt channel for the LASER_OC signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_LASEROC          ((expchannel_t)5)
+
+/**
+ * @brief   Interrupt channel for the SYS_UART_DN signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSUARTDN        ((expchannel_t)6)
+
+/**
+ * @brief   Interrupt channel for the WL_GDO2 signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_WLGDO2           ((expchannel_t)8)
+
+/**
+ * @brief   Interrupt channel for the WL_GDO0 signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_WLGDO0           ((expchannel_t)9)
+
+/**
+ * @brief   Interrupt channel for the SYS_PD signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSPD            ((expchannel_t)14)
+
+/**
+ * @brief   LIGHT_BANK output signal GPIO.
+ */
+extern apalGpio_t moduleGpioLightBlank;
+
+/**
+ * @brief   LASER_EN output signal GPIO.
+ */
+extern apalGpio_t moduleGpioLaserEn;
+
+/**
+ * @brief   LASER_OC input signal GPIO.
+ */
+extern apalGpio_t moduleGpioLaserOc;
+
+/**
+ * @brief   SYS_UART_DN bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysUartDn;
+
+/**
+ * @brief   WL_GDO2 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioWlGdo2;
+
+/**
+ * @brief   WL_GDO0 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioWlGdo0;
+
+/**
+ * @brief   LIGHT_XLAT output signal GPIO.
+ */
+extern apalGpio_t moduleGpioLightXlat;
+
+/**
+ * @brief   SYS_PD bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysPd;
+
+/**
+ * @brief   SYS_SYNC bidirectional signal GPIO.
+ */
+extern apalGpio_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 << MODULE_GPIO_EXTCHANNEL_LASEROC))
+
+/**
+ * @brief   Event flag to be set on a SYS_UART_DN interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSUARTDN        ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSUARTDN))
+
+/**
+ * @brief   Event flag to be set on a WL_GDO2 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_WLGDO2           ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_WLGDO2))
+
+/**
+ * @brief   Event flag to be set on a WL_GDO0 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_WLGDO0           ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_WLGDO0))
+
+/**
+ * @brief   Event flag to be set on a SYS_PD interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSPD            ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSPD))
+
+/**
+ * @brief   Event flag to be set on a SYS_SYNC interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSSYNC          ((eventflags_t)(1 << MODULE_GPIO_EXTCHANNEL_SYSSYNC))
+
+/**
+ * @brief   PD signal for SSSP.
+ */
+extern apalControlGpio_t moduleSsspPd;
+
+/**
+ * @brief   SYNC signal for SSSP.
+ */
+extern apalControlGpio_t moduleSsspSync;
+
+/**
+ * @brief   Shell prompt text.
+ */
+extern const char* moduleShellPrompt;
+
+/**
+ * @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);           \
+}
+
+/**
+ * @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);                  \
+}
+
+/**
+ * @brief   Hook to handle IO events during SSSP startup synchronization.
+ */
+#define MODULE_SSP_STARTUP_OUTRO_IO_EVENT(mask, flags) {                      \
+  /* ignore all events */                                                     \
+  (void)mask;                                                                 \
+  (void)flags;                                                                \
+}
+
+/**
+ * @brief   Periphery communication interface deinitialization hook.
+ */
+#define MODULE_SHUTDOWN_PERIPHERY_COMM() {                                    \
+  /* SPI */                                                                   \
+  spiStop(&MODULE_HAL_SPI_LIGHT);                                             \
+  /* I2C */                                                                   \
+  i2cStop(&MODULE_HAL_I2C_EEPROM);                                            \
+  /* don't stop the serial driver so messages can still be printed */         \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+#include <alld_at24c01bn-sh-b.h>
+#include <alld_tlc5947.h>
+#include <alld_tps2051bdbv.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;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @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>
+
+/**
+ * @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;
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
+
+#endif /* _AMIROOS_MODULE_H_ */
diff --git a/os/modules/Makefile b/os/modules/Makefile
new file mode 100644
index 0000000..21c6306
--- /dev/null
+++ b/os/modules/Makefile
@@ -0,0 +1,45 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+
+
+all: modules
+
+include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))modules.mk
+
+CLEANTRGS = $(MODULES:%=clean_%)
+FLASHTRGS = $(MODULES:%=flash_%)
+
+.PHONY: $(MODULES)
+
+modules: $(MODULES)
+$(MODULES):
+	$(MAKE) -C $(MODULES_DIR)$@
+
+flash: $(FLASHTRGS)
+$(FLASHTRGS):
+	$(MAKE) -C $(MODULES_DIR)$(@:flash_%=%) flash
+
+clean: $(CLEANTRGS)
+$(CLEANTRGS):
+	$(MAKE) -C $(MODULES_DIR)$(@:clean_%=%) clean
diff --git a/os/modules/PowerManagement_1-1/Makefile b/os/modules/PowerManagement_1-1/Makefile
new file mode 100644
index 0000000..bb493eb
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/Makefile
@@ -0,0 +1,302 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+
+
+################################################################################
+# Build global options                                                         #
+# NOTE: Can be overridden externally.                                          #
+#                                                                              #
+
+# Compiler options here.
+ifeq ($(USE_OPT),)
+  USE_OPT = -O2 -fomit-frame-pointer -falign-functions=16 -fstack-usage
+endif
+
+# C specific options here (added to USE_OPT).
+ifeq ($(USE_COPT),)
+  USE_COPT = -std=c99
+endif
+
+# C++ specific options here (added to USE_OPT).
+ifeq ($(USE_CPPOPT),)
+  USE_CPPOPT = -fno-rtti -std=c++14
+endif
+
+# Enable this if you want the linker to remove unused code and data
+ifeq ($(USE_LINK_GC),)
+  USE_LINK_GC = yes
+endif
+
+# Linker extra options here.
+ifeq ($(USE_LDOPT),)
+  USE_LDOPT =
+endif
+
+# Enable this if you want link time optimizations (LTO)
+ifeq ($(USE_LTO),)
+  USE_LTO = yes
+endif
+
+# If enabled, this option allows to compile the application in THUMB mode.
+ifeq ($(USE_THUMB),)
+  USE_THUMB = yes
+endif
+
+# Enable this if you want to see the full log while compiling.
+ifeq ($(USE_VERBOSE_COMPILE),)
+  USE_VERBOSE_COMPILE = no
+endif
+
+# If enabled, this option makes the build process faster by not compiling
+# modules not used in the current configuration.
+ifeq ($(USE_SMART_BUILD),)
+  USE_SMART_BUILD = yes
+endif
+
+#                                                                              #
+# Build global options                                                         #
+################################################################################
+
+################################################################################
+# Architecture or project specific options                                     #
+#                                                                              #
+
+# Stack size to be allocated to the Cortex-M process stack. This stack is
+# the stack used by the main() thread.
+ifneq ($(MAIN_STACKSIZE_POWERMANAGEMENT),)
+  USE_PROCESS_STACKSIZE = $(MAIN_STACKSIZE_POWERMANAGEMENT)
+endif
+ifeq ($(USE_PROCESS_STACKSIZE),)
+  USE_PROCESS_STACKSIZE = 0x400
+endif
+
+# Stack size to the allocated to the Cortex-M main/exceptions stack. This
+# stack is used for processing interrupts and exceptions.
+ifneq ($(EXCEPTIONS_STACKSIZE_POWERMANAGEMENT),)
+  USE_PROCESS_STACKSIZE = $(EXCEPTIONS_STACKSIZE_POWERMANAGEMENT)
+endif
+ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
+  USE_EXCEPTIONS_STACKSIZE = 0x400
+endif
+
+# Enables the use of FPU on Cortex-M4.
+# Possible selections are:
+#   no     - no FPU is used (propably equals 'soft')
+#   soft   - does not use the FPU, thus all floating point operations are emulated
+#   softfp - uses the FPU, but uses the integer registers only
+#   hard   - uses the FPU and passes data via the FPU registers
+ifeq ($(USE_FPU),)
+  USE_FPU = softfp
+endif
+
+#                                                                              #
+# Architecture or project specific options                                     #
+################################################################################
+
+################################################################################
+# Project, sources and paths                                                   #
+#                                                                              #
+
+# Define project name here
+PROJECT := $(patsubst $(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))..)/%,%,$(abspath $(dir $(abspath $(lastword $(MAKEFILE_LIST))))))
+
+# Imported source files and paths
+include ../../../kernel/kernel.mk
+CHIBIOS := $(AMIROOS_KERNEL)
+AMIROOS = ../..
+# Startup files
+include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
+# HAL-OSAL files
+include $(CHIBIOS)/os/hal/hal.mk
+include $(AMIROOS)/hal/hal.mk
+include $(CHIBIOS)/os/hal/ports/STM32/STM32F4xx/platform.mk
+include $(AMIROOS)/hal/ports/STM32/platform.mk
+include ./board.mk
+include $(CHIBIOS)/os/hal/osal/rt/osal.mk
+# RTOS files
+include $(CHIBIOS)/os/rt/rt.mk
+include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
+# Other files (optional).
+include $(CHIBIOS)/test/rt/test.mk
+# AMiRo-BLT files
+include ../../../bootloader/bootloader.mk
+# AMiRo-LLD files
+include ../../../periphery-lld/periphery-lld.mk
+# AMiRo-OS files
+include $(AMIROOS)/modules/modules.mk
+include $(AMIROOS)/core/core.mk
+include $(AMIROOS)/unittests/unittests.mk
+
+# Define linker script file here
+LDSCRIPT= $(BOARDLD)/STM32F405xG.ld
+
+# C sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CSRC = $(STARTUPSRC) \
+       $(KERNSRC) \
+       $(PORTSRC) \
+       $(OSALSRC) \
+       $(HALSRC) \
+       $(PLATFORMSRC) \
+       $(BOARDSRC) \
+       $(MODULESCSRC) \
+       $(TESTSRC) \
+       $(PERIPHERYLLDCSRC) \
+       $(AMIROOSCORECSRC) \
+       $(UNITTESTSCSRC) \
+       $(CHIBIOS)/os/various/evtimer.c \
+       $(CHIBIOS)/os/various/syscalls.c \
+       $(CHIBIOS)/os/hal/lib/streams/chprintf.c \
+       module.c \
+       $(APPSCSRC_POWERMANAGEMENT)
+
+# C++ sources that can be compiled in ARM or THUMB mode depending on the global
+# setting.
+CPPSRC = $(APPSCPPSRC_POWERMANAGEMENT)
+
+# C sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACSRC =
+
+# C++ sources to be compiled in ARM mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+ACPPSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCSRC =
+
+# C sources to be compiled in THUMB mode regardless of the global setting.
+# NOTE: Mixing ARM and THUMB mode enables the -mthumb-interwork compiler
+#       option that results in lower performance and larger code size.
+TCPPSRC =
+
+# List ASM source files here
+ASMSRC =
+ASMXSRC = $(STARTUPASM) \
+          $(PORTASM) \
+          $(OSALASM)
+
+INCDIR = $(CHIBIOS)/os/license \
+         $(STARTUPINC) \
+         $(KERNINC) \
+         $(PORTINC) \
+         $(OSALINC) \
+         $(HALINC) \
+         $(PLATFORMINC) \
+         $(BOARDINC) \
+         $(MODULESINC) \
+         $(TESTINC) \
+         $(BOOTLOADERINC) \
+         $(CHIBIOS)/os/hal/lib/streams \
+         $(CHIBIOS)/os/various \
+         $(PERIPHERYLLDINC) \
+         $(AMIROOS) \
+         $(AMIROOSCOREINC) \
+         $(UNITTESTSINC) \
+         $(APPSINC_POWERMANAGEMENT)
+
+#                                                                              #
+# Project, sources and paths                                                   #
+################################################################################
+
+################################################################################
+# Compiler settings                                                            #
+# NOTE: Some can be overridden externally.                                     #
+#                                                                              #
+
+MCU  = cortex-m4
+
+#TRGT = arm-elf-
+TRGT = arm-none-eabi-
+CC   = $(TRGT)gcc
+CPPC = $(TRGT)g++
+# Enable loading with g++ only if you need C++ runtime support.
+# NOTE: You can use C++ even without C++ support if you are careful. C++
+#       runtime support makes code size explode.
+LD   = $(TRGT)gcc
+#LD   = $(TRGT)g++
+CP   = $(TRGT)objcopy
+AS   = $(TRGT)gcc -x assembler-with-cpp
+AR   = $(TRGT)ar
+OD   = $(TRGT)objdump
+SZ   = $(TRGT)size
+HEX  = $(CP) -O ihex
+BIN  = $(CP) -O binary
+SREC = $(CP) -O srec --srec-len=248
+
+# ARM-specific options here
+ifeq ($(AOPT),)
+  AOPT =
+endif
+
+# THUMB-specific options here
+ifeq ($(TOPT),)
+  TOPT = -mthumb -DTHUMB
+endif
+
+# Define C warning options here
+ifeq ($(CWARN),)
+  CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
+endif
+
+# Define C++ warning options here
+ifeq ($(CPPWARN),)
+  CPPWARN = -Wall -Wextra -Wundef
+endif
+
+#                                                                              #
+# Compiler settings                                                            #
+################################################################################
+
+################################################################################
+# Start of user section                                                        #
+#                                                                              #
+
+# List all user C define here, like -D_DEBUG=1
+UDEFS +=
+
+# Define ASM defines here
+UADEFS +=
+
+# List all user directories here
+UINCDIR +=
+
+# List the user directory to look for the libraries here
+ULIBDIR +=
+
+# List all user libraries here
+ULIBS +=
+
+#                                                                              #
+# End of user defines                                                          #
+################################################################################
+
+RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
+include $(RULESPATH)/rules.mk
+
+include $(AMIROOS)/modules/flash.mk
diff --git a/os/modules/PowerManagement_1-1/alldconf.h b/os/modules/PowerManagement_1-1/alldconf.h
new file mode 100644
index 0000000..14572d2
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/alldconf.h
@@ -0,0 +1,84 @@
+/*
+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 _ALLDCONF_H_
+#define _ALLDCONF_H_
+
+/*
+ * compatibility guards
+ */
+#define _AMIRO_LLD_CFG_
+#define AMIRO_LLD_CFG_VERSION_MAJOR         1
+#define AMIRO_LLD_CFG_VERSION_MINOR         0
+
+/**
+ * @brief   Enable flag for the AT24C01BN-SH-B EEPROM.
+ */
+#define AMIROLLD_CFG_USE_AT24C01BN
+
+/**
+ * @brief   Enable flag for the BQ24103A charger.
+ */
+#define AMIROLLD_CFG_USE_BQ24103A
+
+/**
+ * @brief   Enable flag for the BQ27500 fuel gauge.
+ */
+#define AMIROLLD_CFG_USE_BQ27500
+
+/**
+ * @brief   Enable flag for the INA219 power monitor.
+ */
+#define AMIROLLD_CFG_USE_INA219
+
+/**
+ * @brief   Enable flag for the status LED.
+ */
+#define AMIROLLD_CFG_USE_LED
+
+/**
+ * @brief   Enable flag for the MPR121 touch sensor.
+ */
+#define AMIROLLD_CFG_USE_MPR121
+
+/**
+ * @brief   Enable flag for the PCA9544A I2C multiplexer.
+ */
+#define AMIROLLD_CFG_USE_PCA9544A
+
+/**
+ * @brief   Enable flag for the PKLCS1212E4001 buzzer.
+ */
+#define AMIROLLD_CFG_USE_PKLCS1212E4001
+
+/**
+ * @brief   Enable flag for the TPS2051BDBV power switch.
+ */
+#define AMIROLLD_CFG_USE_TPS2051BDBV
+
+/**
+ * @brief   Enable flag for the TPS62113 step-down converter.
+ */
+#define AMIROLLD_CFG_USE_TPS62113
+
+/**
+ * @brief   Enable flag for the VCNL4020 proximity sensor.
+ */
+#define AMIROLLD_CFG_USE_VCNL4020
+
+#endif /* _ALLDCONF_H_ */
diff --git a/os/modules/PowerManagement_1-1/aosconf.h b/os/modules/PowerManagement_1-1/aosconf.h
new file mode 100644
index 0000000..e280715
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/aosconf.h
@@ -0,0 +1,152 @@
+/*
+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 _AOSCONF_H_
+#define _AOSCONF_H_
+
+/*
+ * compatibility guards
+ */
+#define _AMIRO_OS_CFG_
+#define _AMIRO_OS_CFG_VERSION_MAJOR_            2
+#define _AMIRO_OS_CFG_VERSION_MINOR_            0
+
+#include <stdbool.h>
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/*
+ * Include an external configuration file to override the following default settings only if required.
+ */
+#if defined(AMIRO_APPS) && (AMIRO_APPS == true)
+  #include <osconf.h>
+#endif
+
+/**
+ * @brief   Flag to set the module as SSSP master.
+ */
+#if !defined(OS_CFG_SSSP_MASTER)
+  #define AMIROOS_CFG_SSSP_MASTER               true
+#else
+  #define AMIROOS_CFG_SSSP_MASTER               OS_CFG_SSSP_MASTER
+#endif
+
+/**
+ * @brief   Time boundary for robot wide clock synchronization in microseconds.
+ * @details Whenever the SSSP S (snychronization) signal gets logically deactivated,
+ *          All modules need to align their local uptime to the nearest multiple of this value.
+ */
+#if !defined(OS_CFG_SSSP_SYSSYNCPERIOD)
+  #define AMIROOS_CFG_SSSP_SYSSYNCPERIOD        1000000
+#else
+  #define AMIROOS_CFG_SSSP_SYSSYNCPERIOD        OS_CFG_SSSP_SYSSYNCPERIOD
+#endif
+
+/**
+ * @brief   Flag to enable/disable debug API.
+ */
+#if !defined(OS_CFG_DBG)
+  #define AMIROOS_CFG_DBG                       true
+#else
+  #define AMIROOS_CFG_DBG                       OS_CFG_DBG
+#endif
+
+/**
+ * @brief   Flag to enable/disable unit tests.
+ */
+#if !defined(OS_CFG_TESTS_ENABLE)
+  #define AMIROOS_CFG_TESTS_ENABLE              true
+#else
+  #define AMIROOS_CFG_TESTS_ENABLE              OS_CFG_TESTS_ENABLE
+#endif
+
+/**
+ * @brief   Flag to enable/disable profiling API.
+ */
+#if !defined(OS_CFG_PROFILE)
+  #define AMIROOS_CFG_PROFILE                   true
+#else
+  #define AMIROOS_CFG_PROFILE                   OS_CFG_PROFILE
+#endif
+
+/**
+ * @brief   Timeout value when waiting for events in the main loop in microseconds.
+ * @details A value of 0 deactivates the timeout.
+ */
+#if !defined(OS_CFG_MAIN_LOOP_TIMEOUT)
+  #define AMIROOS_CFG_MAIN_LOOP_TIMEOUT         0
+#else
+  #define AMIROOS_CFG_MAIN_LOOP_TIMEOUT         OS_CFG_MAIN_LOOP_TIMEOUT
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name System shell options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Shell enable flag.
+ */
+#if (AMIROOS_CFG_TESTS_ENABLE == false) && !defined(OS_CFG_SHELL_ENABLE)
+  #define AMIROOS_CFG_SHELL_ENABLE              true
+#elif (AMIROOS_CFG_TESTS_ENABLE == true)
+  #define AMIROOS_CFG_SHELL_ENABLE              true
+#else
+  #define AMIROOS_CFG_SHELL_ENABLE              OS_CFG_SHELL_ENABLE
+#endif
+
+/**
+ * @brief   Shell thread stack size.
+ */
+#if !defined(OS_CFG_SHELL_STACKSIZE)
+  #define AMIROOS_CFG_SHELL_STACKSIZE           1024
+#else
+  #define AMIROOS_CFG_SHELL_STACKSIZE           OS_CFG_SHELL_STACKSIZE
+#endif
+
+/**
+ * @brief   Shell maximum input line length.
+ */
+#if !defined(OS_CFG_SHELL_LINEWIDTH)
+  #define AMIROOS_CFG_SHELL_LINEWIDTH           64
+#else
+  #define AMIROOS_CFG_SHELL_LINEWIDTH           OS_CFG_SHELL_LINEWIDTH
+#endif
+
+/**
+ * @brief   Shell maximum number of arguments.
+ */
+#if !defined(OS_CFG_SHELL_MAXARGS)
+  #define AMIROOS_CFG_SHELL_MAXARGS             4
+#else
+  #define AMIROOS_CFG_SHELL_MAXARGS             OS_CFG_SHELL_MAXARGS
+#endif
+
+/** @} */
+
+#endif // _AOSCONF_H_
+
diff --git a/os/modules/PowerManagement_1-1/board.c b/os/modules/PowerManagement_1-1/board.c
new file mode 100644
index 0000000..7e6ad50
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/board.c
@@ -0,0 +1,82 @@
+/*
+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 <hal.h>
+
+#if HAL_USE_PAL || defined(__DOXYGEN__)
+/**
+ * @brief   PAL setup.
+ * @details Digital I/O ports static configuration as defined in @p board.h.
+ *          This variable is used by the HAL when initializing the PAL driver.
+ */
+const PALConfig pal_default_config = {
+#if STM32_HAS_GPIOA
+  {VAL_GPIOA_MODER, VAL_GPIOA_OTYPER, VAL_GPIOA_OSPEEDR, VAL_GPIOA_PUPDR,
+   VAL_GPIOA_ODR,   VAL_GPIOA_AFRL,   VAL_GPIOA_AFRH},
+#endif
+#if STM32_HAS_GPIOB
+  {VAL_GPIOB_MODER, VAL_GPIOB_OTYPER, VAL_GPIOB_OSPEEDR, VAL_GPIOB_PUPDR,
+   VAL_GPIOB_ODR,   VAL_GPIOB_AFRL,   VAL_GPIOB_AFRH},
+#endif
+#if STM32_HAS_GPIOC
+  {VAL_GPIOC_MODER, VAL_GPIOC_OTYPER, VAL_GPIOC_OSPEEDR, VAL_GPIOC_PUPDR,
+   VAL_GPIOC_ODR,   VAL_GPIOC_AFRL,   VAL_GPIOC_AFRH},
+#endif
+#if STM32_HAS_GPIOD
+  {VAL_GPIOD_MODER, VAL_GPIOD_OTYPER, VAL_GPIOD_OSPEEDR, VAL_GPIOD_PUPDR,
+   VAL_GPIOD_ODR,   VAL_GPIOD_AFRL,   VAL_GPIOD_AFRH},
+#endif
+#if STM32_HAS_GPIOE
+  {VAL_GPIOE_MODER, VAL_GPIOE_OTYPER, VAL_GPIOE_OSPEEDR, VAL_GPIOE_PUPDR,
+   VAL_GPIOE_ODR,   VAL_GPIOE_AFRL,   VAL_GPIOE_AFRH},
+#endif
+#if STM32_HAS_GPIOF
+  {VAL_GPIOF_MODER, VAL_GPIOF_OTYPER, VAL_GPIOF_OSPEEDR, VAL_GPIOF_PUPDR,
+   VAL_GPIOF_ODR,   VAL_GPIOF_AFRL,   VAL_GPIOF_AFRH},
+#endif
+#if STM32_HAS_GPIOG
+  {VAL_GPIOG_MODER, VAL_GPIOG_OTYPER, VAL_GPIOG_OSPEEDR, VAL_GPIOG_PUPDR,
+   VAL_GPIOG_ODR,   VAL_GPIOG_AFRL,   VAL_GPIOG_AFRH},
+#endif
+#if STM32_HAS_GPIOH
+  {VAL_GPIOH_MODER, VAL_GPIOH_OTYPER, VAL_GPIOH_OSPEEDR, VAL_GPIOH_PUPDR,
+   VAL_GPIOH_ODR,   VAL_GPIOH_AFRL,   VAL_GPIOH_AFRH},
+#endif
+#if STM32_HAS_GPIOI
+  {VAL_GPIOI_MODER, VAL_GPIOI_OTYPER, VAL_GPIOI_OSPEEDR, VAL_GPIOI_PUPDR,
+   VAL_GPIOI_ODR,   VAL_GPIOI_AFRL,   VAL_GPIOI_AFRH}
+#endif
+};
+#endif
+
+/**
+ * @brief   Early initialization code.
+ * @details This initialization must be performed just after stack setup
+ *          and before any other initialization.
+ */
+void __early_init(void) {
+
+  stm32_clock_init();
+}
+
+/**
+ * @brief   Board-specific initialization code.
+ * @todo    Add your board-specific code, if any.
+ */
+void boardInit(void) {
+}
diff --git a/os/modules/PowerManagement_1-1/board.h b/os/modules/PowerManagement_1-1/board.h
new file mode 100644
index 0000000..a5e8407
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/board.h
@@ -0,0 +1,1374 @@
+/*
+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 _BOARD_H_
+#define _BOARD_H_
+
+/*
+ * Setup for AMiRo PowerManagement board.
+ */
+
+/*
+ * Board identifier.
+ */
+#define BOARD_POWERMANAGEMENT
+#define BOARD_NAME                      "AMiRo PowerManagement"
+#define BOARD_VERSION                   "1.1"
+
+/*
+ * Board oscillators-related settings.
+ * NOTE: LSE not fitted.
+ */
+#if !defined(STM32_LSECLK)
+#define STM32_LSECLK                    0U
+#endif
+
+#if !defined(STM32_HSECLK)
+#define STM32_HSECLK                    8000000U
+#endif
+
+/*
+ * Board voltages.
+ * Required for performance limits calculation.
+ */
+#define STM32_VDD                       330U
+
+/*
+ * MCU type as defined in the ST header.
+ */
+#define STM32F405xx
+
+/*
+ * STM32F4 alternate function definitions
+ */
+#define STM32F4xx_AF_system             0U
+#define STM32F4xx_AF_TIM1to2            1U
+#define STM32F4xx_AF_TIM3to5            2U
+#define STM32F4xx_AF_TIM8to11           3U
+#define STM32F4xx_AF_I2C1to3            4U
+#define STM32F4xx_AF_SPI1to2            5U
+#define STM32F4xx_AF_SPI3               6U
+#define STM32F4xx_AF_USART1to3          7U
+#define STM32F4xx_AF_USART4to6          8U
+#define STM32F4xx_AF_CAN1to2_TIM12to14  9U
+#define STM32F4xx_AF_OTG_HSFS           10U
+#define STM32F4xx_AF_ETH                11U
+#define STM32F4xx_AF_FSMC_SDIO_OTGHS    12U
+#define STM32F4xx_AF_DCMI               13U
+#define STM32F4xx_AF_EVENTOUT           15U
+
+/*
+ * IO pins assignments.
+ */
+#define GPIOA_WKUP                      0U
+#define GPIOA_PIN1                      1U
+#define GPIOA_SYS_UART_TX               2U
+#define GPIOA_SYS_UART_RX               3U
+#define GPIOA_SYS_SPI_SS0_N             4U
+#define GPIOA_SYS_SPI_SCLK              5U
+#define GPIOA_SYS_SPI_MISO              6U
+#define GPIOA_SYS_SPI_MOSI              7U
+#define GPIOA_SYS_REG_EN                8U
+#define GPIOA_PROG_RX                   9U
+#define GPIOA_PROG_TX                   10U
+#define GPIOA_CAN_RX                    11U
+#define GPIOA_CAN_TX                    12U
+#define GPIOA_SWDIO                     13U
+#define GPIOA_SWCLK                     14U
+#define GPIOA_SYS_SPI_SS1_N             15U
+
+#define GPIOB_IR_INT1_N                 0U
+#define GPIOB_VSYS_SENSE                1U
+#define GPIOB_POWER_EN                  2U
+#define GPIOB_SYS_UART_DN               3U
+#define GPIOB_CHARGE_STAT2A             4U
+#define GPIOB_BUZZER                    5U
+#define GPIOB_GAUGE_BATLOW2             6U
+#define GPIOB_GAUGE_BATGD2_N            7U
+#define GPIOB_GAUGE_SCL2                8U
+#define GPIOB_GAUGE_SDA2                9U
+#define GPIOB_GAUGE_SCL1                10U
+#define GPIOB_GAUGE_SDA1                11U
+#define GPIOB_LED                       12U
+#define GPIOB_BT_RTS                    13U
+#define GPIOB_BT_CTS                    14U
+#define GPIOB_SYS_UART_UP               15U
+
+#define GPIOC_CHARGE_STAT1A             0U
+#define GPIOC_GAUGE_BATLOW1             1U
+#define GPIOC_GAUGE_BATGD1_N            2U
+#define GPIOC_CHARGE_EN1_N              3U
+#define GPIOC_IR_INT2_N                 4U
+#define GPIOC_TOUCH_INT_N               5U
+#define GPIOC_SYS_DONE                  6U
+#define GPIOC_SYS_PROG_N                7U
+#define GPIOC_PATH_DC                   8U
+#define GPIOC_SYS_SPI_DIR               9U
+#define GPIOC_BT_RX                     10U
+#define GPIOC_BT_TX                     11U
+#define GPIOC_SYS_INT_N                 12U
+#define GPIOC_SYS_PD_N                  13U
+#define GPIOC_SYS_WARMRST_N             14U
+#define GPIOC_BT_RST                    15U
+
+#define GPIOD_PIN0                      0U
+#define GPIOD_PIN1                      1U
+#define GPIOD_CHARGE_EN2_N              2U
+#define GPIOD_PIN3                      3U
+#define GPIOD_PIN4                      4U
+#define GPIOD_PIN5                      5U
+#define GPIOD_PIN6                      6U
+#define GPIOD_PIN7                      7U
+#define GPIOD_PIN8                      8U
+#define GPIOD_PIN9                      9U
+#define GPIOD_PIN10                     10U
+#define GPIOD_PIN11                     11U
+#define GPIOD_PIN12                     12U
+#define GPIOD_PIN13                     13U
+#define GPIOD_PIN14                     14U
+#define GPIOD_PIN15                     15U
+
+#define GPIOE_PIN0                      0U
+#define GPIOE_PIN1                      1U
+#define GPIOE_PIN2                      2U
+#define GPIOE_PIN3                      3U
+#define GPIOE_PIN4                      4U
+#define GPIOE_PIN5                      5U
+#define GPIOE_PIN6                      6U
+#define GPIOE_PIN7                      7U
+#define GPIOE_PIN8                      8U
+#define GPIOE_PIN9                      9U
+#define GPIOE_PIN10                     10U
+#define GPIOE_PIN11                     11U
+#define GPIOE_PIN12                     12U
+#define GPIOE_PIN13                     13U
+#define GPIOE_PIN14                     14U
+#define GPIOE_PIN15                     15U
+
+#define GPIOF_PIN0                      0U
+#define GPIOF_PIN1                      1U
+#define GPIOF_PIN2                      2U
+#define GPIOF_PIN3                      3U
+#define GPIOF_PIN4                      4U
+#define GPIOF_PIN5                      5U
+#define GPIOF_PIN6                      6U
+#define GPIOF_PIN7                      7U
+#define GPIOF_PIN8                      8U
+#define GPIOF_PIN9                      9U
+#define GPIOF_PIN10                     10U
+#define GPIOF_PIN11                     11U
+#define GPIOF_PIN12                     12U
+#define GPIOF_PIN13                     13U
+#define GPIOF_PIN14                     14U
+#define GPIOF_PIN15                     15U
+
+#define GPIOG_PIN0                      0U
+#define GPIOG_PIN1                      1U
+#define GPIOG_PIN2                      2U
+#define GPIOG_PIN3                      3U
+#define GPIOG_PIN4                      4U
+#define GPIOG_PIN5                      5U
+#define GPIOG_PIN6                      6U
+#define GPIOG_PIN7                      7U
+#define GPIOG_PIN8                      8U
+#define GPIOG_PIN9                      9U
+#define GPIOG_PIN10                     10U
+#define GPIOG_PIN11                     11U
+#define GPIOG_PIN12                     12U
+#define GPIOG_PIN13                     13U
+#define GPIOG_PIN14                     14U
+#define GPIOG_PIN15                     15U
+
+#define GPIOH_OSC_IN                    0U
+#define GPIOH_OSC_OUT                   1U
+#define GPIOH_PIN2                      2U
+#define GPIOH_PIN3                      3U
+#define GPIOH_PIN4                      4U
+#define GPIOH_PIN5                      5U
+#define GPIOH_PIN6                      6U
+#define GPIOH_PIN7                      7U
+#define GPIOH_PIN8                      8U
+#define GPIOH_PIN9                      9U
+#define GPIOH_PIN10                     10U
+#define GPIOH_PIN11                     11U
+#define GPIOH_PIN12                     12U
+#define GPIOH_PIN13                     13U
+#define GPIOH_PIN14                     14U
+#define GPIOH_PIN15                     15U
+
+#define GPIOI_PIN0                      0U
+#define GPIOI_PIN1                      1U
+#define GPIOI_PIN2                      2U
+#define GPIOI_PIN3                      3U
+#define GPIOI_PIN4                      4U
+#define GPIOI_PIN5                      5U
+#define GPIOI_PIN6                      6U
+#define GPIOI_PIN7                      7U
+#define GPIOI_PIN8                      8U
+#define GPIOI_PIN9                      9U
+#define GPIOI_PIN10                     10U
+#define GPIOI_PIN11                     11U
+#define GPIOI_PIN12                     12U
+#define GPIOI_PIN13                     13U
+#define GPIOI_PIN14                     14U
+#define GPIOI_PIN15                     15U
+
+/*
+ * IO lines assignments.
+ */
+#define LINE_WKUP                       PAL_LINE(GPIOA, GPIOA_WKUP)
+#define LINE_SYS_UART_TX                PAL_LINE(GPIOA, GPIOA_SYS_UART_TX)
+#define LINE_SYS_UART_RX                PAL_LINE(GPIOA, GPIOA_SYS_UART_RX)
+#define LINE_SYS_SPI_SS0_N              PAL_LINE(GPIOA, GPIOA_SYS_SPI_SS0_N)
+#define LINE_SYS_SPI_SCLK               PAL_LINE(GPIOA, GPIOA_SYS_SPI_SCLK)
+#define LINE_SYS_SPI_MISO               PAL_LINE(GPIOA, GPIOA_SYS_SPI_MISO)
+#define LINE_SYS_SPI_MOSI               PAL_LINE(GPIOA, GPIOA_SYS_SPI_MOSI)
+#define LINE_SYS_REG_EN                 PAL_LINE(GPIOA, GPIOA_SYS_REG_EN)
+#define LINE_PROG_RX                    PAL_LINE(GPIOA, GPIOA_PROG_RX)
+#define LINE_PROG_TX                    PAL_LINE(GPIOA, GPIOA_PROG_TX)
+#define LINE_CAN_RX                     PAL_LINE(GPIOA, GPIOA_CAN_RX)
+#define LINE_CAN_TX                     PAL_LINE(GPIOA, GPIOA_CAN_TX)
+#define LINE_SWDIO                      PAL_LINE(GPIOA, GPIOA_SWDIO)
+#define LINE_SWCLK                      PAL_LINE(GPIOA, GPIOA_SWCLK)
+#define LINE_SYS_SPI_SS1_N              PAL_LINE(GPIOA, GPIOA_SYS_SPI_SS1_N)
+
+#define LINE_IR_INT1_N                  PAL_LINE(GPIOB, GPIOB_IR_INT1_N)
+#define LINE_VSYS_SENSE                 PAL_LINE(GPIOB, GPIOB_VSYS_SENSE)
+#define LINE_POWER_EN                   PAL_LINE(GPIOB, GPIOB_POWER_EN)
+#define LINE_SYS_UART_DN                PAL_LINE(GPIOB, GPIOB_SYS_UART_DN)
+#define LINE_CHARGE_STAT2A              PAL_LINE(GPIOB, GPIOB_CHARGE_STAT2A)
+#define LINE_BUZZER                     PAL_LINE(GPIOB, GPIOB_BUZZER)
+#define LINE_GAUGE_BATLOW2              PAL_LINE(GPIOB, GPIOB_GAUGE_BATLOW2)
+#define LINE_GAUGE_BATGD2_N             PAL_LINE(GPIOB, GPIOB_GAUGE_BATGD2_N)
+#define LINE_GAUGE_SCL2                 PAL_LINE(GPIOB, GPIOB_GAUGE_SCL2)
+#define LINE_GAUGE_SDA2                 PAL_LINE(GPIOB, GPIOB_GAUGE_SDA2)
+#define LINE_GAUGE_SCL1                 PAL_LINE(GPIOB, GPIOB_GAUGE_SCL1)
+#define LINE_GAUGE_SDA1                 PAL_LINE(GPIOB, GPIOB_GAUGE_SDA1)
+#define LINE_LED                        PAL_LINE(GPIOB, GPIOB_LED)
+#define LINE_BT_RTS                     PAL_LINE(GPIOB, GPIOB_BT_RTS)
+#define LINE_BT_CTS                     PAL_LINE(GPIOB, GPIOB_BT_CTS)
+#define LINE_SYS_UART_UP                PAL_LINE(GPIOB, GPIOB_SYS_UART_UP)
+
+#define LINE_CHARGE_STAT1A              PAL_LINE(GPIOC, GPIOC_CHARGE_STAT1A)
+#define LINE_GAUGE_BATLOW1              PAL_LINE(GPIOC, GPIOC_GAUGE_BATLOW1)
+#define LINE_GAUGE_BATGD1_N             PAL_LINE(GPIOC, GPIOC_GAUGE_BATGD1_N)
+#define LINE_CHARGE_EN1_N               PAL_LINE(GPIOC, GPIOC_CHARGE_EN1_N)
+#define LINE_IR_INT2_N                  PAL_LINE(GPIOC, GPIOC_IR_INT2_N)
+#define LINE_TOUCH_INT_N                PAL_LINE(GPIOC, GPIOC_TOUCH_INT_N)
+#define LINE_SYS_DONE                   PAL_LINE(GPIOC, GPIOC_SYS_DONE)
+#define LINE_SYS_PROG_N                 PAL_LINE(GPIOC, GPIOC_SYS_PROG_N)
+#define LINE_PATH_DC                    PAL_LINE(GPIOC, GPIOC_PATH_DC)
+#define LINE_SYS_SPI_DIR                PAL_LINE(GPIOC, GPIOC_SYS_SPI_DIR)
+#define LINE_BT_RX                      PAL_LINE(GPIOC, GPIOC_BT_RX)
+#define LINE_BT_TX                      PAL_LINE(GPIOC, GPIOC_BT_TX)
+#define LINE_SYS_INT_N                  PAL_LINE(GPIOC, GPIOC_SYS_INT_N)
+#define LINE_SYS_PD_N                   PAL_LINE(GPIOC, GPIOC_SYS_PD_N)
+#define LINE_SYS_WARMRST_N              PAL_LINE(GPIOC, GPIOC_SYS_WARMRST_N)
+#define LINE_BT_RST                     PAL_LINE(GPIOC, GPIOC_BT_RST)
+
+#define LINE_CHARGE_EN2_N               PAL_LINE(GPIOD, GPIOD_CHARGE_EN2_N)
+
+#define LINE_OSC_IN                     PAL_LINE(GPIOH, 0U)
+#define LINE_OSC_OUT                    PAL_LINE(GPIOH, 1U)
+
+/*
+ * I/O ports initial setup, this configuration is established soon after reset
+ * in the initialization code.
+ * Please refer to the STM32 Reference Manual for details.
+ */
+#define PIN_MODE_INPUT(n)               (0U << ((n) * 2U))
+#define PIN_MODE_OUTPUT(n)              (1U << ((n) * 2U))
+#define PIN_MODE_ALTERNATE(n)           (2U << ((n) * 2U))
+#define PIN_MODE_ANALOG(n)              (3U << ((n) * 2U))
+#define PIN_ODR_LOW(n)                  (0U << (n))
+#define PIN_ODR_HIGH(n)                 (1U << (n))
+#define PIN_OTYPE_PUSHPULL(n)           (0U << (n))
+#define PIN_OTYPE_OPENDRAIN(n)          (1U << (n))
+#define PIN_OSPEED_LOW(n)               (0U << ((n) * 2U))
+#define PIN_OSPEED_MEDIUM(n)            (1U << ((n) * 2U))
+#define PIN_OSPEED_HIGH(n)              (2U << ((n) * 2U))
+#define PIN_OSPEED_VERYHIGH(n)          (3U << ((n) * 2U))
+#define PIN_PUPDR_FLOATING(n)           (0U << ((n) * 2U))
+#define PIN_PUPDR_PULLUP(n)             (1U << ((n) * 2U))
+#define PIN_PUPDR_PULLDOWN(n)           (2U << ((n) * 2U))
+#define PIN_AFIO_AF(n, v)               ((v) << (((n) % 8U) * 4U))
+
+/*
+ * GPIOA setup:
+ *
+ * PA0  - WKUP                          (input floating)
+ * PA1  - PIN1                          (input pullup)
+ * PA2  - SYS_UART_TX                   (input floating)
+ * PA3  - SYS_UART_RX                   (alternate 7 pushpull floating)
+ * PA4  - SYS_SPI_SS0_N                 (input floating)
+ * PA5  - SYS_SPI_SCLK                  (alternate 5 pushpull floating)
+ * PA6  - SYS_SPI_MISO                  (alternate 5 pushpull floating)
+ * PA7  - SYS_SPI_MOSI                  (alternate 5 pushpull floating)
+ * PA8  - SYS_REG_EN                    (output pushpull high)
+ * PA9  - PROG_RX                       (alternate 7 pushpull floating)
+ * PA10 - PROG_TX                       (alternate 7 pushpull pullup)
+ * PA11 - CAN_RX                        (alternate 9 pushpull floating)
+ * PA12 - CAN_TX                        (input floating)
+ * PA13 - SWDIO                         (alternate 0 pushpull floating)
+ * PA14 - SWCLK                         (alternate 0 pushpull floating)
+ * PA15 - SYS_SPI_SS1_N                 (input floating)
+ */
+#define VAL_GPIOA_MODER                 (PIN_MODE_INPUT(GPIOA_WKUP) |                                 \
+                                         PIN_MODE_INPUT(GPIOA_PIN1) |                                 \
+                                         PIN_MODE_INPUT(GPIOA_SYS_UART_TX) |                          \
+                                         PIN_MODE_ALTERNATE(GPIOA_SYS_UART_RX) |                      \
+                                         PIN_MODE_INPUT(GPIOA_SYS_SPI_SS0_N) |                        \
+                                         PIN_MODE_ALTERNATE(GPIOA_SYS_SPI_SCLK) |                     \
+                                         PIN_MODE_ALTERNATE(GPIOA_SYS_SPI_MISO) |                     \
+                                         PIN_MODE_ALTERNATE(GPIOA_SYS_SPI_MOSI) |                     \
+                                         PIN_MODE_OUTPUT(GPIOA_SYS_REG_EN) |                          \
+                                         PIN_MODE_ALTERNATE(GPIOA_PROG_RX) |                          \
+                                         PIN_MODE_ALTERNATE(GPIOA_PROG_TX) |                          \
+                                         PIN_MODE_ALTERNATE(GPIOA_CAN_RX) |                           \
+                                         PIN_MODE_INPUT(GPIOA_CAN_TX) |                               \
+                                         PIN_MODE_ALTERNATE(GPIOA_SWDIO) |                            \
+                                         PIN_MODE_ALTERNATE(GPIOA_SWCLK) |                            \
+                                         PIN_MODE_INPUT(GPIOA_SYS_SPI_SS1_N))
+#define VAL_GPIOA_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOA_WKUP) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_PIN1) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_UART_TX) |                      \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_UART_RX) |                      \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_SPI_SS0_N) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_SPI_SCLK) |                     \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_SPI_MISO) |                     \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_SPI_MOSI) |                     \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_REG_EN) |                       \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_PROG_RX) |                          \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_PROG_TX) |                          \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_CAN_RX) |                           \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_CAN_TX) |                           \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SWDIO) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SWCLK) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOA_SYS_SPI_SS1_N))
+#define VAL_GPIOA_OSPEEDR               (PIN_OSPEED_VERYHIGH(GPIOA_WKUP) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_PIN1) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_UART_TX) |                     \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_UART_RX) |                     \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_SPI_SS0_N) |                   \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_SPI_SCLK) |                    \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_SPI_MISO) |                    \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_SPI_MOSI) |                    \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_REG_EN) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_PROG_RX) |                         \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_PROG_TX) |                         \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_CAN_RX) |                          \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_CAN_TX) |                          \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SWDIO) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SWCLK) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOA_SYS_SPI_SS1_N))
+#define VAL_GPIOA_PUPDR                 (PIN_PUPDR_FLOATING(GPIOA_WKUP) |                             \
+                                         PIN_PUPDR_PULLUP(GPIOA_PIN1) |                               \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_UART_TX) |                      \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_UART_RX) |                      \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_SPI_SS0_N) |                    \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_SPI_SCLK) |                     \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_SPI_MISO) |                     \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_SPI_MOSI) |                     \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_REG_EN) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOA_PROG_RX) |                          \
+                                         PIN_PUPDR_PULLUP(GPIOA_PROG_TX) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOA_CAN_RX) |                           \
+                                         PIN_PUPDR_FLOATING(GPIOA_CAN_TX) |                           \
+                                         PIN_PUPDR_FLOATING(GPIOA_SWDIO) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOA_SWCLK) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOA_SYS_SPI_SS1_N))
+#define VAL_GPIOA_ODR                   (PIN_ODR_HIGH(GPIOA_WKUP) |                                   \
+                                         PIN_ODR_HIGH(GPIOA_PIN1) |                                   \
+                                         PIN_ODR_HIGH(GPIOA_SYS_UART_TX) |                            \
+                                         PIN_ODR_HIGH(GPIOA_SYS_UART_RX) |                            \
+                                         PIN_ODR_HIGH(GPIOA_SYS_SPI_SS0_N) |                          \
+                                         PIN_ODR_HIGH(GPIOA_SYS_SPI_SCLK) |                           \
+                                         PIN_ODR_HIGH(GPIOA_SYS_SPI_MISO) |                           \
+                                         PIN_ODR_HIGH(GPIOA_SYS_SPI_MOSI) |                           \
+                                         PIN_ODR_HIGH(GPIOA_SYS_REG_EN) |                             \
+                                         PIN_ODR_HIGH(GPIOA_PROG_RX) |                                \
+                                         PIN_ODR_HIGH(GPIOA_PROG_TX) |                                \
+                                         PIN_ODR_HIGH(GPIOA_CAN_RX) |                                 \
+                                         PIN_ODR_HIGH(GPIOA_CAN_TX) |                                 \
+                                         PIN_ODR_HIGH(GPIOA_SWDIO) |                                  \
+                                         PIN_ODR_HIGH(GPIOA_SWCLK) |                                  \
+                                         PIN_ODR_HIGH(GPIOA_SYS_SPI_SS1_N))
+#define VAL_GPIOA_AFRL                  (PIN_AFIO_AF(GPIOA_WKUP, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOA_PIN1, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOA_SYS_UART_TX, STM32F4xx_AF_USART1to3) |     \
+                                         PIN_AFIO_AF(GPIOA_SYS_UART_RX, STM32F4xx_AF_USART1to3) |     \
+                                         PIN_AFIO_AF(GPIOA_SYS_SPI_SS0_N, STM32F4xx_AF_system) |      \
+                                         PIN_AFIO_AF(GPIOA_SYS_SPI_SCLK, STM32F4xx_AF_SPI1to2) |      \
+                                         PIN_AFIO_AF(GPIOA_SYS_SPI_MISO, STM32F4xx_AF_SPI1to2) |      \
+                                         PIN_AFIO_AF(GPIOA_SYS_SPI_MOSI, STM32F4xx_AF_SPI1to2))
+#define VAL_GPIOA_AFRH                  (PIN_AFIO_AF(GPIOA_SYS_REG_EN, STM32F4xx_AF_system) |         \
+                                         PIN_AFIO_AF(GPIOA_PROG_RX, STM32F4xx_AF_USART1to3) |         \
+                                         PIN_AFIO_AF(GPIOA_PROG_TX, STM32F4xx_AF_USART1to3) |         \
+                                         PIN_AFIO_AF(GPIOA_CAN_RX, STM32F4xx_AF_CAN1to2_TIM12to14) |  \
+                                         PIN_AFIO_AF(GPIOA_CAN_TX, STM32F4xx_AF_CAN1to2_TIM12to14) |  \
+                                         PIN_AFIO_AF(GPIOA_SWDIO, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOA_SWCLK, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOA_SYS_SPI_SS1_N, STM32F4xx_AF_system))
+
+/*
+ * GPIOB setup:
+ *
+ * PB0  - IR_INT1_N                     (input floating)
+ * PB1  - VSYS_SENSE                    (analog)
+ * PB2  - POWER_EN                      (output pushpull high)
+ * PB3  - SYS_UART_DN                   (output opendrain high)
+ * PB4  - CHARGE_STAT2A                 (inout floating)
+ * PB5  - BUZZER                        (alternate 2 pushpull floating)
+ * PB6  - GAUGE_BATLOW2                 (input floating)
+ * PB7  - GAUGE_BATGD2_N                (input floating)
+ * PB8  - GAUGE_SCL2                    (alternate 4 opendrain floating)
+ * PB9  - GAUGE_SDA2                    (alternate 4 opendrain floating)
+ * PB10 - GAUGE_SCL1                    (alternate 4 opendrain floating)
+ * PB11 - GAUGE_SDA1                    (alternate 4 opendrain floating)
+ * PB12 - LED                           (output opendrain high)
+ * PB13 - BT_RTS                        (alternate 7 pushpull floating)
+ * PB14 - BT_CTS                        (inout floating)
+ * PB15 - SYS_UART_UP                   (output opendrain high)
+ */
+#define VAL_GPIOB_MODER                 (PIN_MODE_INPUT(GPIOB_IR_INT1_N) |                            \
+                                         PIN_MODE_ANALOG(GPIOB_VSYS_SENSE) |                          \
+                                         PIN_MODE_OUTPUT(GPIOB_POWER_EN) |                            \
+                                         PIN_MODE_OUTPUT(GPIOB_SYS_UART_DN) |                         \
+                                         PIN_MODE_INPUT(GPIOB_CHARGE_STAT2A) |                        \
+                                         PIN_MODE_ALTERNATE(GPIOB_BUZZER) |                           \
+                                         PIN_MODE_INPUT(GPIOB_GAUGE_BATLOW2) |                        \
+                                         PIN_MODE_INPUT(GPIOB_GAUGE_BATGD2_N) |                       \
+                                         PIN_MODE_ALTERNATE(GPIOB_GAUGE_SCL2) |                       \
+                                         PIN_MODE_ALTERNATE(GPIOB_GAUGE_SDA2) |                       \
+                                         PIN_MODE_ALTERNATE(GPIOB_GAUGE_SCL1) |                       \
+                                         PIN_MODE_ALTERNATE(GPIOB_GAUGE_SDA1) |                       \
+                                         PIN_MODE_OUTPUT(GPIOB_LED) |                                 \
+                                         PIN_MODE_ALTERNATE(GPIOB_BT_RTS) |                           \
+                                         PIN_MODE_INPUT(GPIOB_BT_CTS) |                               \
+                                         PIN_MODE_OUTPUT(GPIOB_SYS_UART_UP))
+#define VAL_GPIOB_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOB_IR_INT1_N) |                        \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_VSYS_SENSE) |                       \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_POWER_EN) |                         \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_SYS_UART_DN) |                     \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_CHARGE_STAT2A) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_BUZZER) |                           \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_GAUGE_BATLOW2) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_GAUGE_BATGD2_N) |                   \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SCL2) |                      \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SDA2) |                      \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SCL1) |                      \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_GAUGE_SDA1) |                      \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_LED) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_BT_RTS) |                           \
+                                         PIN_OTYPE_PUSHPULL(GPIOB_BT_CTS) |                           \
+                                         PIN_OTYPE_OPENDRAIN(GPIOB_SYS_UART_UP))
+#define VAL_GPIOB_OSPEEDR               (PIN_OSPEED_VERYHIGH(GPIOB_IR_INT1_N) |                       \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_VSYS_SENSE) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_POWER_EN) |                        \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_SYS_UART_DN) |                     \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_CHARGE_STAT2A) |                   \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_BUZZER) |                          \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_GAUGE_BATLOW2) |                   \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_GAUGE_BATGD2_N) |                  \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_GAUGE_SCL2) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_GAUGE_SDA2) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_GAUGE_SCL1) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_GAUGE_SDA1) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_LED) |                             \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_BT_RTS) |                          \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_BT_CTS) |                          \
+                                         PIN_OSPEED_VERYHIGH(GPIOB_SYS_UART_UP))
+#define VAL_GPIOB_PUPDR                 (PIN_PUPDR_FLOATING(GPIOB_IR_INT1_N) |                        \
+                                         PIN_PUPDR_FLOATING(GPIOB_VSYS_SENSE) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOB_POWER_EN) |                         \
+                                         PIN_PUPDR_FLOATING(GPIOB_SYS_UART_DN) |                      \
+                                         PIN_PUPDR_FLOATING(GPIOB_CHARGE_STAT2A) |                    \
+                                         PIN_PUPDR_FLOATING(GPIOB_BUZZER) |                           \
+                                         PIN_PUPDR_FLOATING(GPIOB_GAUGE_BATLOW2) |                    \
+                                         PIN_PUPDR_FLOATING(GPIOB_GAUGE_BATGD2_N) |                   \
+                                         PIN_PUPDR_FLOATING(GPIOB_GAUGE_SCL2) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOB_GAUGE_SDA2) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOB_GAUGE_SCL1) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOB_GAUGE_SDA1) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOB_LED) |                              \
+                                         PIN_PUPDR_FLOATING(GPIOB_BT_RTS) |                           \
+                                         PIN_PUPDR_FLOATING(GPIOB_BT_CTS) |                           \
+                                         PIN_PUPDR_FLOATING(GPIOB_SYS_UART_UP))
+#define VAL_GPIOB_ODR                   (PIN_ODR_HIGH(GPIOB_IR_INT1_N) |                              \
+                                         PIN_ODR_HIGH(GPIOB_VSYS_SENSE) |                             \
+                                         PIN_ODR_HIGH(GPIOB_POWER_EN) |                               \
+                                         PIN_ODR_HIGH(GPIOB_SYS_UART_DN) |                            \
+                                         PIN_ODR_HIGH(GPIOB_CHARGE_STAT2A) |                          \
+                                         PIN_ODR_HIGH(GPIOB_BUZZER) |                                 \
+                                         PIN_ODR_HIGH(GPIOB_GAUGE_BATLOW2) |                          \
+                                         PIN_ODR_HIGH(GPIOB_GAUGE_BATGD2_N) |                         \
+                                         PIN_ODR_HIGH(GPIOB_GAUGE_SCL2) |                             \
+                                         PIN_ODR_HIGH(GPIOB_GAUGE_SDA2) |                             \
+                                         PIN_ODR_HIGH(GPIOB_GAUGE_SCL1) |                             \
+                                         PIN_ODR_HIGH(GPIOB_GAUGE_SDA1) |                             \
+                                         PIN_ODR_HIGH(GPIOB_LED) |                                    \
+                                         PIN_ODR_HIGH(GPIOB_BT_RTS) |                                 \
+                                         PIN_ODR_HIGH(GPIOB_BT_CTS) |                                 \
+                                         PIN_ODR_HIGH(GPIOB_SYS_UART_UP))
+#define VAL_GPIOB_AFRL                  (PIN_AFIO_AF(GPIOB_IR_INT1_N, STM32F4xx_AF_system) |          \
+                                         PIN_AFIO_AF(GPIOB_VSYS_SENSE, STM32F4xx_AF_system) |         \
+                                         PIN_AFIO_AF(GPIOB_POWER_EN, STM32F4xx_AF_system) |           \
+                                         PIN_AFIO_AF(GPIOB_SYS_UART_DN, STM32F4xx_AF_system) |        \
+                                         PIN_AFIO_AF(GPIOB_CHARGE_STAT2A, STM32F4xx_AF_system) |      \
+                                         PIN_AFIO_AF(GPIOB_BUZZER, STM32F4xx_AF_TIM3to5) |            \
+                                         PIN_AFIO_AF(GPIOB_GAUGE_BATLOW2, STM32F4xx_AF_system) |      \
+                                         PIN_AFIO_AF(GPIOB_GAUGE_BATGD2_N, STM32F4xx_AF_system))
+#define VAL_GPIOB_AFRH                  (PIN_AFIO_AF(GPIOB_GAUGE_SCL2, STM32F4xx_AF_I2C1to3) |        \
+                                         PIN_AFIO_AF(GPIOB_GAUGE_SDA2, STM32F4xx_AF_I2C1to3) |        \
+                                         PIN_AFIO_AF(GPIOB_GAUGE_SCL1, STM32F4xx_AF_I2C1to3) |        \
+                                         PIN_AFIO_AF(GPIOB_GAUGE_SDA1, STM32F4xx_AF_I2C1to3) |        \
+                                         PIN_AFIO_AF(GPIOB_LED, STM32F4xx_AF_system) |                \
+                                         PIN_AFIO_AF(GPIOB_BT_RTS, STM32F4xx_AF_USART1to3) |          \
+                                         PIN_AFIO_AF(GPIOB_BT_CTS, STM32F4xx_AF_USART1to3) |          \
+                                         PIN_AFIO_AF(GPIOB_SYS_UART_UP, STM32F4xx_AF_system))
+
+/*
+ * GPIOC setup:
+ *
+ * PC0  - CHARGE_STAT1A                 (input floating)
+ * PC1  - GAUGE_BATLOW1                 (input floating)
+ * PC2  - GAUGE_BATGD1_N                (input floating)
+ * PC3  - CHARGE_EN1_N                  (output opendrain high)
+ * PC4  - IR_INT2_N                     (input floating)
+ * PC5  - TOUCH_INT_N                   (input floating)
+ * PC6  - SYS_DONE                      (input floating)
+ * PC7  - SYS_PROG_N                    (output opendrain high)
+ * PC8  - PATH_DC                       (input floating)
+ * PC9  - SYS_SPI_DIR                   (output opendrain high)
+ * PC10 - BT_RX                         (alternate 7 pushpull floating)
+ * PC11 - BT_TX                         (alternate 7 pushpull floating)
+ * PC12 - SYS_INT_N                     (output opendrain low)
+ * PC13 - SYS_PD_N                      (output opendrain high)
+ * PC14 - SYS_WARMRST_N                 (output opendrain high)
+ * PC15 - BT_RST                        (output opendrain high)
+ */
+#define VAL_GPIOC_MODER                 (PIN_MODE_INPUT(GPIOC_CHARGE_STAT1A) |                        \
+                                         PIN_MODE_INPUT(GPIOC_GAUGE_BATLOW1) |                        \
+                                         PIN_MODE_INPUT(GPIOC_GAUGE_BATGD1_N) |                       \
+                                         PIN_MODE_OUTPUT(GPIOC_CHARGE_EN1_N) |                        \
+                                         PIN_MODE_INPUT(GPIOC_IR_INT2_N) |                            \
+                                         PIN_MODE_INPUT(GPIOC_TOUCH_INT_N) |                          \
+                                         PIN_MODE_INPUT(GPIOC_SYS_DONE) |                             \
+                                         PIN_MODE_OUTPUT(GPIOC_SYS_PROG_N) |                          \
+                                         PIN_MODE_INPUT(GPIOC_PATH_DC) |                              \
+                                         PIN_MODE_OUTPUT(GPIOC_SYS_SPI_DIR) |                         \
+                                         PIN_MODE_ALTERNATE(GPIOC_BT_RX) |                            \
+                                         PIN_MODE_ALTERNATE(GPIOC_BT_TX) |                            \
+                                         PIN_MODE_OUTPUT(GPIOC_SYS_INT_N) |                           \
+                                         PIN_MODE_OUTPUT(GPIOC_SYS_PD_N) |                            \
+                                         PIN_MODE_OUTPUT(GPIOC_SYS_WARMRST_N) |                       \
+                                         PIN_MODE_OUTPUT(GPIOC_BT_RST))
+#define VAL_GPIOC_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOC_CHARGE_STAT1A) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_GAUGE_BATLOW1) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_GAUGE_BATGD1_N) |                   \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_CHARGE_EN1_N) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_IR_INT2_N) |                        \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_TOUCH_INT_N) |                      \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_SYS_DONE) |                         \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_SYS_PROG_N) |                      \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_PATH_DC) |                          \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_SYS_SPI_DIR) |                     \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_BT_RX) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOC_BT_TX) |                            \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_SYS_INT_N) |                       \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_SYS_PD_N) |                        \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_SYS_WARMRST_N) |                   \
+                                         PIN_OTYPE_OPENDRAIN(GPIOC_BT_RST))
+#define VAL_GPIOC_OSPEEDR               (PIN_OSPEED_VERYHIGH(GPIOC_CHARGE_STAT1A) |                   \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_GAUGE_BATLOW1) |                   \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_GAUGE_BATGD1_N) |                  \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_CHARGE_EN1_N) |                    \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_IR_INT2_N) |                       \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_TOUCH_INT_N) |                     \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_SYS_DONE) |                        \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_SYS_PROG_N) |                      \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_PATH_DC) |                         \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_SYS_SPI_DIR) |                     \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_BT_RX) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_BT_TX) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_SYS_INT_N) |                       \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_SYS_PD_N) |                        \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_SYS_WARMRST_N) |                   \
+                                         PIN_OSPEED_VERYHIGH(GPIOC_BT_RST))
+#define VAL_GPIOC_PUPDR                 (PIN_PUPDR_FLOATING(GPIOC_CHARGE_STAT1A) |                    \
+                                         PIN_PUPDR_FLOATING(GPIOC_GAUGE_BATLOW1) |                    \
+                                         PIN_PUPDR_FLOATING(GPIOC_GAUGE_BATGD1_N) |                   \
+                                         PIN_PUPDR_FLOATING(GPIOC_CHARGE_EN1_N) |                     \
+                                         PIN_PUPDR_FLOATING(GPIOC_IR_INT2_N) |                        \
+                                         PIN_PUPDR_FLOATING(GPIOC_TOUCH_INT_N) |                      \
+                                         PIN_PUPDR_FLOATING(GPIOC_SYS_DONE) |                         \
+                                         PIN_PUPDR_FLOATING(GPIOC_SYS_PROG_N) |                       \
+                                         PIN_PUPDR_FLOATING(GPIOC_PATH_DC) |                          \
+                                         PIN_PUPDR_FLOATING(GPIOC_SYS_SPI_DIR) |                      \
+                                         PIN_PUPDR_FLOATING(GPIOC_BT_RX) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOC_BT_TX) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOC_SYS_INT_N) |                        \
+                                         PIN_PUPDR_FLOATING(GPIOC_SYS_PD_N) |                         \
+                                         PIN_PUPDR_FLOATING(GPIOC_SYS_WARMRST_N) |                    \
+                                         PIN_PUPDR_FLOATING(GPIOC_BT_RST))
+#define VAL_GPIOC_ODR                   (PIN_ODR_HIGH(GPIOC_CHARGE_STAT1A) |                          \
+                                         PIN_ODR_HIGH(GPIOC_GAUGE_BATLOW1) |                          \
+                                         PIN_ODR_HIGH(GPIOC_GAUGE_BATGD1_N) |                         \
+                                         PIN_ODR_HIGH(GPIOC_CHARGE_EN1_N) |                           \
+                                         PIN_ODR_HIGH(GPIOC_IR_INT2_N) |                              \
+                                         PIN_ODR_HIGH(GPIOC_TOUCH_INT_N) |                            \
+                                         PIN_ODR_HIGH(GPIOC_SYS_DONE) |                               \
+                                         PIN_ODR_HIGH(GPIOC_SYS_PROG_N) |                             \
+                                         PIN_ODR_LOW(GPIOC_PATH_DC) |                                 \
+                                         PIN_ODR_HIGH(GPIOC_SYS_SPI_DIR) |                            \
+                                         PIN_ODR_HIGH(GPIOC_BT_RX) |                                  \
+                                         PIN_ODR_HIGH(GPIOC_BT_TX) |                                  \
+                                         PIN_ODR_LOW(GPIOC_SYS_INT_N) |                               \
+                                         PIN_ODR_HIGH(GPIOC_SYS_PD_N) |                               \
+                                         PIN_ODR_HIGH(GPIOC_SYS_WARMRST_N) |                          \
+                                         PIN_ODR_HIGH(GPIOC_BT_RST))
+#define VAL_GPIOC_AFRL                  (PIN_AFIO_AF(GPIOC_CHARGE_STAT1A, STM32F4xx_AF_system) |      \
+                                         PIN_AFIO_AF(GPIOC_GAUGE_BATLOW1, STM32F4xx_AF_system) |      \
+                                         PIN_AFIO_AF(GPIOC_GAUGE_BATGD1_N, STM32F4xx_AF_system) |     \
+                                         PIN_AFIO_AF(GPIOC_CHARGE_EN1_N, STM32F4xx_AF_system) |       \
+                                         PIN_AFIO_AF(GPIOC_IR_INT2_N, STM32F4xx_AF_system) |          \
+                                         PIN_AFIO_AF(GPIOC_TOUCH_INT_N, STM32F4xx_AF_system) |        \
+                                         PIN_AFIO_AF(GPIOC_SYS_DONE, STM32F4xx_AF_system) |           \
+                                         PIN_AFIO_AF(GPIOC_SYS_PROG_N, STM32F4xx_AF_system))
+#define VAL_GPIOC_AFRH                  (PIN_AFIO_AF(GPIOC_PATH_DC, STM32F4xx_AF_system) |            \
+                                         PIN_AFIO_AF(GPIOC_SYS_SPI_DIR, STM32F4xx_AF_system) |        \
+                                         PIN_AFIO_AF(GPIOC_BT_RX, STM32F4xx_AF_USART1to3) |           \
+                                         PIN_AFIO_AF(GPIOC_BT_TX, STM32F4xx_AF_USART1to3) |           \
+                                         PIN_AFIO_AF(GPIOC_SYS_INT_N, STM32F4xx_AF_system) |          \
+                                         PIN_AFIO_AF(GPIOC_SYS_PD_N, STM32F4xx_AF_system) |           \
+                                         PIN_AFIO_AF(GPIOC_SYS_WARMRST_N, STM32F4xx_AF_system) |      \
+                                         PIN_AFIO_AF(GPIOC_BT_RST, STM32F4xx_AF_system))
+
+/*
+ * GPIOD setup:
+ *
+ * PD0  - PIN0                          (input floating)
+ * PD1  - PIN1                          (input floating)
+ * PD2  - CHARGE_EN2_N                  (output opendrain high)
+ * PD3  - PIN3                          (input floating)
+ * PD4  - PIN4                          (input floating)
+ * PD5  - PIN5                          (input floating)
+ * PD6  - PIN6                          (input floating)
+ * PD7  - PIN7                          (input floating)
+ * PD8  - PIN8                          (input floating)
+ * PD9  - PIN9                          (input floating)
+ * PD10 - PIN10                         (input floating)
+ * PD11 - PIN11                         (input floating)
+ * PD12 - PIN12                         (input floating)
+ * PD13 - PIN13                         (input floating)
+ * PD14 - PIN14                         (input floating)
+ * PD15 - PIN15                         (input floating)
+ */
+#define VAL_GPIOD_MODER                 (PIN_MODE_INPUT(GPIOD_PIN0) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN1) |                                 \
+                                         PIN_MODE_OUTPUT(GPIOD_CHARGE_EN2_N) |                        \
+                                         PIN_MODE_INPUT(GPIOD_PIN3) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN4) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN5) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN6) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN7) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN8) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN9) |                                 \
+                                         PIN_MODE_INPUT(GPIOD_PIN10) |                                \
+                                         PIN_MODE_INPUT(GPIOD_PIN11) |                                \
+                                         PIN_MODE_INPUT(GPIOD_PIN12) |                                \
+                                         PIN_MODE_INPUT(GPIOD_PIN13) |                                \
+                                         PIN_MODE_INPUT(GPIOD_PIN14) |                                \
+                                         PIN_MODE_INPUT(GPIOD_PIN15))
+#define VAL_GPIOD_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOD_PIN0) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN1) |                             \
+                                         PIN_OTYPE_OPENDRAIN(GPIOD_CHARGE_EN2_N) |                    \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN3) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN4) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN5) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN6) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN7) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN8) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN9) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN10) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN11) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN12) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN13) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN14) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOD_PIN15))
+#define VAL_GPIOD_OSPEEDR               (PIN_OSPEED_VERYHIGH(GPIOD_PIN0) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN1) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_CHARGE_EN2_N) |                    \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN3) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN4) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN5) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN6) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN7) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN8) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN9) |                            \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN10) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN11) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN12) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN13) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN14) |                           \
+                                         PIN_OSPEED_VERYHIGH(GPIOD_PIN15))
+#define VAL_GPIOD_PUPDR                 (PIN_PUPDR_PULLUP(GPIOD_PIN0) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN1) |                               \
+                                         PIN_PUPDR_FLOATING(GPIOD_CHARGE_EN2_N) |                     \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN3) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN4) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN5) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN6) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN7) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN8) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN9) |                               \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN10) |                              \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN11) |                              \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN12) |                              \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN13) |                              \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN14) |                              \
+                                         PIN_PUPDR_PULLUP(GPIOD_PIN15))
+#define VAL_GPIOD_ODR                   (PIN_ODR_HIGH(GPIOD_PIN0) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN1) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_CHARGE_EN2_N) |                           \
+                                         PIN_ODR_HIGH(GPIOD_PIN3) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN4) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN5) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN6) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN7) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN8) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN9) |                                   \
+                                         PIN_ODR_HIGH(GPIOD_PIN10) |                                  \
+                                         PIN_ODR_HIGH(GPIOD_PIN11) |                                  \
+                                         PIN_ODR_HIGH(GPIOD_PIN12) |                                  \
+                                         PIN_ODR_HIGH(GPIOD_PIN13) |                                  \
+                                         PIN_ODR_HIGH(GPIOD_PIN14) |                                  \
+                                         PIN_ODR_HIGH(GPIOD_PIN15))
+#define VAL_GPIOD_AFRL                  (PIN_AFIO_AF(GPIOD_PIN0, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN1, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_CHARGE_EN2_N, STM32F4xx_AF_system) |       \
+                                         PIN_AFIO_AF(GPIOD_PIN3, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN4, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN5, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN6, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN7, STM32F4xx_AF_system))
+#define VAL_GPIOD_AFRH                  (PIN_AFIO_AF(GPIOD_PIN8, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN9, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOD_PIN10, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOD_PIN11, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOD_PIN12, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOD_PIN13, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOD_PIN14, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOD_PIN15, STM32F4xx_AF_system))
+
+/*
+ * GPIOE setup:
+ *
+ * PE0  - PIN0                          (input floating)
+ * PE1  - PIN1                          (input floating)
+ * PE2  - PIN2                          (input floating)
+ * PE3  - PIN3                          (input floating)
+ * PE4  - PIN4                          (input floating)
+ * PE5  - PIN5                          (input floating)
+ * PE6  - PIN6                          (input floating)
+ * PE7  - PIN7                          (input floating)
+ * PE8  - PIN8                          (input floating)
+ * PE9  - PIN9                          (input floating)
+ * PE10 - PIN10                         (input floating)
+ * PE11 - PIN11                         (input floating)
+ * PE12 - PIN12                         (input floating)
+ * PE13 - PIN13                         (input floating)
+ * PE14 - PIN14                         (input floating)
+ * PE15 - PIN15                         (input floating)
+ */
+#define VAL_GPIOE_MODER                 (PIN_MODE_INPUT(GPIOE_PIN0) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN1) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN2) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN3) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN4) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN5) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN6) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN7) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN8) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN9) |                                 \
+                                         PIN_MODE_INPUT(GPIOE_PIN10) |                                \
+                                         PIN_MODE_INPUT(GPIOE_PIN11) |                                \
+                                         PIN_MODE_INPUT(GPIOE_PIN12) |                                \
+                                         PIN_MODE_INPUT(GPIOE_PIN13) |                                \
+                                         PIN_MODE_INPUT(GPIOE_PIN14) |                                \
+                                         PIN_MODE_INPUT(GPIOE_PIN15))
+#define VAL_GPIOE_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOE_PIN0) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN1) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN2) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN3) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN4) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN5) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN6) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN7) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN8) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN9) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN10) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN11) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN12) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN13) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN14) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOE_PIN15))
+#define VAL_GPIOE_OSPEEDR               (PIN_OSPEED_LOW(GPIOE_PIN0) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN1) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN2) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN3) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN4) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN5) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN6) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN7) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN8) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN9) |                                 \
+                                         PIN_OSPEED_LOW(GPIOE_PIN10) |                                \
+                                         PIN_OSPEED_LOW(GPIOE_PIN11) |                                \
+                                         PIN_OSPEED_LOW(GPIOE_PIN12) |                                \
+                                         PIN_OSPEED_LOW(GPIOE_PIN13) |                                \
+                                         PIN_OSPEED_LOW(GPIOE_PIN14) |                                \
+                                         PIN_OSPEED_LOW(GPIOE_PIN15))
+#define VAL_GPIOE_PUPDR                 (PIN_PUPDR_FLOATING(GPIOE_PIN0) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN1) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN2) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN3) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN4) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN5) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN6) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN7) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN8) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN9) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN10) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN11) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN12) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN13) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN14) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOE_PIN15))
+#define VAL_GPIOE_ODR                   (PIN_ODR_LOW(GPIOE_PIN0) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN1) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN2) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN3) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN4) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN5) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN6) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN7) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN8) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN9) |                                    \
+                                         PIN_ODR_LOW(GPIOE_PIN10) |                                   \
+                                         PIN_ODR_LOW(GPIOE_PIN11) |                                   \
+                                         PIN_ODR_LOW(GPIOE_PIN12) |                                   \
+                                         PIN_ODR_LOW(GPIOE_PIN13) |                                   \
+                                         PIN_ODR_LOW(GPIOE_PIN14) |                                   \
+                                         PIN_ODR_LOW(GPIOE_PIN15))
+#define VAL_GPIOE_AFRL                  (PIN_AFIO_AF(GPIOE_PIN0, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN1, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN2, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN3, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN4, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN5, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN6, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN7, STM32F4xx_AF_system))
+#define VAL_GPIOE_AFRH                  (PIN_AFIO_AF(GPIOE_PIN8, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN9, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOE_PIN10, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOE_PIN11, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOE_PIN12, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOE_PIN13, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOE_PIN14, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOE_PIN15, STM32F4xx_AF_system))
+
+/*
+ * GPIOF setup:
+ *
+ * PF0  - PIN0                          (input floating)
+ * PF1  - PIN1                          (input floating)
+ * PF2  - PIN2                          (input floating)
+ * PF3  - PIN3                          (input floating)
+ * PF4  - PIN4                          (input floating)
+ * PF5  - PIN5                          (input floating)
+ * PF6  - PIN6                          (input floating)
+ * PF7  - PIN7                          (input floating)
+ * PF8  - PIN8                          (input floating)
+ * PF9  - PIN9                          (input floating)
+ * PF10 - PIN10                         (input floating)
+ * PF11 - PIN11                         (input floating)
+ * PF12 - PIN12                         (input floating)
+ * PF13 - PIN13                         (input floating)
+ * PF14 - PIN14                         (input floating)
+ * PF15 - PIN15                         (input floating)
+ */
+#define VAL_GPIOF_MODER                 (PIN_MODE_INPUT(GPIOF_PIN0) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN1) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN2) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN3) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN4) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN5) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN6) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN7) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN8) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN9) |                                 \
+                                         PIN_MODE_INPUT(GPIOF_PIN10) |                                \
+                                         PIN_MODE_INPUT(GPIOF_PIN11) |                                \
+                                         PIN_MODE_INPUT(GPIOF_PIN12) |                                \
+                                         PIN_MODE_INPUT(GPIOF_PIN13) |                                \
+                                         PIN_MODE_INPUT(GPIOF_PIN14) |                                \
+                                         PIN_MODE_INPUT(GPIOF_PIN15))
+#define VAL_GPIOF_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOF_PIN0) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN1) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN2) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN3) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN4) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN5) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN6) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN7) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN8) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN9) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN10) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN11) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN12) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN13) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN14) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOF_PIN15))
+#define VAL_GPIOF_OSPEEDR               (PIN_OSPEED_LOW(GPIOF_PIN0) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN1) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN2) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN3) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN4) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN5) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN6) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN7) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN8) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN9) |                                 \
+                                         PIN_OSPEED_LOW(GPIOF_PIN10) |                                \
+                                         PIN_OSPEED_LOW(GPIOF_PIN11) |                                \
+                                         PIN_OSPEED_LOW(GPIOF_PIN12) |                                \
+                                         PIN_OSPEED_LOW(GPIOF_PIN13) |                                \
+                                         PIN_OSPEED_LOW(GPIOF_PIN14) |                                \
+                                         PIN_OSPEED_LOW(GPIOF_PIN15))
+#define VAL_GPIOF_PUPDR                 (PIN_PUPDR_FLOATING(GPIOF_PIN0) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN1) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN2) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN3) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN4) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN5) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN6) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN7) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN8) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN9) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN10) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN11) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN12) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN13) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN14) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOF_PIN15))
+#define VAL_GPIOF_ODR                   (PIN_ODR_LOW(GPIOF_PIN0) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN1) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN2) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN3) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN4) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN5) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN6) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN7) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN8) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN9) |                                    \
+                                         PIN_ODR_LOW(GPIOF_PIN10) |                                   \
+                                         PIN_ODR_LOW(GPIOF_PIN11) |                                   \
+                                         PIN_ODR_LOW(GPIOF_PIN12) |                                   \
+                                         PIN_ODR_LOW(GPIOF_PIN13) |                                   \
+                                         PIN_ODR_LOW(GPIOF_PIN14) |                                   \
+                                         PIN_ODR_LOW(GPIOF_PIN15))
+#define VAL_GPIOF_AFRL                  (PIN_AFIO_AF(GPIOF_PIN0, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN1, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN2, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN3, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN4, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN5, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN6, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN7, STM32F4xx_AF_system))
+#define VAL_GPIOF_AFRH                  (PIN_AFIO_AF(GPIOF_PIN8, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN9, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOF_PIN10, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOF_PIN11, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOF_PIN12, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOF_PIN13, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOF_PIN14, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOF_PIN15, STM32F4xx_AF_system))
+
+/*
+ * GPIOG setup:
+ *
+ * PG0  - PIN0                          (input floating)
+ * PG1  - PIN1                          (input floating)
+ * PG2  - PIN2                          (input floating)
+ * PG3  - PIN3                          (input floating)
+ * PG4  - PIN4                          (input floating)
+ * PG5  - PIN5                          (input floating)
+ * PG6  - PIN6                          (input floating)
+ * PG7  - PIN7                          (input floating)
+ * PG8  - PIN8                          (input floating)
+ * PG9  - PIN9                          (input floating)
+ * PG10 - PIN10                         (input floating)
+ * PG11 - PIN11                         (input floating)
+ * PG12 - PIN12                         (input floating)
+ * PG13 - PIN13                         (input floating)
+ * PG14 - PIN14                         (input floating)
+ * PG15 - PIN15                         (input floating)
+ */
+#define VAL_GPIOG_MODER                 (PIN_MODE_INPUT(GPIOG_PIN0) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN1) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN2) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN3) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN4) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN5) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN6) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN7) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN8) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN9) |                                 \
+                                         PIN_MODE_INPUT(GPIOG_PIN10) |                                \
+                                         PIN_MODE_INPUT(GPIOG_PIN11) |                                \
+                                         PIN_MODE_INPUT(GPIOG_PIN12) |                                \
+                                         PIN_MODE_INPUT(GPIOG_PIN13) |                                \
+                                         PIN_MODE_INPUT(GPIOG_PIN14) |                                \
+                                         PIN_MODE_INPUT(GPIOG_PIN15))
+#define VAL_GPIOG_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOG_PIN0) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN1) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN2) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN3) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN4) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN5) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN6) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN7) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN8) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN9) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN10) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN11) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN12) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN13) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN14) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOG_PIN15))
+#define VAL_GPIOG_OSPEEDR               (PIN_OSPEED_LOW(GPIOG_PIN0) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN1) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN2) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN3) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN4) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN5) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN6) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN7) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN8) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN9) |                                 \
+                                         PIN_OSPEED_LOW(GPIOG_PIN10) |                                \
+                                         PIN_OSPEED_LOW(GPIOG_PIN11) |                                \
+                                         PIN_OSPEED_LOW(GPIOG_PIN12) |                                \
+                                         PIN_OSPEED_LOW(GPIOG_PIN13) |                                \
+                                         PIN_OSPEED_LOW(GPIOG_PIN14) |                                \
+                                         PIN_OSPEED_LOW(GPIOG_PIN15))
+#define VAL_GPIOG_PUPDR                 (PIN_PUPDR_FLOATING(GPIOG_PIN0) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN1) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN2) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN3) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN4) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN5) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN6) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN7) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN8) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN9) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN10) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN11) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN12) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN13) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN14) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOG_PIN15))
+#define VAL_GPIOG_ODR                   (PIN_ODR_LOW(GPIOG_PIN0) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN1) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN2) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN3) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN4) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN5) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN6) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN7) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN8) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN9) |                                    \
+                                         PIN_ODR_LOW(GPIOG_PIN10) |                                   \
+                                         PIN_ODR_LOW(GPIOG_PIN11) |                                   \
+                                         PIN_ODR_LOW(GPIOG_PIN12) |                                   \
+                                         PIN_ODR_LOW(GPIOG_PIN13) |                                   \
+                                         PIN_ODR_LOW(GPIOG_PIN14) |                                   \
+                                         PIN_ODR_LOW(GPIOG_PIN15))
+#define VAL_GPIOG_AFRL                  (PIN_AFIO_AF(GPIOG_PIN0, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN1, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN2, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN3, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN4, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN5, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN6, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN7, STM32F4xx_AF_system))
+#define VAL_GPIOG_AFRH                  (PIN_AFIO_AF(GPIOG_PIN8, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN9, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOG_PIN10, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOG_PIN11, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOG_PIN12, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOG_PIN13, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOG_PIN14, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOG_PIN15, STM32F4xx_AF_system))
+
+/*
+ * GPIOH setup:
+ *
+ * PH0  - OSC_IN                        (input floating)
+ * PH1  - OSC_OUT                       (input floating)
+ * PH2  - PIN2                          (input floating)
+ * PH3  - PIN3                          (input floating)
+ * PH4  - PIN4                          (input floating)
+ * PH5  - PIN5                          (input floating)
+ * PH6  - PIN6                          (input floating)
+ * PH7  - PIN7                          (input floating)
+ * PH8  - PIN8                          (input floating)
+ * PH9  - PIN9                          (input floating)
+ * PH10 - PIN10                         (input floating)
+ * PH11 - PIN11                         (input floating)
+ * PH12 - PIN12                         (input floating)
+ * PH13 - PIN13                         (input floating)
+ * PH14 - PIN14                         (input floating)
+ * PH15 - PIN15                         (input floating)
+ */
+#define VAL_GPIOH_MODER                 (PIN_MODE_INPUT(GPIOH_OSC_IN) |                               \
+                                         PIN_MODE_INPUT(GPIOH_OSC_OUT) |                              \
+                                         PIN_MODE_INPUT(GPIOH_PIN2) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN3) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN4) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN5) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN6) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN7) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN8) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN9) |                                 \
+                                         PIN_MODE_INPUT(GPIOH_PIN10) |                                \
+                                         PIN_MODE_INPUT(GPIOH_PIN11) |                                \
+                                         PIN_MODE_INPUT(GPIOH_PIN12) |                                \
+                                         PIN_MODE_INPUT(GPIOH_PIN13) |                                \
+                                         PIN_MODE_INPUT(GPIOH_PIN14) |                                \
+                                         PIN_MODE_INPUT(GPIOH_PIN15))
+#define VAL_GPIOH_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOH_OSC_IN) |                           \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_OSC_OUT) |                          \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN2) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN3) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN4) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN5) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN6) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN7) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN8) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN9) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN10) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN11) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN12) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN13) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN14) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOH_PIN15))
+#define VAL_GPIOH_OSPEEDR               (PIN_OSPEED_VERYHIGH(GPIOH_OSC_IN) |                          \
+                                         PIN_OSPEED_VERYHIGH(GPIOH_OSC_OUT) |                         \
+                                         PIN_OSPEED_LOW(GPIOH_PIN2) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN3) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN4) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN5) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN6) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN7) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN8) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN9) |                                 \
+                                         PIN_OSPEED_LOW(GPIOH_PIN10) |                                \
+                                         PIN_OSPEED_LOW(GPIOH_PIN11) |                                \
+                                         PIN_OSPEED_LOW(GPIOH_PIN12) |                                \
+                                         PIN_OSPEED_LOW(GPIOH_PIN13) |                                \
+                                         PIN_OSPEED_LOW(GPIOH_PIN14) |                                \
+                                         PIN_OSPEED_LOW(GPIOH_PIN15))
+#define VAL_GPIOH_PUPDR                 (PIN_PUPDR_FLOATING(GPIOH_OSC_IN) |                           \
+                                         PIN_PUPDR_FLOATING(GPIOH_OSC_OUT) |                          \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN2) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN3) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN4) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN5) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN6) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN7) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN8) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN9) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN10) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN11) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN12) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN13) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN14) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOH_PIN15))
+#define VAL_GPIOH_ODR                   (PIN_ODR_HIGH(GPIOH_OSC_IN) |                                 \
+                                         PIN_ODR_HIGH(GPIOH_OSC_OUT) |                                \
+                                         PIN_ODR_HIGH(GPIOH_PIN2) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN3) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN4) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN5) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN6) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN7) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN8) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN9) |                                   \
+                                         PIN_ODR_HIGH(GPIOH_PIN10) |                                  \
+                                         PIN_ODR_HIGH(GPIOH_PIN11) |                                  \
+                                         PIN_ODR_HIGH(GPIOH_PIN12) |                                  \
+                                         PIN_ODR_HIGH(GPIOH_PIN13) |                                  \
+                                         PIN_ODR_HIGH(GPIOH_PIN14) |                                  \
+                                         PIN_ODR_HIGH(GPIOH_PIN15))
+#define VAL_GPIOH_AFRL                  (PIN_AFIO_AF(GPIOH_OSC_IN, STM32F4xx_AF_system) |             \
+                                         PIN_AFIO_AF(GPIOH_OSC_OUT, STM32F4xx_AF_system) |            \
+                                         PIN_AFIO_AF(GPIOH_PIN2, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN3, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN4, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN5, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN6, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN7, STM32F4xx_AF_system))
+#define VAL_GPIOH_AFRH                  (PIN_AFIO_AF(GPIOH_PIN8, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN9, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOH_PIN10, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOH_PIN11, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOH_PIN12, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOH_PIN13, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOH_PIN14, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOH_PIN15, STM32F4xx_AF_system))
+
+/*
+ * GPIOI setup:
+ *
+ * PI0  - PIN0                          (input floating)
+ * PI1  - PIN1                          (input floating)
+ * PI2  - PIN2                          (input floating)
+ * PI3  - PIN3                          (input floating)
+ * PI4  - PIN4                          (input floating)
+ * PI5  - PIN5                          (input floating)
+ * PI6  - PIN6                          (input floating)
+ * PI7  - PIN7                          (input floating)
+ * PI8  - PIN8                          (input floating)
+ * PI9  - PIN9                          (input floating)
+ * PI10 - PIN10                         (input floating)
+ * PI11 - PIN11                         (input floating)
+ * PI12 - PIN12                         (input floating)
+ * PI13 - PIN13                         (input floating)
+ * PI14 - PIN14                         (input floating)
+ * PI15 - PIN15                         (input floating)
+ */
+#define VAL_GPIOI_MODER                 (PIN_MODE_INPUT(GPIOI_PIN0) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN1) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN2) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN3) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN4) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN5) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN6) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN7) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN8) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN9) |                                 \
+                                         PIN_MODE_INPUT(GPIOI_PIN10) |                                \
+                                         PIN_MODE_INPUT(GPIOI_PIN11) |                                \
+                                         PIN_MODE_INPUT(GPIOI_PIN12) |                                \
+                                         PIN_MODE_INPUT(GPIOI_PIN13) |                                \
+                                         PIN_MODE_INPUT(GPIOI_PIN14) |                                \
+                                         PIN_MODE_INPUT(GPIOI_PIN15))
+#define VAL_GPIOI_OTYPER                (PIN_OTYPE_PUSHPULL(GPIOI_PIN0) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN1) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN2) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN3) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN4) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN5) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN6) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN7) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN8) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN9) |                             \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN10) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN11) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN12) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN13) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN14) |                            \
+                                         PIN_OTYPE_PUSHPULL(GPIOI_PIN15))
+#define VAL_GPIOI_OSPEEDR               (PIN_OSPEED_LOW(GPIOI_PIN0) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN1) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN2) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN3) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN4) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN5) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN6) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN7) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN8) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN9) |                                 \
+                                         PIN_OSPEED_LOW(GPIOI_PIN10) |                                \
+                                         PIN_OSPEED_LOW(GPIOI_PIN11) |                                \
+                                         PIN_OSPEED_LOW(GPIOI_PIN12) |                                \
+                                         PIN_OSPEED_LOW(GPIOI_PIN13) |                                \
+                                         PIN_OSPEED_LOW(GPIOI_PIN14) |                                \
+                                         PIN_OSPEED_LOW(GPIOI_PIN15))
+#define VAL_GPIOI_PUPDR                 (PIN_PUPDR_FLOATING(GPIOI_PIN0) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN1) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN2) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN3) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN4) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN5) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN6) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN7) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN8) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN9) |                             \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN10) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN11) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN12) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN13) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN14) |                            \
+                                         PIN_PUPDR_FLOATING(GPIOI_PIN15))
+#define VAL_GPIOI_ODR                   (PIN_ODR_LOW(GPIOI_PIN0) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN1) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN2) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN3) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN4) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN5) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN6) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN7) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN8) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN9) |                                    \
+                                         PIN_ODR_LOW(GPIOI_PIN10) |                                   \
+                                         PIN_ODR_LOW(GPIOI_PIN11) |                                   \
+                                         PIN_ODR_LOW(GPIOI_PIN12) |                                   \
+                                         PIN_ODR_LOW(GPIOI_PIN13) |                                   \
+                                         PIN_ODR_LOW(GPIOI_PIN14) |                                   \
+                                         PIN_ODR_LOW(GPIOI_PIN15))
+#define VAL_GPIOI_AFRL                  (PIN_AFIO_AF(GPIOI_PIN0, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN1, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN2, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN3, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN4, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN5, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN6, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN7, STM32F4xx_AF_system))
+#define VAL_GPIOI_AFRH                  (PIN_AFIO_AF(GPIOI_PIN8, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN9, STM32F4xx_AF_system) |               \
+                                         PIN_AFIO_AF(GPIOI_PIN10, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOI_PIN11, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOI_PIN12, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOI_PIN13, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOI_PIN14, STM32F4xx_AF_system) |              \
+                                         PIN_AFIO_AF(GPIOI_PIN15, STM32F4xx_AF_system))
+
+#if !defined(_FROM_ASM_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+  void boardInit(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* _FROM_ASM_ */
+
+#endif /* _BOARD_H_ */
diff --git a/os/modules/PowerManagement_1-1/board.mk b/os/modules/PowerManagement_1-1/board.mk
new file mode 100644
index 0000000..075d14d
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/board.mk
@@ -0,0 +1,36 @@
+################################################################################
+# 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
+BOARD_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# include paths
+BOARDINC = $(BOARD_DIR)
+
+# C source files
+BOARDSRC = $(BOARD_DIR)board.c
+
+# linker path
+BOARDLD = $(AMIROOS)/hal/ports
diff --git a/os/modules/PowerManagement_1-1/chconf.h b/os/modules/PowerManagement_1-1/chconf.h
new file mode 100644
index 0000000..c610e98
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/chconf.h
@@ -0,0 +1,585 @@
+/*
+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    os/modules/PowerManagement/chconf.h
+ * @brief   ChibiOS Configuration file for the PowerManagement module.
+ * @details Contains the application specific kernel settings.
+ *
+ * @addtogroup config
+ * @details Kernel related settings and hooks.
+ * @{
+ */
+
+#ifndef _CHCONF_H_
+#define _CHCONF_H_
+
+#define _CHIBIOS_RT_CONF_
+
+#include <aosconf.h>
+
+/*===========================================================================*/
+/**
+ * @name System timers settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   System time counter resolution.
+ * @note    Allowed values are 16 or 32 bits.
+ */
+#define CH_CFG_ST_RESOLUTION                32
+
+/**
+ * @brief   System tick frequency.
+ * @details Frequency of the system timer that drives the system ticks. This
+ *          setting also defines the system tick time unit.
+ */
+#define CH_CFG_ST_FREQUENCY                 1000000UL
+
+/**
+ * @brief   Time delta constant for the tick-less mode.
+ * @note    If this value is zero then the system uses the classic
+ *          periodic tick. This value represents the minimum number
+ *          of ticks that is safe to specify in a timeout directive.
+ *          The value one is not valid, timeouts are rounded up to
+ *          this value.
+ */
+#define CH_CFG_ST_TIMEDELTA                 10
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel parameters and options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Round robin interval.
+ * @details This constant is the number of system ticks allowed for the
+ *          threads before preemption occurs. Setting this value to zero
+ *          disables the preemption for threads with equal priority and the
+ *          round robin becomes cooperative. Note that higher priority
+ *          threads can still preempt, the kernel is always preemptive.
+ * @note    Disabling the round robin preemption makes the kernel more compact
+ *          and generally faster.
+ * @note    The round robin preemption is not supported in tickless mode and
+ *          must be set to zero in that case.
+ */
+#define CH_CFG_TIME_QUANTUM                 0
+
+/**
+ * @brief   Managed RAM size.
+ * @details Size of the RAM area to be managed by the OS. If set to zero
+ *          then the whole available RAM is used. The core memory is made
+ *          available to the heap allocator and/or can be used directly through
+ *          the simplified core memory allocator.
+ *
+ * @note    In order to let the OS manage the whole RAM the linker script must
+ *          provide the @p __heap_base__ and @p __heap_end__ symbols.
+ * @note    Requires @p CH_CFG_USE_MEMCORE.
+ */
+#define CH_CFG_MEMCORE_SIZE                 0
+
+/**
+ * @brief   Idle thread automatic spawn suppression.
+ * @details When this option is activated the function @p chSysInit()
+ *          does not spawn the idle thread. The application @p main()
+ *          function becomes the idle thread and must implement an
+ *          infinite loop.
+ */
+#define CH_CFG_NO_IDLE_THREAD               FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Performance options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   OS optimization.
+ * @details If enabled then time efficient rather than space efficient code
+ *          is used when two possible implementations exist.
+ *
+ * @note    This is not related to the compiler optimization options.
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_OPTIMIZE_SPEED               TRUE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Subsystem options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Time Measurement APIs.
+ * @details If enabled then the time measurement APIs are included in
+ *          the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_TM                       FALSE
+
+/**
+ * @brief   Threads registry APIs.
+ * @details If enabled then the registry APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_REGISTRY                 FALSE
+
+/**
+ * @brief   Threads synchronization APIs.
+ * @details If enabled then the @p chThdWait() function is included in
+ *          the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_WAITEXIT                 TRUE
+
+/**
+ * @brief   Semaphores APIs.
+ * @details If enabled then the Semaphores APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_SEMAPHORES               FALSE
+
+/**
+ * @brief   Semaphores queuing mode.
+ * @details If enabled then the threads are enqueued on semaphores by
+ *          priority rather than in FIFO order.
+ *
+ * @note    The default is @p FALSE. Enable this if you have special
+ *          requirements.
+ * @note    Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_SEMAPHORES_PRIORITY      FALSE
+
+/**
+ * @brief   Mutexes APIs.
+ * @details If enabled then the mutexes APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MUTEXES                  TRUE
+
+/**
+ * @brief   Enables recursive behavior on mutexes.
+ * @note    Recursive mutexes are heavier and have an increased
+ *          memory footprint.
+ *
+ * @note    The default is @p FALSE.
+ * @note    Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_MUTEXES_RECURSIVE        FALSE
+
+/**
+ * @brief   Conditional Variables APIs.
+ * @details If enabled then the conditional variables APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_MUTEXES.
+ */
+#define CH_CFG_USE_CONDVARS                 FALSE
+
+/**
+ * @brief   Conditional Variables APIs with timeout.
+ * @details If enabled then the conditional variables APIs with timeout
+ *          specification are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_CONDVARS.
+ */
+#define CH_CFG_USE_CONDVARS_TIMEOUT         FALSE
+
+/**
+ * @brief   Events Flags APIs.
+ * @details If enabled then the event flags APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_EVENTS                   TRUE
+
+/**
+ * @brief   Events Flags APIs with timeout.
+ * @details If enabled then the events APIs with timeout specification
+ *          are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_EVENTS.
+ */
+#define CH_CFG_USE_EVENTS_TIMEOUT           TRUE
+
+/**
+ * @brief   Synchronous Messages APIs.
+ * @details If enabled then the synchronous messages APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MESSAGES                 FALSE
+
+/**
+ * @brief   Synchronous Messages queuing mode.
+ * @details If enabled then messages are served by priority rather than in
+ *          FIFO order.
+ *
+ * @note    The default is @p FALSE. Enable this if you have special
+ *          requirements.
+ * @note    Requires @p CH_CFG_USE_MESSAGES.
+ */
+#define CH_CFG_USE_MESSAGES_PRIORITY        FALSE
+
+/**
+ * @brief   Mailboxes APIs.
+ * @details If enabled then the asynchronous messages (mailboxes) APIs are
+ *          included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_SEMAPHORES.
+ */
+#define CH_CFG_USE_MAILBOXES                FALSE
+
+/**
+ * @brief   I/O Queues APIs.
+ * @details If enabled then the I/O queues APIs are included in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_QUEUES                   FALSE
+
+/**
+ * @brief   Core Memory Manager APIs.
+ * @details If enabled then the core memory manager APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMCORE                  FALSE
+
+/**
+ * @brief   Heap Allocator APIs.
+ * @details If enabled then the memory heap allocator APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or
+ *          @p CH_CFG_USE_SEMAPHORES.
+ * @note    Mutexes are recommended.
+ */
+#define CH_CFG_USE_HEAP                     FALSE
+
+/**
+ * @brief   Memory Pools Allocator APIs.
+ * @details If enabled then the memory pools allocator APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ */
+#define CH_CFG_USE_MEMPOOLS                 FALSE
+
+/**
+ * @brief   Dynamic Threads APIs.
+ * @details If enabled then the dynamic threads creation APIs are included
+ *          in the kernel.
+ *
+ * @note    The default is @p TRUE.
+ * @note    Requires @p CH_CFG_USE_WAITEXIT.
+ * @note    Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS.
+ */
+#define CH_CFG_USE_DYNAMIC                  FALSE
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Debug options
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Debug option, kernel statistics.
+ *
+ * @note    The default is @p FALSE.
+ */
+#define CH_DBG_STATISTICS                   FALSE
+
+/**
+ * @brief   Debug option, system state check.
+ * @details If enabled the correct call protocol for system APIs is checked
+ *          at runtime.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_SYSTEM_STATE_CHECK           TRUE
+#else
+#define CH_DBG_SYSTEM_STATE_CHECK           FALSE
+#endif
+
+/**
+ * @brief   Debug option, parameters checks.
+ * @details If enabled then the checks on the API functions input
+ *          parameters are activated.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_CHECKS                TRUE
+#else
+#define CH_DBG_ENABLE_CHECKS                FALSE
+#endif
+
+/**
+ * @brief   Debug option, consistency checks.
+ * @details If enabled then all the assertions in the kernel code are
+ *          activated. This includes consistency checks inside the kernel,
+ *          runtime anomalies and port-defined checks.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_ASSERTS               TRUE
+#else
+#define CH_DBG_ENABLE_ASSERTS               FALSE
+#endif
+
+/**
+ * @brief   Debug option, trace buffer.
+ * @details If enabled then the trace buffer is activated.
+ *
+ * @note    The default is @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#define CH_DBG_TRACE_MASK                   CH_DBG_TRACE_MASK_DISABLED
+
+/**
+ * @brief   Trace buffer entries.
+ * @note    The trace buffer is only allocated if @p CH_DBG_TRACE_MASK is
+ *          different from @p CH_DBG_TRACE_MASK_DISABLED.
+ */
+#define CH_DBG_TRACE_BUFFER_SIZE            128
+
+/**
+ * @brief   Debug option, stack checks.
+ * @details If enabled then a runtime stack check is performed.
+ *
+ * @note    The default is @p FALSE.
+ * @note    The stack check is performed in a architecture/port dependent way.
+ *          It may not be implemented or some ports.
+ * @note    The default failure mode is to halt the system with the global
+ *          @p panic_msg variable set to @p NULL.
+ */
+#if (AMIROOS_CFG_DBG == true) || defined(__DOXYGEN__)
+#define CH_DBG_ENABLE_STACK_CHECK           TRUE
+#else
+#define CH_DBG_ENABLE_STACK_CHECK           FALSE
+#endif
+
+/**
+ * @brief   Debug option, stacks initialization.
+ * @details If enabled then the threads working area is filled with a byte
+ *          value when a thread is created. This can be useful for the
+ *          runtime measurement of the used stack.
+ *
+ * @note    The default is @p FALSE.
+ */
+#if (AMIROOS_CFG_PROFILE == true) || defined(__DOXYGEN__)
+#define CH_DBG_FILL_THREADS                 TRUE
+#else
+#define CH_DBG_FILL_THREADS                 FALSE
+#endif
+
+/**
+ * @brief   Debug option, threads profiling.
+ * @details If enabled then a field is added to the @p thread_t structure that
+ *          counts the system ticks occurred while executing the thread.
+ *
+ * @note    The default is @p FALSE.
+ * @note    This debug option is not currently compatible with the
+ *          tickless mode.
+ */
+#if ((CH_CFG_ST_TIMEDELTA == 0) && (AMIROOS_CFG_PROFILE == true)) || defined(__DOXYGEN__)
+  #define CH_DBG_THREADS_PROFILING          TRUE
+#else
+  #define CH_DBG_THREADS_PROFILING          FALSE
+#endif
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Kernel hooks
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Threads descriptor structure extension.
+ * @details User fields added to the end of the @p thread_t structure.
+ */
+#define CH_CFG_THREAD_EXTRA_FIELDS                                          \
+  /* Add threads custom fields here.*/
+
+/**
+ * @brief   Threads initialization hook.
+ * @details User initialization code added to the @p chThdInit() API.
+ *
+ * @note    It is invoked from within @p chThdInit() and implicitly from all
+ *          the threads creation APIs.
+ */
+#define CH_CFG_THREAD_INIT_HOOK(tp) {                                       \
+  /* Add threads initialization code here.*/                                \
+}
+
+/**
+ * @brief   Threads finalization hook.
+ * @details User finalization code added to the @p chThdExit() API.
+ *
+ * @note    It is inserted into lock zone.
+ * @note    It is also invoked when the threads simply return in order to
+ *          terminate.
+ */
+#define CH_CFG_THREAD_EXIT_HOOK(tp) {                                       \
+  /* Add threads finalization code here.*/                                  \
+}
+
+/**
+ * @brief   Context switch hook.
+ * @details This hook is invoked just before switching between threads.
+ */
+#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) {                              \
+  /* Context switch code here.*/                                            \
+}
+
+/**
+ * @brief   ISR enter hook.
+ */
+#define CH_CFG_IRQ_PROLOGUE_HOOK() {                                        \
+  /* IRQ prologue code here.*/                                              \
+}
+
+/**
+ * @brief   ISR exit hook.
+ */
+#define CH_CFG_IRQ_EPILOGUE_HOOK() {                                        \
+  /* IRQ epilogue code here.*/                                              \
+}
+
+/**
+ * @brief   Idle thread enter hook.
+ * @note    This hook is invoked within a critical zone, no OS functions
+ *          should be invoked from here.
+ * @note    This macro can be used to activate a power saving mode.
+ */
+#define CH_CFG_IDLE_ENTER_HOOK() {                                          \
+  /* Idle-enter code here.*/                                                \
+}
+
+/**
+ * @brief   Idle thread leave hook.
+ * @note    This hook is invoked within a critical zone, no OS functions
+ *          should be invoked from here.
+ * @note    This macro can be used to deactivate a power saving mode.
+ */
+#define CH_CFG_IDLE_LEAVE_HOOK() {                                          \
+  /* Idle-leave code here.*/                                                \
+}
+
+/**
+ * @brief   Idle Loop hook.
+ * @details This hook is continuously invoked by the idle thread loop.
+ */
+#define CH_CFG_IDLE_LOOP_HOOK() {                                           \
+  /* Idle loop code here.*/                                                 \
+}
+
+/**
+ * @brief   System tick event hook.
+ * @details This hook is invoked in the system tick handler immediately
+ *          after processing the virtual timers queue.
+ */
+#define CH_CFG_SYSTEM_TICK_HOOK() {                                         \
+  /* System tick event code here.*/                                         \
+}
+
+/**
+ * @brief   System halt hook.
+ * @details This hook is invoked in case to a system halting error before
+ *          the system is halted.
+ */
+#define CH_CFG_SYSTEM_HALT_HOOK(reason) {                                   \
+  extern void aosPrintHaltErrorCode(const char* reason);                       \
+  aosPrintHaltErrorCode(reason);                                               \
+}
+
+/**
+ * @brief   Trace hook.
+ * @details This hook is invoked each time a new record is written in the
+ *          trace buffer.
+ */
+#define CH_CFG_TRACE_HOOK(tep) {                                            \
+  /* Trace code here.*/                                                     \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Port specific settings
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   NVIC VTOR initialization offset.
+ * @details On initialization, the code at this address in the flash memory will be executed.
+ */
+#define CORTEX_VTOR_INIT 0x00008000U
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name other
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Flag to enable/disable floating point support in chprinf()
+ */
+#define CHPRINTF_USE_FLOAT                  TRUE
+
+/** @} */
+
+#endif  /* _CHCONF_H_ */
+
+/** @} */
diff --git a/os/modules/PowerManagement_1-1/halconf.h b/os/modules/PowerManagement_1-1/halconf.h
new file mode 100644
index 0000000..16b7bd4
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/halconf.h
@@ -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    os/modules/PowerManagement/halconf.h
+ * @brief   HAL configuration header for the PowerManagement module.
+ * @details HAL configuration file, this file allows to enable or disable the
+ *          various device drivers from your application. You may also use
+ *          this file in order to override the device drivers default settings.
+ *
+ * @addtogroup HAL_CONF
+ * @{
+ */
+
+#ifndef _HALCONF_H_
+#define _HALCONF_H_
+
+/**
+ * @brief   Enables the PAL subsystem.
+ */
+#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
+#define HAL_USE_PAL                 TRUE
+#endif
+
+/**
+ * @brief   Enables the ADC subsystem.
+ */
+#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
+#define HAL_USE_ADC                 TRUE
+#endif
+
+/**
+ * @brief   Enables the CAN subsystem.
+ */
+#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
+#define HAL_USE_CAN                 TRUE
+#endif
+
+/**
+ * @brief   Enables the DAC subsystem.
+ */
+#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
+#define HAL_USE_DAC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the EXT subsystem.
+ */
+#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__)
+#define HAL_USE_EXT                 TRUE
+#endif
+
+/**
+ * @brief   Enables the GPT subsystem.
+ */
+#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
+#define HAL_USE_GPT                 FALSE
+#endif
+
+/**
+ * @brief   Enables the I2C subsystem.
+ */
+#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
+#define HAL_USE_I2C                 TRUE
+#endif
+
+/**
+ * @brief   Enables the I2S subsystem.
+ */
+#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
+#define HAL_USE_I2S                 FALSE
+#endif
+
+/**
+ * @brief   Enables the ICU subsystem.
+ */
+#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
+#define HAL_USE_ICU                 FALSE
+#endif
+
+/**
+ * @brief   Enables the MAC subsystem.
+ */
+#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
+#define HAL_USE_MAC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the MMC_SPI subsystem.
+ */
+#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_MMC_SPI             FALSE
+#endif
+
+/**
+ * @brief   Enables the PWM subsystem.
+ */
+#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
+#define HAL_USE_PWM                 TRUE
+#endif
+
+/**
+ * @brief   Enables the RTC subsystem.
+ */
+#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
+#define HAL_USE_RTC                 TRUE
+#endif
+
+/**
+ * @brief   Enables the SDC subsystem.
+ */
+#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
+#define HAL_USE_SDC                 FALSE
+#endif
+
+/**
+ * @brief   Enables the SERIAL subsystem.
+ */
+#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL              TRUE
+#endif
+
+/**
+ * @brief   Enables the SERIAL over USB subsystem.
+ */
+#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
+#define HAL_USE_SERIAL_USB          FALSE
+#endif
+
+/**
+ * @brief   Enables the SPI subsystem.
+ */
+#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
+#define HAL_USE_SPI                 TRUE
+#endif
+
+/**
+ * @brief   Enables the UART subsystem.
+ */
+#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
+#define HAL_USE_UART                FALSE
+#endif
+
+/**
+ * @brief   Enables the USB subsystem.
+ */
+#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
+#define HAL_USE_USB                 FALSE
+#endif
+
+/**
+ * @brief   Enables the WDG subsystem.
+ */
+#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
+#define HAL_USE_WDG                 FALSE
+#endif
+
+/**
+ * @brief   Enables the QEI subsystem.
+ */
+#if !defined(HAL_USE_QEI) || defined(__DOXYGEN__)
+#define HAL_USE_QEI                 FALSE
+#endif
+
+/*===========================================================================*/
+/* ADC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
+#define ADC_USE_WAIT                TRUE
+#endif
+
+/**
+ * @brief   Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define ADC_USE_MUTUAL_EXCLUSION    FALSE
+#endif
+
+/*===========================================================================*/
+/* CAN driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Sleep mode related APIs inclusion switch.
+ */
+#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
+#define CAN_USE_SLEEP_MODE          FALSE
+#endif
+
+/*===========================================================================*/
+/* I2C driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables the mutual exclusion APIs on the I2C bus.
+ */
+#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define I2C_USE_MUTUAL_EXCLUSION    TRUE
+#endif
+
+/*===========================================================================*/
+/* MAC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
+#define MAC_USE_ZERO_COPY           FALSE
+#endif
+
+/**
+ * @brief   Enables an event sources for incoming packets.
+ */
+#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
+#define MAC_USE_EVENTS              FALSE
+#endif
+
+/*===========================================================================*/
+/* MMC_SPI driver related settings.                                          */
+/*===========================================================================*/
+
+/**
+ * @brief   Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ *          routines releasing some extra CPU time for the threads with
+ *          lower priority, this may slow down the driver a bit however.
+ *          This option is recommended also if the SPI driver does not
+ *          use a DMA channel and heavily loads the CPU.
+ */
+#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
+#define MMC_NICE_WAITING            FALSE
+#endif
+
+/*===========================================================================*/
+/* SDC driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Number of initialization attempts before rejecting the card.
+ * @note    Attempts are performed at 10mS intervals.
+ */
+#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
+#define SDC_INIT_RETRY              100
+#endif
+
+/**
+ * @brief   Include support for MMC cards.
+ * @note    MMC support is not yet implemented so this option must be kept
+ *          at @p FALSE.
+ */
+#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
+#define SDC_MMC_SUPPORT             FALSE
+#endif
+
+/**
+ * @brief   Delays insertions.
+ * @details If enabled this options inserts delays into the MMC waiting
+ *          routines releasing some extra CPU time for the threads with
+ *          lower priority, this may slow down the driver a bit however.
+ */
+#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
+#define SDC_NICE_WAITING            FALSE
+#endif
+
+/*===========================================================================*/
+/* SERIAL driver related settings.                                           */
+/*===========================================================================*/
+
+/**
+ * @brief   Default bit rate.
+ * @details Configuration parameter, this is the baud rate selected for the
+ *          default configuration.
+ */
+#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
+#define SERIAL_DEFAULT_BITRATE      115200
+#endif
+
+/**
+ * @brief   Serial buffers size.
+ * @details Configuration parameter, you can change the depth of the queue
+ *          buffers depending on the requirements of your application.
+ * @note    The default is 16 bytes for both the transmission and receive
+ *          buffers.
+ */
+#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_BUFFERS_SIZE         16
+#endif
+
+/*===========================================================================*/
+/* SERIAL_USB driver related setting.                                        */
+/*===========================================================================*/
+
+/**
+ * @brief   Serial over USB buffers size.
+ * @details Configuration parameter, the buffer size must be a multiple of
+ *          the USB data endpoint maximum packet size.
+ * @note    The default is 256 bytes for both the transmission and receive
+ *          buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_SIZE     256
+#endif
+
+/**
+ * @brief   Serial over USB number of buffers.
+ * @note    The default is 2 buffers.
+ */
+#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
+#define SERIAL_USB_BUFFERS_NUMBER   2
+#endif
+
+/*===========================================================================*/
+/* SPI driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
+#define SPI_USE_WAIT                TRUE
+#endif
+
+/**
+ * @brief   Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define SPI_USE_MUTUAL_EXCLUSION    TRUE
+#endif
+
+/*===========================================================================*/
+/* UART driver related settings.                                             */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
+#define UART_USE_WAIT               FALSE
+#endif
+
+/**
+ * @brief   Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
+#define UART_USE_MUTUAL_EXCLUSION   FALSE
+#endif
+
+/*===========================================================================*/
+/* USB driver related settings.                                              */
+/*===========================================================================*/
+
+/**
+ * @brief   Enables synchronous APIs.
+ * @note    Disabling this option saves both code and data space.
+ */
+#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
+#define USB_USE_WAIT                FALSE
+#endif
+
+#endif /* _HALCONF_H_ */
+
+/** @} */
diff --git a/os/modules/PowerManagement_1-1/mcuconf.h b/os/modules/PowerManagement_1-1/mcuconf.h
new file mode 100644
index 0000000..fd198b9
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/mcuconf.h
@@ -0,0 +1,362 @@
+/*
+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 _MCUCONF_H_
+#define _MCUCONF_H_
+
+#define STM32F4xx_MCUCONF
+
+/*
+ * Some old revisions of F4x MCU randomly chrashes with certain compiler options enabled.
+ * This flag makes the kernel dynamically detect the MCUs ID code and CPU ID and react accordingly.
+ * (see ChibiOS kernel: os/hal/ports/STM32/STM32F4xx/hal_lld.c)
+ */
+#define STM32_USE_REVISION_A_FIX
+
+/*
+ * STM32F4xx drivers configuration.
+ * The following settings override the default settings present in
+ * the various device driver implementation headers.
+ * Note that the settings for each driver only have effect if the whole
+ * driver is enabled in halconf.h.
+ *
+ * IRQ priorities:
+ * 15...0       Lowest...Highest.
+ *
+ * DMA priorities:
+ * 0...3        Lowest...Highest.
+ */
+
+/*
+ * HAL driver system settings.
+ */
+#define STM32_NO_INIT                       FALSE
+#define STM32_HSI_ENABLED                   TRUE
+#define STM32_LSI_ENABLED                   TRUE
+#define STM32_HSE_ENABLED                   TRUE
+#define STM32_LSE_ENABLED                   FALSE
+#define STM32_CLOCK48_REQUIRED              TRUE
+#define STM32_SW                            STM32_SW_PLL
+#define STM32_PLLSRC                        STM32_PLLSRC_HSE
+#define STM32_PLLM_VALUE                    8
+#define STM32_PLLN_VALUE                    336
+#define STM32_PLLP_VALUE                    2
+#define STM32_PLLQ_VALUE                    7
+#define STM32_HPRE                          STM32_HPRE_DIV1
+#define STM32_PPRE1                         STM32_PPRE1_DIV4
+#define STM32_PPRE2                         STM32_PPRE2_DIV2
+#define STM32_RTCSEL                        STM32_RTCSEL_LSI
+#define STM32_RTCPRE_VALUE                  8
+#define STM32_MCO1SEL                       STM32_MCO1SEL_HSI
+#define STM32_MCO1PRE                       STM32_MCO1PRE_DIV1
+#define STM32_MCO2SEL                       STM32_MCO2SEL_SYSCLK
+#define STM32_MCO2PRE                       STM32_MCO2PRE_DIV5
+#define STM32_I2SSRC                        STM32_I2SSRC_CKIN
+#define STM32_PLLI2SN_VALUE                 192
+#define STM32_PLLI2SR_VALUE                 5
+#define STM32_PVD_ENABLE                    FALSE
+#define STM32_PLS                           STM32_PLS_LEV0
+#define STM32_BKPRAM_ENABLE                 FALSE
+
+/*
+ * ADC driver system settings.
+ */
+#define STM32_ADC_ADCPRE                    ADC_CCR_ADCPRE_DIV4
+#define STM32_ADC_USE_ADC1                  TRUE
+#define STM32_ADC_USE_ADC2                  FALSE
+#define STM32_ADC_USE_ADC3                  FALSE
+#define STM32_ADC_ADC1_DMA_STREAM           STM32_DMA_STREAM_ID(2, 4)
+#define STM32_ADC_ADC2_DMA_STREAM           STM32_DMA_STREAM_ID(2, 2)
+#define STM32_ADC_ADC3_DMA_STREAM           STM32_DMA_STREAM_ID(2, 1)
+#define STM32_ADC_ADC1_DMA_PRIORITY         2
+#define STM32_ADC_ADC2_DMA_PRIORITY         2
+#define STM32_ADC_ADC3_DMA_PRIORITY         2
+#define STM32_ADC_IRQ_PRIORITY              6
+#define STM32_ADC_ADC1_DMA_IRQ_PRIORITY     6
+#define STM32_ADC_ADC2_DMA_IRQ_PRIORITY     6
+#define STM32_ADC_ADC3_DMA_IRQ_PRIORITY     6
+
+/*
+ * CAN driver system settings.
+ */
+#define STM32_CAN_USE_CAN1                  TRUE
+#define STM32_CAN_USE_CAN2                  FALSE
+#define STM32_CAN_CAN1_IRQ_PRIORITY         11
+#define STM32_CAN_CAN2_IRQ_PRIORITY         11
+
+/*
+ * DAC driver system settings.
+ */
+#define STM32_DAC_DUAL_MODE                 FALSE
+#define STM32_DAC_USE_DAC1_CH1              FALSE
+#define STM32_DAC_USE_DAC1_CH2              FALSE
+#define STM32_DAC_DAC1_CH1_IRQ_PRIORITY     10
+#define STM32_DAC_DAC1_CH2_IRQ_PRIORITY     10
+#define STM32_DAC_DAC1_CH1_DMA_PRIORITY     2
+#define STM32_DAC_DAC1_CH2_DMA_PRIORITY     2
+#define STM32_DAC_DAC1_CH1_DMA_STREAM       STM32_DMA_STREAM_ID(1, 5)
+#define STM32_DAC_DAC1_CH2_DMA_STREAM       STM32_DMA_STREAM_ID(1, 6)
+
+/*
+ * EXT driver system settings.
+ */
+#define STM32_EXT_EXTI0_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI1_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI2_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI3_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI4_IRQ_PRIORITY        6
+#define STM32_EXT_EXTI5_9_IRQ_PRIORITY      6
+#define STM32_EXT_EXTI10_15_IRQ_PRIORITY    6
+#define STM32_EXT_EXTI16_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI17_IRQ_PRIORITY       15
+#define STM32_EXT_EXTI18_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI19_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI20_IRQ_PRIORITY       6
+#define STM32_EXT_EXTI21_IRQ_PRIORITY       15
+#define STM32_EXT_EXTI22_IRQ_PRIORITY       15
+
+/*
+ * GPT driver system settings.
+ */
+#define STM32_GPT_USE_TIM1                  FALSE
+#define STM32_GPT_USE_TIM2                  FALSE
+#define STM32_GPT_USE_TIM3                  FALSE
+#define STM32_GPT_USE_TIM4                  FALSE
+#define STM32_GPT_USE_TIM5                  FALSE
+#define STM32_GPT_USE_TIM6                  FALSE
+#define STM32_GPT_USE_TIM7                  FALSE
+#define STM32_GPT_USE_TIM8                  FALSE
+#define STM32_GPT_USE_TIM9                  FALSE
+#define STM32_GPT_USE_TIM11                 FALSE
+#define STM32_GPT_USE_TIM12                 FALSE
+#define STM32_GPT_USE_TIM14                 FALSE
+#define STM32_GPT_TIM1_IRQ_PRIORITY         7
+#define STM32_GPT_TIM2_IRQ_PRIORITY         7
+#define STM32_GPT_TIM3_IRQ_PRIORITY         7
+#define STM32_GPT_TIM4_IRQ_PRIORITY         7
+#define STM32_GPT_TIM5_IRQ_PRIORITY         7
+#define STM32_GPT_TIM6_IRQ_PRIORITY         7
+#define STM32_GPT_TIM7_IRQ_PRIORITY         7
+#define STM32_GPT_TIM8_IRQ_PRIORITY         7
+#define STM32_GPT_TIM9_IRQ_PRIORITY         7
+#define STM32_GPT_TIM11_IRQ_PRIORITY        7
+#define STM32_GPT_TIM12_IRQ_PRIORITY        7
+#define STM32_GPT_TIM14_IRQ_PRIORITY        7
+
+/*
+ * I2C driver system settings.
+ */
+#define STM32_I2C_USE_I2C1                  TRUE
+#define STM32_I2C_USE_I2C2                  TRUE
+#define STM32_I2C_USE_I2C3                  FALSE
+#define STM32_I2C_BUSY_TIMEOUT              50
+#define STM32_I2C_I2C1_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 0)
+#define STM32_I2C_I2C1_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 6)
+#define STM32_I2C_I2C2_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 2)
+#define STM32_I2C_I2C2_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 7)
+#define STM32_I2C_I2C3_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 2)
+#define STM32_I2C_I2C3_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 4)
+#define STM32_I2C_I2C1_IRQ_PRIORITY         5
+#define STM32_I2C_I2C2_IRQ_PRIORITY         5
+#define STM32_I2C_I2C3_IRQ_PRIORITY         5
+#define STM32_I2C_I2C1_DMA_PRIORITY         3
+#define STM32_I2C_I2C2_DMA_PRIORITY         3
+#define STM32_I2C_I2C3_DMA_PRIORITY         3
+#define STM32_I2C_DMA_ERROR_HOOK(i2cp)      osalSysHalt("DMA failure")
+#define STM32_I2C_USE_DMA                   TRUE
+
+/*
+ * I2S driver system settings.
+ */
+#define STM32_I2S_USE_SPI2                  FALSE
+#define STM32_I2S_USE_SPI3                  FALSE
+#define STM32_I2S_SPI2_IRQ_PRIORITY         10
+#define STM32_I2S_SPI3_IRQ_PRIORITY         10
+#define STM32_I2S_SPI2_DMA_PRIORITY         1
+#define STM32_I2S_SPI3_DMA_PRIORITY         1
+#define STM32_I2S_SPI2_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 3)
+#define STM32_I2S_SPI2_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 4)
+#define STM32_I2S_SPI3_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 0)
+#define STM32_I2S_SPI3_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 7)
+#define STM32_I2S_DMA_ERROR_HOOK(i2sp)      osalSysHalt("DMA failure")
+
+/*
+ * ICU driver system settings.
+ */
+#define STM32_ICU_USE_TIM1                  FALSE
+#define STM32_ICU_USE_TIM2                  FALSE
+#define STM32_ICU_USE_TIM3                  FALSE
+#define STM32_ICU_USE_TIM4                  FALSE
+#define STM32_ICU_USE_TIM5                  FALSE
+#define STM32_ICU_USE_TIM8                  FALSE
+#define STM32_ICU_USE_TIM9                  FALSE
+#define STM32_ICU_TIM1_IRQ_PRIORITY         7
+#define STM32_ICU_TIM2_IRQ_PRIORITY         7
+#define STM32_ICU_TIM3_IRQ_PRIORITY         7
+#define STM32_ICU_TIM4_IRQ_PRIORITY         7
+#define STM32_ICU_TIM5_IRQ_PRIORITY         7
+#define STM32_ICU_TIM8_IRQ_PRIORITY         7
+#define STM32_ICU_TIM9_IRQ_PRIORITY         7
+
+/*
+ * MAC driver system settings.
+ */
+#define STM32_MAC_TRANSMIT_BUFFERS          2
+#define STM32_MAC_RECEIVE_BUFFERS           4
+#define STM32_MAC_BUFFERS_SIZE              1522
+#define STM32_MAC_PHY_TIMEOUT               100
+#define STM32_MAC_ETH1_CHANGE_PHY_STATE     TRUE
+#define STM32_MAC_ETH1_IRQ_PRIORITY         13
+#define STM32_MAC_IP_CHECKSUM_OFFLOAD       0
+
+/*
+ * PWM driver system settings.
+ */
+#define STM32_PWM_USE_ADVANCED              FALSE
+#define STM32_PWM_USE_TIM1                  FALSE
+#define STM32_PWM_USE_TIM2                  FALSE
+#define STM32_PWM_USE_TIM3                  TRUE
+#define STM32_PWM_USE_TIM4                  FALSE
+#define STM32_PWM_USE_TIM5                  FALSE
+#define STM32_PWM_USE_TIM8                  FALSE
+#define STM32_PWM_USE_TIM9                  FALSE
+#define STM32_PWM_TIM1_IRQ_PRIORITY         7
+#define STM32_PWM_TIM2_IRQ_PRIORITY         7
+#define STM32_PWM_TIM3_IRQ_PRIORITY         7
+#define STM32_PWM_TIM4_IRQ_PRIORITY         7
+#define STM32_PWM_TIM5_IRQ_PRIORITY         7
+#define STM32_PWM_TIM8_IRQ_PRIORITY         7
+#define STM32_PWM_TIM9_IRQ_PRIORITY         7
+
+/*
+ * SDC driver system settings.
+ */
+#define STM32_SDC_SDIO_DMA_PRIORITY         3
+#define STM32_SDC_SDIO_IRQ_PRIORITY         9
+#define STM32_SDC_WRITE_TIMEOUT_MS          250
+#define STM32_SDC_READ_TIMEOUT_MS           25
+#define STM32_SDC_CLOCK_ACTIVATION_DELAY    10
+#define STM32_SDC_SDIO_UNALIGNED_SUPPORT    TRUE
+#define STM32_SDC_SDIO_DMA_STREAM           STM32_DMA_STREAM_ID(2, 3)
+
+/*
+ * SERIAL driver system settings.
+ */
+#define STM32_SERIAL_USE_USART1             TRUE
+#define STM32_SERIAL_USE_USART2             FALSE
+#define STM32_SERIAL_USE_USART3             FALSE
+#define STM32_SERIAL_USE_UART4              FALSE
+#define STM32_SERIAL_USE_UART5              FALSE
+#define STM32_SERIAL_USE_USART6             FALSE
+#define STM32_SERIAL_USART1_PRIORITY        12
+#define STM32_SERIAL_USART2_PRIORITY        12
+#define STM32_SERIAL_USART3_PRIORITY        12
+#define STM32_SERIAL_UART4_PRIORITY         12
+#define STM32_SERIAL_UART5_PRIORITY         12
+#define STM32_SERIAL_USART6_PRIORITY        12
+
+/*
+ * SPI driver system settings.
+ */
+#define STM32_SPI_USE_SPI1                  TRUE
+#define STM32_SPI_USE_SPI2                  FALSE
+#define STM32_SPI_USE_SPI3                  FALSE
+#define STM32_SPI_SPI1_RX_DMA_STREAM        STM32_DMA_STREAM_ID(2, 0)
+#define STM32_SPI_SPI1_TX_DMA_STREAM        STM32_DMA_STREAM_ID(2, 3)
+#define STM32_SPI_SPI2_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 3)
+#define STM32_SPI_SPI2_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 4)
+#define STM32_SPI_SPI3_RX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 0)
+#define STM32_SPI_SPI3_TX_DMA_STREAM        STM32_DMA_STREAM_ID(1, 7)
+#define STM32_SPI_SPI1_DMA_PRIORITY         1
+#define STM32_SPI_SPI2_DMA_PRIORITY         1
+#define STM32_SPI_SPI3_DMA_PRIORITY         1
+#define STM32_SPI_SPI1_IRQ_PRIORITY         10
+#define STM32_SPI_SPI2_IRQ_PRIORITY         10
+#define STM32_SPI_SPI3_IRQ_PRIORITY         10
+#define STM32_SPI_DMA_ERROR_HOOK(spip)      osalSysHalt("DMA failure")
+
+/*
+ * ST driver system settings.
+ */
+#define STM32_ST_IRQ_PRIORITY               8
+#define STM32_ST_USE_TIMER                  2
+
+/*
+ * UART driver system settings.
+ */
+#define STM32_UART_USE_USART1               FALSE
+#define STM32_UART_USE_USART2               TRUE
+#define STM32_UART_USE_USART3               TRUE
+#define STM32_UART_USE_UART4                FALSE
+#define STM32_UART_USE_UART5                FALSE
+#define STM32_UART_USE_USART6               FALSE
+#define STM32_UART_USART1_RX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 5)
+#define STM32_UART_USART1_TX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 7)
+#define STM32_UART_USART2_RX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 5)
+#define STM32_UART_USART2_TX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 6)
+#define STM32_UART_USART3_RX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 1)
+#define STM32_UART_USART3_TX_DMA_STREAM     STM32_DMA_STREAM_ID(1, 3)
+#define STM32_UART_UART4_RX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 2)
+#define STM32_UART_UART4_TX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 4)
+#define STM32_UART_UART5_RX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 0)
+#define STM32_UART_UART5_TX_DMA_STREAM      STM32_DMA_STREAM_ID(1, 7)
+#define STM32_UART_USART6_RX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 2)
+#define STM32_UART_USART6_TX_DMA_STREAM     STM32_DMA_STREAM_ID(2, 7)
+#define STM32_UART_USART1_IRQ_PRIORITY      12
+#define STM32_UART_USART2_IRQ_PRIORITY      12
+#define STM32_UART_USART3_IRQ_PRIORITY      12
+#define STM32_UART_UART4_IRQ_PRIORITY       12
+#define STM32_UART_UART5_IRQ_PRIORITY       12
+#define STM32_UART_USART6_IRQ_PRIORITY      12
+#define STM32_UART_USART1_DMA_PRIORITY      0
+#define STM32_UART_USART2_DMA_PRIORITY      0
+#define STM32_UART_USART3_DMA_PRIORITY      0
+#define STM32_UART_UART4_DMA_PRIORITY       0
+#define STM32_UART_UART5_DMA_PRIORITY       0
+#define STM32_UART_USART6_DMA_PRIORITY      0
+#define STM32_UART_DMA_ERROR_HOOK(uartp)    osalSysHalt("DMA failure")
+
+/*
+ * USB driver system settings.
+ */
+#define STM32_USB_USE_OTG1                  FALSE
+#define STM32_USB_USE_OTG2                  FALSE
+#define STM32_USB_OTG1_IRQ_PRIORITY         14
+#define STM32_USB_OTG2_IRQ_PRIORITY         14
+#define STM32_USB_OTG1_RX_FIFO_SIZE         512
+#define STM32_USB_OTG2_RX_FIFO_SIZE         1024
+#define STM32_USB_OTG_THREAD_PRIO           LOWPRIO
+#define STM32_USB_OTG_THREAD_STACK_SIZE     128
+#define STM32_USB_OTGFIFO_FILL_BASEPRI      0
+
+/*
+ * WDG driver system settings.
+ */
+#define STM32_WDG_USE_IWDG                  FALSE
+
+/*
+ * QEI driver system settings.
+ */
+#define STM32_QEI_USE_TIM1                  FALSE
+#define STM32_QEI_USE_TIM2                  FALSE
+#define STM32_QEI_USE_TIM3                  FALSE
+#define STM32_QEI_USE_TIM4                  FALSE
+#define STM32_QEI_USE_TIM5                  FALSE
+#define STM32_QEI_USE_TIM8                  FALSE
+
+#endif /* _MCUCONF_H_ */
diff --git a/os/modules/PowerManagement_1-1/module.c b/os/modules/PowerManagement_1-1/module.c
new file mode 100644
index 0000000..94feab6
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/module.c
@@ -0,0 +1,1139 @@
+/*
+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 "module.h"
+
+/*===========================================================================*/
+/**
+ * @name Module specific functions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiroos.h>
+
+/**
+ * @brief   Interrupt service routine callback for I/O interrupt signals.
+ *
+ * @param   extp      EXT driver to handle the ISR.
+ * @param   channel   Channel on which the interrupt was encountered.
+ */
+static void _moduleIsrCallback(EXTDriver* extp, expchannel_t channel) {
+  (void)extp;
+
+  chSysLockFromISR();
+  chEvtBroadcastFlagsI(&aos.events.io.source, (1 << channel));
+  chSysUnlockFromISR();
+
+  return;
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name ChibiOS/HAL configuration
+ * @{
+ */
+/*===========================================================================*/
+
+ADCConversionGroup moduleHalAdcVsysConversionGroup = {
+  /* buffer type        */ true,
+  /* number of channels */ 1,
+  /* callback function  */ NULL,
+  /* error callback     */ NULL,
+  /* CR1                */ ADC_CR1_AWDEN | ADC_CR1_AWDIE,
+  /* CR2                */ ADC_CR2_SWSTART | ADC_CR2_CONT,
+  /* SMPR1              */ 0,
+  /* SMPR2              */ ADC_SMPR2_SMP_AN9(ADC_SAMPLE_480),
+  /* HTR                */ ADC_HTR_HT,
+  /* LTR                */ 0,
+  /* SQR1               */ ADC_SQR1_NUM_CH(1),
+  /* SQR2               */ 0,
+  /* SQR3               */ ADC_SQR3_SQ1_N(ADC_CHANNEL_IN9),
+};
+
+CANConfig moduleHalCanConfig = {
+  /* mcr  */ CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_TXFP,
+  /* btr  */ CAN_BTR_SJW(1) | CAN_BTR_TS2(2) | CAN_BTR_TS1(13) | CAN_BTR_BRP(1),
+};
+
+EXTConfig moduleHalExtConfig = {
+  /* channel configrations */ {
+    /* channel  0 */ { // IR_INT1_N: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | APAL2CH_EDGE(VCNL4020_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  1 */ { // GAUGE_BATLOW1: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_RISING_EDGE,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  2 */ { // GAUGE_BATDG1_N: must be enabled expliciety
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_RISING_EDGE,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  3 */ { // SYS_UART_DN: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  4 */ { // IR_INT2_N: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOC | APAL2CH_EDGE(VCNL4020_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  5 */ { // TOUCH_INT: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOC | APAL2CH_EDGE(MPR121_LLD_INT_EDGE),
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  6 */ { // GAUGE_BATLOW2: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_RISING_EDGE,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  7 */ { // GAUGE_BATDG2_N: must be enabled expliciety
+      /* mode     */ EXT_MODE_GPIOB | EXT_CH_MODE_RISING_EDGE,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  8 */ { // PATH_DC: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_BOTH_EDGES,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel  9 */ { // SYS_SPI_DIR: must be enabled explicitely
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_BOTH_EDGES,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 10 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 11 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 12 */ { // SYS_SYNC_N: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 13 */ { // SYS_PD_N: automatic interrupt when activated
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 14 */ { // SYS_WARMRST_N: automatic interrupt when activated
+      /* mode     */ EXT_MODE_GPIOC | EXT_CH_MODE_FALLING_EDGE | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 15 */ { // SYS_UART_UP: automatic interrupt on event
+      /* mode     */ EXT_MODE_GPIOB| EXT_CH_MODE_BOTH_EDGES | EXT_CH_MODE_AUTOSTART,
+      /* callback */ _moduleIsrCallback,
+    },
+    /* channel 16 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 17 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 18 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 19 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 20 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 21 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+    /* channel 22 */ {
+      /* mode     */ EXT_CH_MODE_DISABLED,
+      /* callback */ NULL,
+    },
+  },
+};
+
+I2CConfig moduleHalI2cProxPm18Pm33GaugeRearConfig = {
+  /* I²C mode   */ OPMODE_I2C,
+  /* frequency  */ 400000, // TODO: replace with some macro (-> ChibiOS/HAL)
+  /* duty cycle */ FAST_DUTY_CYCLE_2,
+};
+
+I2CConfig moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig = {
+  /* I²C mode   */ OPMODE_I2C,
+  /* frequency  */ 400000, // TODO: replace with some macro (-> ChibiOS/HAL)
+  /* duty cycle */ FAST_DUTY_CYCLE_2,
+};
+
+PWMConfig moduleHalPwmBuzzerConfig = {
+  /* frequency              */ 1000000,
+  /* period                 */ 0,
+  /* callback               */ NULL,
+  /* channel configurations */ {
+    /* channel 0              */ {
+      /* mode                   */ PWM_OUTPUT_DISABLED,
+      /* callback               */ NULL
+    },
+    /* channel 1              */ {
+      /* mode                   */ PWM_OUTPUT_ACTIVE_HIGH,
+      /* callback               */ NULL
+    },
+    /* channel 2              */ {
+      /* mode                   */ PWM_OUTPUT_DISABLED,
+      /* callback               */ NULL
+    },
+    /* channel 3              */ {
+      /* mode                   */ PWM_OUTPUT_DISABLED,
+      /* callback               */ NULL
+    },
+  },
+  /* TIM CR2 register       */ 0,
+#if STM32_PWM_USE_ADVANCED
+  /* TIM BDTR register      */ 0,
+#endif
+  /* TIM DIER register      */ 0,
+};
+
+SerialConfig moduleHalProgIfConfig = {
+  /* bit rate */ 115200,
+  /* CR1      */ 0,
+  /* CR1      */ 0,
+  /* CR1      */ 0,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+
+apalGpio_t moduleGpioSysRegEn = {
+  /* port */ GPIOA,
+  /* pad  */ GPIOA_SYS_REG_EN,
+};
+
+apalGpio_t moduleGpioIrInt1 = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_IR_INT1_N,
+};
+
+apalGpio_t moduleGpioPowerEn = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_POWER_EN,
+};
+
+apalGpio_t moduleGpioSysUartDn = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_SYS_UART_DN,
+};
+
+apalGpio_t moduleGpioChargeStat2A = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_CHARGE_STAT2A,
+};
+
+apalGpio_t moduleGpioGaugeBatLow2 = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_GAUGE_BATLOW2,
+};
+
+apalGpio_t moduleGpioGaugeBatGd2 = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_GAUGE_BATGD2_N,
+};
+
+apalGpio_t moduleGpioLed = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_LED,
+};
+
+apalGpio_t moduleGpioSysUartUp = {
+  /* port */ GPIOB,
+  /* pad  */ GPIOB_SYS_UART_UP,
+};
+
+apalGpio_t moduleGpioChargeStat1A = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_CHARGE_STAT1A,
+};
+
+apalGpio_t moduleGpioGaugeBatLow1 = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_GAUGE_BATLOW1,
+};
+
+apalGpio_t moduleGpioGaugeBatGd1 = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_GAUGE_BATGD1_N,
+};
+
+apalGpio_t moduleGpioChargeEn1 = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_CHARGE_EN1_N,
+};
+
+apalGpio_t moduleGpioIrInt2 = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_IR_INT2_N,
+};
+
+apalGpio_t moduleGpioTouchInt = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_TOUCH_INT_N,
+};
+
+apalGpio_t moduleGpioSysDone = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_DONE,
+};
+
+apalGpio_t moduleGpioSysProg = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_PROG_N,
+};
+
+apalGpio_t moduleGpioPathDc = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_PATH_DC,
+};
+
+apalGpio_t moduleGpioSysSpiDir = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_SPI_DIR,
+};
+
+apalGpio_t moduleGpioSysSync = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_INT_N,
+};
+
+apalGpio_t moduleGpioSysPd = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_PD_N,
+};
+
+apalGpio_t moduleGpioSysWarmrst = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_SYS_WARMRST_N,
+};
+
+apalGpio_t moduleGpioBtRst = {
+  /* port */ GPIOC,
+  /* pad  */ GPIOC_BT_RST,
+};
+
+apalGpio_t moduleGpioChargeEn2 = {
+  /* port */ GPIOD,
+  /* pad  */ GPIOD_CHARGE_EN2_N,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name AMiRo-OS core configurations
+ * @{
+ */
+/*===========================================================================*/
+
+apalControlGpio_t moduleSsspPd = {
+  /* GPIO */ &moduleGpioSysPd,
+  /* meta */ {
+    /* active state */ APAL_GPIO_ACTIVE_LOW,
+    /* edge         */ APAL_GPIO_EDGE_FALLING,
+    /* direction    */ APAL_GPIO_DIRECTION_BIDIRECTIONAL,
+  },
+};
+
+apalControlGpio_t moduleSsspSync = {
+  /* GPIO */ &moduleGpioSysSync,
+  /* meta */ {
+    /* active state */ APAL_GPIO_ACTIVE_LOW,
+    /* edge         */ APAL_GPIO_EDGE_FALLING,
+    /* direction    */ APAL_GPIO_DIRECTION_BIDIRECTIONAL,
+  },
+};
+
+const char* moduleShellPrompt = "PowerManagement";
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+
+AT24C01BNDriver moduleLldEeprom = {
+  /* I2C driver   */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+  /* I2C address  */ AT24C01BN_LLD_I2C_ADDR_FIXED,
+};
+
+BQ24103ADriver moduleLldBatteryChargerFront = {
+  /* charge enable GPIO */ {
+    /* GPIO */ &moduleGpioChargeEn1,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+  /* charge status GPIO */ {
+    /* GPIO */ &moduleGpioChargeStat1A,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+};
+
+BQ24103ADriver moduleLldBatteryChargerRear = {
+  /* charge enable GPIO */ {
+    /* GPIO */ &moduleGpioChargeEn2,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+  /* charge status GPIO */ {
+    /* GPIO */ &moduleGpioChargeStat2A,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+};
+
+BQ27500Driver moduleLldFuelGaugeFront = {
+  /* I2C driver       */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+  /* battery low GPIO */ {
+    /* GPIO */ &moduleGpioGaugeBatLow1,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+  /* battery good GPIO */ {
+    /* GPIO */ &moduleGpioGaugeBatGd1,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+};
+
+BQ27500Driver moduleLldFuelGaugeRear = {
+  /* I2C driver       */ &MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR,
+  /* battery low GPIO */ {
+    /* GPIO */ &moduleGpioGaugeBatLow2,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+  /* battery good GPIO */ {
+    /* GPIO */ &moduleGpioGaugeBatGd2,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_INPUT,
+    },
+  },
+};
+
+INA219Driver moduleLldPowerMonitorVdd = {
+  /* I2C Driver       */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+  /* I²C address      */ INA219_LLD_I2C_ADDR_A0 | INA219_LLD_I2C_ADDR_A1,
+  /* current LSB (uA) */ 0x00u,
+  /* configuration    */ NULL,
+};
+
+INA219Driver moduleLldPowerMonitorVio18 = {
+  /* I2C Driver       */ &MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR,
+  /* I²C address      */ INA219_LLD_I2C_ADDR_A1,
+  /* current LSB (uA) */ 0x00u,
+  /* configuration    */ NULL,
+};
+
+INA219Driver moduleLldPowerMonitorVio33 = {
+  /* I2C Driver       */ &MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR,
+  /* I²C address      */ INA219_LLD_I2C_ADDR_FIXED,
+  /* current LSB (uA) */ 0x00u,
+  /* configuration    */ NULL,
+};
+
+INA219Driver moduleLldPowerMonitorVsys42 = {
+  /* I2C Driver       */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+  /* I²C address      */ INA219_LLD_I2C_ADDR_FIXED,
+  /* current LSB (uA) */ 0x00u,
+  /* configuration    */ NULL,
+};
+
+INA219Driver moduleLldPowerMonitorVio50 = {
+  /* I2C Driver       */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+  /* I²C address      */ INA219_LLD_I2C_ADDR_A1,
+  /* current LSB (uA) */ 0x00u,
+  /* configuration    */ NULL,
+};
+
+LEDDriver moduleLldStatusLed = {
+  /* LED GPIO */ {
+    /* GPIO */ &moduleGpioLed,
+    /* meta */ {
+      /* active state */ APAL_GPIO_ACTIVE_LOW,
+      /* edge         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+};
+
+MPR121Driver moduleLldTouch = {
+  /* I²C Driver */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+};
+
+PCA9544ADriver moduleLldI2cMultiplexer1 = {
+  /* I²C driver   */ &MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR,
+  /* I²C address  */ PCA9544A_LLD_I2C_ADDR_A0 | PCA9544A_LLD_I2C_ADDR_A1 | PCA9544A_LLD_I2C_ADDR_A2,
+};
+
+PCA9544ADriver moduleLldI2cMultiplexer2 = {
+  /* I²C driver   */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+  /* I²C address  */ PCA9544A_LLD_I2C_ADDR_A0 | PCA9544A_LLD_I2C_ADDR_A1 | PCA9544A_LLD_I2C_ADDR_A2,
+};
+
+TPS62113Driver moduleLldStepDownConverter = {
+  /* Power enable GPIO */ {
+    /* GPIO       */ &moduleGpioPowerEn,
+    /* GPIO meta  */ {
+      /* active state */ APAL_GPIO_ACTIVE_HIGH,
+      /* egde         */ APAL_GPIO_EDGE_NONE,
+      /* direction    */ APAL_GPIO_DIRECTION_OUTPUT,
+    },
+  },
+};
+
+VCNL4020Driver moduleLldProximity1 = {
+  /* I²C Driver */ &MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR,
+};
+
+VCNL4020Driver moduleLldProximity2 = {
+  /* I²C Driver */ &MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT,
+};
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Unit tests (UT)
+ * @{
+ */
+/*===========================================================================*/
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <string.h>
+
+/* ADC  */
+static int _utShellCmdCb_Adc(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAdcVsys, NULL);
+  return AOS_OK;
+}
+static ut_adcdata_t _utAdcVsysData = {
+  /* driver               */ &MODULE_HAL_ADC_VSYS,
+  /* ADC conversion group */ &moduleHalAdcVsysConversionGroup,
+};
+aos_unittest_t moduleUtAdcVsys = {
+  /* name           */ "ADC",
+  /* info           */ "VSYS",
+  /* test function  */ utAdcFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:ADC",
+    /* callback */ _utShellCmdCb_Adc,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAdcVsysData,
+};
+
+/* AT24C01BN-SH-B (EEPROM) */
+static int _utShellCmdCb_AlldAt24c01bn(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldAt24c01bn, NULL);
+  return AOS_OK;
+}
+static ut_at24c01bndata_t _utAlldAt24c01bnData = {
+  /* driver   */ &moduleLldEeprom,
+  /* timeout  */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldAt24c01bn = {
+  /* name           */ "AT24C01BN-SH-B",
+  /* info           */ "1kbit EEPROM",
+  /* test function  */ utAlldAt24c01bnFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:EEPROM",
+    /* callback */ _utShellCmdCb_AlldAt24c01bn,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldAt24c01bnData,
+};
+
+/* BQ24103A (battery charger) */
+static int _utShellCmdCb_AlldBq24103a(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  // local variables
+  bool print_help = false;
+
+  // evaluate argument
+  if (argc == 2) {
+    if (strcmp(argv[1], "-f") == 0 || strcmp(argv[1], "--front") == 0) {
+      moduleUtAlldBq24103a.data = &moduleLldBatteryChargerFront;
+      aosUtRun(stream, &moduleUtAlldBq24103a, "front battery");
+      moduleUtAlldBq24103a.data = NULL;
+    }
+    else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--rear") == 0) {
+      moduleUtAlldBq24103a.data = &moduleLldBatteryChargerRear;
+      aosUtRun(stream, &moduleUtAlldBq24103a, "rear battery");
+      moduleUtAlldBq24103a.data = NULL;
+    }
+    else {
+      print_help = true;
+    }
+  } else {
+    print_help = true;
+  }
+
+  // print help or just return
+  if (print_help) {
+    chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+    chprintf(stream, "Options:\n");
+    chprintf(stream, "  --front, -f\n");
+    chprintf(stream, "    Test the front battery charger.\n");
+    chprintf(stream, "  --rear, -r\n");
+    chprintf(stream, "    Test the rear battery charger.\n");
+    return AOS_INVALID_ARGUMENTS;
+  } else {
+    return AOS_OK;
+  }
+}
+aos_unittest_t moduleUtAlldBq24103a = {
+  /* name           */ "BQ24103A",
+  /* info           */ "battery charger",
+  /* test function  */ utAlldBq24103aFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:BatteryCharger",
+    /* callback */ _utShellCmdCb_AlldBq24103a,
+    /* next     */ NULL,
+  },
+  /* data           */ NULL,
+};
+
+/* BQ27500 (fuel gauge) */
+static int _utShellCmdCb_AlldBq27500(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  // evaluate arguments
+  if (argc == 2) {
+    if (strcmp(argv[1], "-f") == 0 || strcmp(argv[1], "--front") == 0) {
+      ((ut_bq27500data_t*)moduleUtAlldBq27500.data)->driver = &moduleLldFuelGaugeFront;
+      aosUtRun(stream, &moduleUtAlldBq27500, "front battery");
+      ((ut_bq27500data_t*)moduleUtAlldBq27500.data)->driver = NULL;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--rear") == 0) {
+      ((ut_bq27500data_t*)moduleUtAlldBq27500.data)->driver = &moduleLldFuelGaugeRear;
+      aosUtRun(stream, &moduleUtAlldBq27500, "rear battery");
+      ((ut_bq27500data_t*)moduleUtAlldBq27500.data)->driver = NULL;
+      return AOS_OK;
+    }
+  }
+  // print help
+  chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+  chprintf(stream, "Options:\n");
+  chprintf(stream, "  --front, -f\n");
+  chprintf(stream, "    Test the front battery fuel gauge.\n");
+  chprintf(stream, "  --rear, -r\n");
+  chprintf(stream, "    Test the rear battery fuel gauge.\n");
+  return AOS_INVALID_ARGUMENTS;
+}
+static ut_bq27500data_t _utAlldBq27500Data = {
+  /* driver   */ NULL,
+  /* timeout  */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldBq27500 = {
+  /* name           */ "BQ27500",
+  /* info           */ "fuel gauge",
+  /* test function  */ utAlldBq27500Func,
+  /* shell command  */ {
+    /* name     */ "unittest:FuelGauge",
+    /* callback */ _utShellCmdCb_AlldBq27500,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldBq27500Data,
+};
+
+/* BQ27500 (fuel gauge) in combination with BQ24103A (battery charger) */
+static int _utShellCmdCb_AlldBq27500Bq24103a(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  // evaluate arguments
+  if (argc == 2) {
+    if (strcmp(argv[1], "-f") == 0 || strcmp(argv[1], "--front") == 0) {
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq27500 = &moduleLldFuelGaugeFront;
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq24103a = &moduleLldBatteryChargerFront;
+      aosUtRun(stream, &moduleUtAlldBq27500Bq24103a, "front battery");
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq27500 = NULL;
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq24103a = NULL;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "-r") == 0 || strcmp(argv[1], "--rear") == 0) {
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq27500 = &moduleLldFuelGaugeRear;
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq24103a = &moduleLldBatteryChargerRear;
+      aosUtRun(stream, &moduleUtAlldBq27500Bq24103a, "rear battery");
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq27500 = NULL;
+      ((ut_bq27500bq24103adata_t*)moduleUtAlldBq27500Bq24103a.data)->bq24103a = NULL;
+      return AOS_OK;
+    }
+  }
+  // print help
+  chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+  chprintf(stream, "Options:\n");
+  chprintf(stream, "  --front, -f\n");
+  chprintf(stream, "    Test the front battery fuel gauge and charger.\n");
+  chprintf(stream, "  --rear, -r\n");
+  chprintf(stream, "    Test the rear battery fuel gauge and charger.\n");
+  return AOS_INVALID_ARGUMENTS;
+}
+static ut_bq27500bq24103adata_t _utAlldBq27500Bq24103aData= {
+  /* BQ27500 driver   */ NULL,
+  /* BQ23203A driver  */ NULL,
+  /* timeout          */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldBq27500Bq24103a = {
+  /* name           */ "BQ27500 & BQ24103A",
+  /* info           */ "fuel gauge & battery charger",
+  /* test function  */ utAlldBq27500Bq24103aFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:FuelGauge&BatteryCharger",
+    /* callback */ _utShellCmdCb_AlldBq27500Bq24103a,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldBq27500Bq24103aData,
+};
+
+/* INA219 (power monitor) */
+static int _utShellCmdCb_AlldIna219(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  // evaluate arguments
+  if (argc == 2) {
+    if (strcmp(argv[1], "VDD") == 0) {
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = &moduleLldPowerMonitorVdd;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 3.3f;
+      aosUtRun(stream, &moduleUtAlldIna219, "VDD (3.3V)");
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = NULL;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 0.0f;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "VIO1.8") == 0) {
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = &moduleLldPowerMonitorVio18;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 1.8f;
+      aosUtRun(stream, &moduleUtAlldIna219, "VIO (1.8V)");
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = NULL;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 0.0f;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "VIO3.3") == 0) {
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = &moduleLldPowerMonitorVio33;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 3.3f;
+      aosUtRun(stream, &moduleUtAlldIna219, "VIO (3.3V)");
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = NULL;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 0.0f;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "VSYS4.2") == 0) {
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = &moduleLldPowerMonitorVsys42;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 4.2f;
+      aosUtRun(stream, &moduleUtAlldIna219, "VSYS (4.2V)");
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = NULL;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 0.0f;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "VIO5.0") == 0) {
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = &moduleLldPowerMonitorVio50;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 5.0f;
+      aosUtRun(stream, &moduleUtAlldIna219, "VIO (5.0V)");
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->inad = NULL;
+      ((ut_ina219data_t*)moduleUtAlldIna219.data)->v_expected = 0.0f;
+      return AOS_OK;
+    }
+  }
+  // print help
+  chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+  chprintf(stream, "Options:\n");
+  chprintf(stream, "  VDD\n");
+  chprintf(stream, "    Test VDD (3.3V) power monitor.\n");
+  chprintf(stream, "  VIO1.8\n");
+  chprintf(stream, "    Test VIO 1.8V power monitor.\n");
+  chprintf(stream, "  VIO3.3\n");
+  chprintf(stream, "    Test VIO 3.3V power monitor.\n");
+  chprintf(stream, "  VSYS4.2\n");
+  chprintf(stream, "    Test VSYS 4.2V power monitor.\n");
+  chprintf(stream, "  VIO5.0\n");
+  chprintf(stream, "    Test VIO 5.0V power monitor.\n");
+  return AOS_INVALID_ARGUMENTS;
+}
+static ut_ina219data_t _utAlldIna219Data = {
+  /* driver           */ NULL,
+  /* expected voltage */ 0.0f,
+  /* tolerance        */ 0.05f,
+  /* timeout          */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldIna219 = {
+  /* name           */ "INA219",
+  /* info           */ "power monitor",
+  /* test function  */ utAlldIna219Func,
+  /* shell command  */ {
+    /* name     */ "unittest:PowerMonitor",
+    /* callback */ _utShellCmdCb_AlldIna219,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldIna219Data,
+};
+
+/* Status LED */
+static int _utShellCmdCb_AlldLed(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldLed, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldLed = {
+  /* name           */ "LED",
+  /* info           */ NULL,
+  /* test function  */ utAlldLedFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:StatusLED",
+    /* callback */ _utShellCmdCb_AlldLed,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldStatusLed,
+};
+
+/* MPR121 (touch sensor) */
+static int _utShellCmdCb_AlldMpr121(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_TOUCHINT);
+  aosUtRun(stream, &moduleUtAlldMpr121, NULL);
+  return AOS_OK;
+}
+static ut_mpr121data_t _utAlldMpr121Data= {
+  /* MPR121 driver  */ &moduleLldTouch,
+  /* timeout        */ MICROSECONDS_PER_SECOND,
+  /* event source   */ &aos.events.io.source,
+  /* event flags    */ (1 << MODULE_GPIO_EXTCHANNEL_TOUCHINT),
+};
+aos_unittest_t moduleUtAlldMpr121 = {
+  /* name           */ "MPR121",
+  /* info           */ "touch sensor",
+  /* test function  */ utAlldMpr121Func,
+  /* shell command  */ {
+    /* name     */ "unittest:Touch",
+    /* callback */ _utShellCmdCb_AlldMpr121,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldMpr121Data,
+};
+
+/* PCA9544A (I2C multiplexer) */
+static int _utShellCmdCb_AlldPca5944a(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  // evaluate arguments
+  if (argc == 2) {
+    if (strcmp(argv[1], "#1") == 0) {
+      ((ut_pca9544adata_t*)moduleUtAlldPca9544a.data)->driver = &moduleLldI2cMultiplexer1;
+      aosUtRun(stream, &moduleUtAlldPca9544a, "I2C bus #1");
+      ((ut_pca9544adata_t*)moduleUtAlldPca9544a.data)->driver = NULL;
+      return AOS_OK;
+    }
+    else if (strcmp(argv[1], "#2") == 0) {
+      ((ut_pca9544adata_t*)moduleUtAlldPca9544a.data)->driver = &moduleLldI2cMultiplexer2;
+      aosUtRun(stream, &moduleUtAlldPca9544a, "I2C bus #2");
+      ((ut_pca9544adata_t*)moduleUtAlldPca9544a.data)->driver = NULL;
+      return AOS_OK;
+    }
+  }
+  // print help
+  chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+  chprintf(stream, "Options:\n");
+  chprintf(stream, "  #1\n");
+  chprintf(stream, "    Test the multiplexer on the I2C bus #1.\n");
+  chprintf(stream, "  #2\n");
+  chprintf(stream, "    Test the multiplexer on the I2C bus #2.\n");
+  return AOS_INVALID_ARGUMENTS;
+}
+static ut_pca9544adata_t _utAlldPca9544aData = {
+  /* driver   */ NULL,
+  /* timeout  */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldPca9544a = {
+  /* name           */ "PCA9544A",
+  /* info           */ "I2C multiplexer",
+  /* test function  */ utAlldPca9544aFunc,
+  /* shell command  */ {
+    /* name     */ "unittest:I2CMultiplexer",
+    /* callback */ _utShellCmdCb_AlldPca5944a,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldPca9544aData,
+};
+
+/* PKLCS1212E4001 (buzzer) */
+static int _utShellCmdCb_AlldPklcs1212e4001(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldPklcs1212e4001, NULL);
+  return AOS_OK;
+}
+static ut_pklcs1212e4001_t _utAlldPklcs1212e4001Data = {
+  /* PWM driver   */ &MODULE_HAL_PWM_BUZZER,
+  /* PWM channel  */ MODULE_HAL_PWM_BUZZER_CHANNEL
+};
+aos_unittest_t moduleUtAlldPklcs1212e4001 = {
+  /* name           */ "PKLCS1212E4001",
+  /* info           */ "buzzer",
+  /* test function  */ utAlldPklcs1212e4001Func,
+  /* shell command  */ {
+    /* name     */ "unittest:Buzzer",
+    /* callback */ _utShellCmdCb_AlldPklcs1212e4001,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldPklcs1212e4001Data,
+};
+
+/* TPS62113 (stop-down converter) */
+static int _utShellCmdCb_AlldTps62113(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  // Although there are four TPS62113 on the PCB, they all share the same input signal.
+  // A sa result, no additional shell arguments need to be evaluated.
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldTps62113, NULL);
+  return AOS_OK;
+}
+aos_unittest_t moduleUtAlldTps62113 = {
+  /* name           */ "TPS62113",
+  /* info           */ "step-down converter",
+  /* test function  */ utAlldTps62113Func,
+  /* shell command  */ {
+    /* name     */ "unittest:StepDownConverter",
+    /* callback */ _utShellCmdCb_AlldTps62113,
+    /* next     */ NULL,
+  },
+  /* data           */ &moduleLldStepDownConverter,
+};
+
+/* TPS62113 (step-donw converter) in combination with INA219 (power monitor) */
+static int _utShellCmdCb_AlldTps62113Ina219(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  (void)argc;
+  (void)argv;
+  aosUtRun(stream, &moduleUtAlldTps62113Ina219, "VSYS (4.2V)");
+  return AOS_OK;
+}
+ut_tps62113ina219data_t _utAlldTps62113Ina219Data = {
+  /* TPS62113 */ &moduleLldStepDownConverter,
+  /* INA219   */ &moduleLldPowerMonitorVsys42,
+  /* timeout  */ MICROSECONDS_PER_SECOND,
+};
+aos_unittest_t moduleUtAlldTps62113Ina219 = {
+  /* name           */ "TPS62113 & INA219",
+  /* info           */ "step-down converter & power monitor",
+  /* test function  */ utAlldTps62113Ina219Func,
+  /* shell command  */ {
+    /* name     */ "unittest:StepDownConverter&PowerMonitor",
+    /* callback */ _utShellCmdCb_AlldTps62113Ina219,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldTps62113Ina219Data,
+};
+
+/* VCNL4020 (proximity sensor) */
+static void _utAlldVcnl4020_disableInterrupt(VCNL4020Driver* vcnl)
+{
+  uint8_t intstatus;
+  vcnl4020_lld_writereg(vcnl, VCNL4020_LLD_REGADDR_INTCTRL, 0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+  vcnl4020_lld_readreg(vcnl, VCNL4020_LLD_REGADDR_INTSTATUS, &intstatus, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+  if (intstatus) {
+    vcnl4020_lld_writereg(vcnl, VCNL4020_LLD_REGADDR_INTSTATUS, intstatus, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+  }
+  return;
+}
+static int _utShellCmdCb_AlldVcnl4020(BaseSequentialStream* stream, int argc, char* argv[])
+{
+  enum {
+    UNKNOWN,
+    NNE, ENE, ESE, SSE, SSW,WSW,WNW, NNW,
+  } sensor = UNKNOWN;
+  // evaluate arguments
+  if (argc == 2) {
+    if (strcmp(argv[1], "-nne") == 0) {
+      sensor = NNE;
+    } else if (strcmp(argv[1], "-ene") == 0) {
+      sensor = ENE;
+    } else if (strcmp(argv[1], "-ese") == 0) {
+      sensor = ESE;
+    } else if (strcmp(argv[1], "-sse") == 0) {
+      sensor = SSE;
+    } else if (strcmp(argv[1], "-ssw") == 0) {
+      sensor = SSW;
+    } else if (strcmp(argv[1], "-wsw") == 0) {
+      sensor = WSW;
+    } else if (strcmp(argv[1], "-wnw") == 0) {
+      sensor = WNW;
+    } else if (strcmp(argv[1], "-nnw") == 0) {
+      sensor = NNW;
+    }
+  }
+  if (sensor != UNKNOWN) {
+    PCA9544ADriver* mux = NULL;
+    switch (sensor) {
+      case SSE:
+      case SSW:
+      case WSW:
+      case WNW:
+        mux = &moduleLldI2cMultiplexer1;
+        ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld = &moduleLldProximity1;
+        ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->evtflags = (1 << MODULE_GPIO_EXTCHANNEL_IRINT2);
+        extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_IRINT2);
+        break;
+      case NNW:
+      case NNE:
+      case ENE:
+      case ESE:
+        mux = &moduleLldI2cMultiplexer2;
+        ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld = &moduleLldProximity2;
+        ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->evtflags = (1 << MODULE_GPIO_EXTCHANNEL_IRINT1);
+        extChannelEnable(&MODULE_HAL_EXT, MODULE_GPIO_EXTCHANNEL_IRINT1);
+        break;
+      default:
+        break;
+    }
+    pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH1, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH2, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH3, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+    _utAlldVcnl4020_disableInterrupt(((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld);
+    switch (sensor) {
+      case NNE:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH1, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "north-northeast sensor");
+        break;
+      case ENE:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH3, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "east-northeast sensor");
+        break;
+      case ESE:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH2, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "north-southeast sensor");
+        break;
+      case SSE:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "south-southeast sensor");
+        break;
+      case SSW:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH1, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "south-southwest sensor");
+        break;
+      case WSW:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH3, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "west-southwest sensor");
+        break;
+      case WNW:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH2, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "west-northwest sensor");
+        break;
+      case NNW:
+        pca9544a_lld_setchannel(mux, PCA9544A_LLD_CH0, ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->timeout);
+        aosUtRun(stream, &moduleUtAlldVcnl4020, "north-northwest sensor");
+        break;
+      default:
+        break;
+    }
+    ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->vcnld = NULL;
+    ((ut_vcnl4020data_t*)moduleUtAlldVcnl4020.data)->evtflags = 0;
+    return AOS_OK;
+  }
+  // print help
+  chprintf(stream, "Usage: %s OPTION\n", argv[0]);
+  chprintf(stream, "Options:\n");
+  chprintf(stream, "  -nne\n");
+  chprintf(stream, "    Test north-northeast sensor.\n");
+  chprintf(stream, "  -ene\n");
+  chprintf(stream, "    Test east-northeast sensor.\n");
+  chprintf(stream, "  -ese\n");
+  chprintf(stream, "    Test east-southeast sensor.\n");
+  chprintf(stream, "  -sse\n");
+  chprintf(stream, "    Test south-southeast sensor.\n");
+  chprintf(stream, "  -ssw\n");
+  chprintf(stream, "    Test south-southwest sensor.\n");
+  chprintf(stream, "  -wsw\n");
+  chprintf(stream, "    Test west-southwest sensor.\n");
+  chprintf(stream, "  -wnw\n");
+  chprintf(stream, "    Test west-northwest sensor.\n");
+  chprintf(stream, "  -nnw\n");
+  chprintf(stream, "    Test north-northwest sensor.\n");
+  return AOS_INVALID_ARGUMENTS;
+}
+static ut_vcnl4020data_t _utAlldVcnl4020Data = {
+  /* driver       */ NULL,
+  /* timeout      */ MICROSECONDS_PER_SECOND,
+  /* event source */ &aos.events.io.source,
+  /* event flags  */ 0,
+};
+aos_unittest_t moduleUtAlldVcnl4020 = {
+  /* name           */ "VCNL4020",
+  /* info           */ "proximity sensor",
+  /* test function  */ utAlldVcnl4020Func,
+  /* shell command  */ {
+    /* name     */ "unittest:Proximity",
+    /* callback */ _utShellCmdCb_AlldVcnl4020,
+    /* next     */ NULL,
+  },
+  /* data           */ &_utAlldVcnl4020Data,
+};
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
diff --git a/os/modules/PowerManagement_1-1/module.h b/os/modules/PowerManagement_1-1/module.h
new file mode 100644
index 0000000..edd1dc2
--- /dev/null
+++ b/os/modules/PowerManagement_1-1/module.h
@@ -0,0 +1,706 @@
+/*
+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
+ * @{
+ */
+/*===========================================================================*/
+
+/*
+ * @brief Makro to store data in the core coupled memory (ccm).
+ *        Example:
+ *        int compute_buffer[128] CCM_RAM;
+ *
+ * @note The ccm is not connected to any bus system.
+ */
+#define CCM_RAM                                 __attribute__((section(".ram4"), aligned(4)))
+
+/*
+ * @brief Makro to store data in the ethernet memory (eth).
+ *        Example:
+ *        int dma_buffer[128] ETH_RAM;
+ *
+ * @note The eth is a dedicated memory block with its own DMA controller.
+ */
+#define ETH_RAM                                 __attribute__((section(".ram2"), aligned(4)))
+
+/*
+ * @brief Makro to store data in the backup memory (bckp).
+ *        Example:
+ *        int backup_buffer[128] BCKP_RAM;
+ *
+ * @note The eth is a dedicated memory block with its own DMA controller.
+ */
+#define BCKP_RAM                                __attribute__((section(".ram5"), aligned(4)))
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name ChibiOS/HAL configuration
+ * @{
+ */
+/*===========================================================================*/
+#include <hal.h>
+
+/**
+ * @brief   ADC driver for reading the system voltage.
+ */
+#define MODULE_HAL_ADC_VSYS                     ADCD1
+
+/**
+ * @brief   Configuration for the ADC.
+ */
+extern ADCConversionGroup moduleHalAdcVsysConversionGroup;
+
+/**
+ * @brief   CAN driver to use.
+ */
+#define MODULE_HAL_CAN                          CAND1
+
+/**
+ * @brief   Configuration for the CAN driver.
+ */
+extern CANConfig moduleHalCanConfig;
+
+/**
+ * @brief   Interrupt driver to use.
+ */
+#define MODULE_HAL_EXT                          EXTD1
+
+/**
+ * @brief   Interrupt driver configuration.
+ */
+extern EXTConfig moduleHalExtConfig;
+
+/**
+ * @brief   I2C driver to access multiplexer, proximity sensors 1 to 4, power monitors for VIO1.8 and VIO 3.3, and fuel gauge (rear battery).
+ */
+#define MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR I2CD1
+
+/**
+ * @brief   Configuration for the multiplexer, proximity sensors 1 to 4, power monitors for VIO1.8 and VIO 3.3, and fuel gauge (rear battery) I2C driver.
+ */
+extern I2CConfig moduleHalI2cProxPm18Pm33GaugeRearConfig;
+
+/**
+ * @brief   I2C driver to access multiplexer, proximity sensors 5 to 8, power monitors for VSYS4.2, VIO 5.0 and VDD, EEPROM, touch sensor, and fuel gauge (front battery).
+ */
+#define MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT I2CD2
+
+/**
+ * @brief   Configuration for the multiplexer, proximity sensors 1 to 4, power monitors for VIO1.8 and VIO 3.3, and fuel gauge (rear battery) I2C driver.
+ */
+extern I2CConfig moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig;
+
+/**
+ * @brief   PWM driver for the buzzer.
+ */
+#define MODULE_HAL_PWM_BUZZER                   PWMD3
+
+/**
+ * @brief   Configuration of the PWM driver.
+ */
+extern PWMConfig moduleHalPwmBuzzerConfig;
+
+/**
+ * @brief   PWM channeö for the buzzer.
+ */
+#define MODULE_HAL_PWM_BUZZER_CHANNEL           1
+
+/**
+ * @brief   Serial driver of the programmer interface.
+ */
+#define MODULE_HAL_PROGIF                       SD1
+
+/**
+ * @brief   Configuration for the programmer serial interface driver.
+ */
+extern SerialConfig moduleHalProgIfConfig;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name GPIO definitions
+ * @{
+ */
+/*===========================================================================*/
+#include <amiro-lld.h>
+
+/**
+ * @brief   Interrupt channel for the IR_INT1 and CHARGE_STAT1A signals.
+ */
+#define MODULE_GPIO_EXTCHANNEL_IRINT1           ((expchannel_t)0)
+
+/**
+ * @brief   Interrupt channel for the GAUGE_BATLOW1 signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_GAUGEBATLOW1     ((expchannel_t)1)
+
+/**
+ * @brief   Interrupt channel for the GAUGE_BATGD1 signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_GAUGEBATGD1      ((expchannel_t)2)
+
+/**
+ * @brief   Interrupt channel for the SYS_UART_DN signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSUARTDN        ((expchannel_t)3)
+
+/**
+ * @brief   Interrupt channel for the IR_INT2 and CHARGE_STAT2A signals.
+ */
+#define MODULE_GPIO_EXTCHANNEL_IRINT2           ((expchannel_t)4)
+
+/**
+ * @brief   Interrupt channel for the TOUCH_INT signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_TOUCHINT         ((expchannel_t)5)
+
+/**
+ * @brief   Interrupt channel for the GAUGE_BATLOW2 signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_GAUGEBATLOW2     ((expchannel_t)6)
+
+/**
+ * @brief   Interrupt channel for the GAUGE_BATGD2 signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_GAUGEBATGD2      ((expchannel_t)7)
+
+/**
+ * @brief   Interrupt channel for the PATH_DC signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_PATHDC           ((expchannel_t)8)
+
+/**
+ * @brief   Interrupt channel for the SYS_SPI_DIR signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSSPIDIR        ((expchannel_t)9)
+
+/**
+ * @brief   Interrupt channel for the SYS_SYNC signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSSYNC          ((expchannel_t)12)
+
+/**
+ * @brief   Interrupt channel for the SYS_PD signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSPD            ((expchannel_t)13)
+
+/**
+ * @brief   Interrupt channel for the SYS_WARMRST signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSWARMRST       ((expchannel_t)14)
+
+/**
+ * @brief   Interrupt channel for the SYS_UART_UP signal.
+ */
+#define MODULE_GPIO_EXTCHANNEL_SYSUARTUP        ((expchannel_t)15)
+
+/**
+ * @brief   SYS_REG_EN output signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysRegEn;
+
+/**
+ * @brief   IR_INT1 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioIrInt1;
+
+/**
+ * @brief   POWER_EN output signal GPIO.
+ */
+extern apalGpio_t moduleGpioPowerEn;
+
+/**
+ * @brief   SYS_UART_DN bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysUartDn;
+
+/**
+ * @brief   CHARGE_STAT2A input signal GPIO.
+ */
+extern apalGpio_t moduleGpioChargeStat2A;
+
+/**
+ * @brief   GAUGE_BATLOW2 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioGaugeBatLow2;
+
+/**
+ * @brief   GAUGE_BATGD2 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioGaugeBatGd2;
+
+/**
+ * @brief   LED output signal GPIO.
+ */
+extern apalGpio_t moduleGpioLed;
+
+/**
+ * @brief   SYS_UART_UP bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysUartUp;
+
+/**
+ * @brief   CHARGE_STAT1A input signal GPIO.
+ */
+extern apalGpio_t moduleGpioChargeStat1A;
+
+/**
+ * @brief   GAUGE_BATLOW1 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioGaugeBatLow1;
+
+/**
+ * @brief   GAUGE_BATGD1 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioGaugeBatGd1;
+
+/**
+ * @brief   CHARG_EN1 output signal GPIO.
+ */
+extern apalGpio_t moduleGpioChargeEn1;
+
+/**
+ * @brief   IR_INT2 input signal GPIO.
+ */
+extern apalGpio_t moduleGpioIrInt2;
+
+/**
+ * @brief   TOUCH_INT input signal GPIO.
+ */
+extern apalGpio_t moduleGpioTouchInt;
+
+/**
+ * @brief   SYS_DONE input signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysDone;
+
+/**
+ * @brief   SYS_PROG output signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysProg;
+
+/**
+ * @brief   PATH_DC input signal GPIO.
+ */
+extern apalGpio_t moduleGpioPathDc;
+
+/**
+ * @brief   SYS_SPI_DIR bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysSpiDir;
+
+/**
+ * @brief   SYS_SYNC bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysSync;
+
+/**
+ * @brief   SYS_PD bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysPd;
+
+/**
+ * @brief   SYS_WARMRST bidirectional signal GPIO.
+ */
+extern apalGpio_t moduleGpioSysWarmrst;
+
+/**
+ * @brief   BT_RST output signal GPIO.
+ */
+extern apalGpio_t moduleGpioBtRst;
+
+/**
+ * @brief   CHARGE_EN2 output signal GPIO.
+ */
+extern apalGpio_t moduleGpioChargeEn2;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name AMiRo-OS core configurations
+ * @{
+ */
+/*===========================================================================*/
+
+/**
+ * @brief   Event flag to be set on a IR_INT1 / CHARGE_STAT1A interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_IRINT1           ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_IRINT1)
+
+/**
+ * @brief   Event flag to be set on a GAUGE_BATLOW1 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_GAUGEBATLOW1     ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_GAUGEBATLOW1)
+
+/**
+ * @brief   Event flag to be set on a GAUGE_BATGD1 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_GAUGEBATGD1      ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_GAUGEBATGD1)
+
+/**
+ * @brief   Event flag to be set on a SYS_UART_DN interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSUARTDN        ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_SYSUARTDN)
+
+/**
+ * @brief   Event flag to be set on a IR_INT2 / CHARGE_STAT2A interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_IRINT2           ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_IRINT2)
+
+/**
+ * @brief   Event flag to be set on a TOUCH_INT interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_TOUCHINT         ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_TOUCHINT)
+
+/**
+ * @brief   Event flag to be set on a GAUGE_BATLOW2 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_GAUGEBATLOW2     ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_GAUGEBATLOW2)
+
+/**
+ * @brief   Event flag to be set on a GAUGE_BATGD2 interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_GAUGEBATGD2      ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_GAUGEBATGD2)
+
+/**
+ * @brief   Event flag to be set on a PATH_DC interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_PATHDC           ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_PATHDC)
+
+/**
+ * @brief   Event flag to be set on a SYS_SPI_DIR interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSSPIDIR        ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_SYSSPIDIR)
+
+/**
+ * @brief   Event flag to be set on a SYS_SYNC interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSSYNC          ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_SYSSYNC)
+
+/**
+ * @brief   Event flag to be set on a SYS_PD interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSPD            ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_SYSPD)
+
+/**
+ * @brief   Event flag to be set on a SYS_WARMRST interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSWARMRST       ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_SYSWARMRST)
+
+/**
+ * @brief   Event flag to be set on a SYS_UART_UP interrupt.
+ */
+#define MODULE_OS_IOEVENTFLAGS_SYSUARTUP        ((eventflags_t)1 << MODULE_GPIO_EXTCHANNEL_SYSUARTUP)
+
+/**
+ * @brief   PD signal for SSSP.
+ */
+extern apalControlGpio_t moduleSsspPd;
+
+/**
+ * @brief   SYNC signal for SSSP.
+ */
+extern apalControlGpio_t moduleSsspSync;
+
+/**
+ * @brief   Shell prompt text.
+ */
+extern const char* moduleShellPrompt;
+
+/**
+ * @brief   Unit test initialization hook.
+ */
+#define MODULE_INIT_TESTS() {                                                 \
+  /* add unit-test shell commands */                                          \
+  aosShellAddCommand(aos.shell, &moduleUtAdcVsys.shellcmd);                   \
+  aosShellAddCommand(aos.shell, &moduleUtAlldAt24c01bn.shellcmd);             \
+  aosShellAddCommand(aos.shell, &moduleUtAlldBq24103a.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldBq27500.shellcmd);               \
+  aosShellAddCommand(aos.shell, &moduleUtAlldBq27500Bq24103a.shellcmd);       \
+  aosShellAddCommand(aos.shell, &moduleUtAlldIna219.shellcmd);                \
+  aosShellAddCommand(aos.shell, &moduleUtAlldMpr121.shellcmd);                \
+  aosShellAddCommand(aos.shell, &moduleUtAlldPca9544a.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldPklcs1212e4001.shellcmd);        \
+  aosShellAddCommand(aos.shell, &moduleUtAlldLed.shellcmd);                   \
+  aosShellAddCommand(aos.shell, &moduleUtAlldTps62113.shellcmd);              \
+  aosShellAddCommand(aos.shell, &moduleUtAlldTps62113Ina219.shellcmd);        \
+  aosShellAddCommand(aos.shell, &moduleUtAlldVcnl4020.shellcmd);              \
+}
+
+/**
+ * @brief   Periphery communication interfaces initialization hook.
+ */
+#define MODULE_INIT_PERIPHERY_COMM() {                                        \
+  /* serial driver */                                                         \
+  sdStart(&MODULE_HAL_PROGIF, &moduleHalProgIfConfig);                        \
+  /* I2C */                                                                   \
+  moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed = (PCA9544A_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed) ? PCA9544A_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed;  \
+  moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed = (VCNL4020_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed) ? VCNL4020_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed;  \
+  moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed = (INA219_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed) ? INA219_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed;  \
+  moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed = (BQ27500_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed) ? BQ27500_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed;  \
+  moduleHalI2cProxPm18Pm33GaugeRearConfig.duty_cycle = (moduleHalI2cProxPm18Pm33GaugeRearConfig.clock_speed <= 100000) ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2;  \
+  i2cStart(&MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR, &moduleHalI2cProxPm18Pm33GaugeRearConfig); \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed = (PCA9544A_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed) ? PCA9544A_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed; \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed = (VCNL4020_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed) ? VCNL4020_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed; \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed = (INA219_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed) ? INA219_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed; \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed = (AT24C01BN_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed) ? AT24C01BN_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed; \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed = (MPR121_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed) ? MPR121_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed; \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed = (BQ27500_LLD_I2C_MAXFREQUENCY < moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed) ? BQ27500_LLD_I2C_MAXFREQUENCY : moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed; \
+  moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.duty_cycle = (moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig.clock_speed <= 100000) ? STD_DUTY_CYCLE : FAST_DUTY_CYCLE_2;  \
+  i2cStart(&MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT, &moduleHalI2cProxPm42Pm50PmVddEepromTouchGaugeFrontConfig);  \
+  /* ADC */                                                                   \
+  adcStart(&MODULE_HAL_ADC_VSYS, NULL);                                       \
+  /* PWM */                                                                   \
+  pwmStart(&MODULE_HAL_PWM_BUZZER, &moduleHalPwmBuzzerConfig);                \
+  moduleHalPwmBuzzerConfig.frequency = MODULE_HAL_PWM_BUZZER.clock;           \
+  pwmStop(&MODULE_HAL_PWM_BUZZER);                                            \
+  moduleHalPwmBuzzerConfig.period = moduleHalPwmBuzzerConfig.frequency / PKLCS1212E4001_LLD_FREQUENCY_SPEC; \
+  pwmStart(&MODULE_HAL_PWM_BUZZER, &moduleHalPwmBuzzerConfig);                \
+}
+
+/**
+ * @brief   Hook to handle IO events during SSSP startup synchronization.
+ */
+#define MODULE_SSP_STARTUP_OUTRO_IO_EVENT(mask, flags) {                      \
+  /* ignore all events */                                                     \
+  (void)mask;                                                                 \
+  (void)flags;                                                                \
+}
+
+/**
+ * @brief   Periphery communication interface deinitialization hook.
+ */
+#define MODULE_SHUTDOWN_PERIPHERY_COMM() {                                    \
+  /* PWM */                                                                   \
+  pwmStop(&MODULE_HAL_PWM_BUZZER);                                            \
+  /* ADC */                                                                   \
+  adcStop(&MODULE_HAL_ADC_VSYS);                                              \
+  /* I2C */                                                                   \
+  i2cStop(&MODULE_HAL_I2C_PROX_PM18_PM33_GAUGEREAR);                          \
+  i2cStop(&MODULE_HAL_I2C_PROX_PM42_PM50_PMVDD_EEPROM_TOUCH_GAUGEFRONT);      \
+  /* don't stop the serial driver so messages can still be printed */         \
+}
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Low-level drivers
+ * @{
+ */
+/*===========================================================================*/
+#include <alld_at24c01bn-sh-b.h>
+#include <alld_bq24103a.h>
+#include <alld_bq27500.h>
+#include <alld_ina219.h>
+#include <alld_led.h>
+#include <alld_mpr121.h>
+#include <alld_pca9544a.h>
+#include <alld_pklcs1212e4001.h>
+#include <alld_tps62113.h>
+#include <alld_vcnl4020.h>
+
+/**
+ * @brief   EEPROM driver.
+ */
+extern AT24C01BNDriver moduleLldEeprom;
+
+/**
+ * @brief   Battery charger (front battery) driver.
+ */
+extern BQ24103ADriver moduleLldBatteryChargerFront;
+
+/**
+ * @brief   Battery charger (rear battery) driver.
+ */
+extern BQ24103ADriver moduleLldBatteryChargerRear;
+
+/**
+ * @brief   Fuel gauge (front battery) driver.
+ */
+extern BQ27500Driver moduleLldFuelGaugeFront;
+
+/**
+ * @brief   Fuel gauge (rear battery) driver.
+ */
+extern BQ27500Driver moduleLldFuelGaugeRear;
+
+/**
+ * @brief   Power monitor (VDD) driver.
+ */
+extern INA219Driver moduleLldPowerMonitorVdd;
+
+/**
+ * @brief   Power monitor (VIO 1.8) driver.
+ */
+extern INA219Driver moduleLldPowerMonitorVio18;
+
+/**
+ * @brief   Power monitor (VIO 3.3) driver.
+ */
+extern INA219Driver moduleLldPowerMonitorVio33;
+
+/**
+ * @brief   Power monitor (VSYS 4.2) driver.
+ */
+extern INA219Driver moduleLldPowerMonitorVsys42;
+
+/**
+ * @brief   Power monitor (VIO 5.0) driver.
+ */
+extern INA219Driver moduleLldPowerMonitorVio50;
+
+/**
+ * @brief   Status LED driver.
+ */
+extern LEDDriver moduleLldStatusLed;
+
+/**
+ * @brief   Touch sensor driver.
+ */
+extern MPR121Driver moduleLldTouch;
+
+/**
+ * @brief   I2C multiplexer (I2C 1) driver.
+ */
+extern PCA9544ADriver moduleLldI2cMultiplexer1;
+
+/**
+ * @brief   I2C multiplexer (I2C 2) driver.
+ */
+extern PCA9544ADriver moduleLldI2cMultiplexer2;
+
+/**
+ * @brief   Step down converter driver.
+ * @note    Although there multiple TPS62113, those are completely identical from driver few (share the same signals).
+ */
+extern TPS62113Driver moduleLldStepDownConverter;
+
+/**
+ * @brief   Proximity sensor (I2C 1) driver.
+ */
+extern VCNL4020Driver moduleLldProximity1;
+
+/**
+ * @brief   Proximity sensor (I2C 2) driver.
+ */
+extern VCNL4020Driver moduleLldProximity2;
+
+/** @} */
+
+/*===========================================================================*/
+/**
+ * @name Unit tests (UT)
+ * @{
+ */
+/*===========================================================================*/
+#if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
+#include <ut_lld_adc.h>
+#include <ut_alld_at24c01bn-sh-b.h>
+#include <ut_alld_bq24103a.h>
+#include <ut_alld_bq27500.h>
+#include <ut_alld_bq27500_bq24103a.h>
+#include <ut_alld_ina219.h>
+#include <ut_alld_led.h>
+#include <ut_alld_mpr121.h>
+#include <ut_alld_pca9544a.h>
+#include <ut_alld_pklcs1212e4001.h>
+#include <ut_alld_tps62113.h>
+#include <ut_alld_tps62113_ina219.h>
+#include <ut_alld_vcnl4020.h>
+
+/**
+ * @brief   ADC unit test object.
+ */
+extern aos_unittest_t moduleUtAdcVsys;
+
+/**
+ * @brief   AT24C01BN-SH-B (EEPROM) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldAt24c01bn;
+
+/**
+ * @brief   BQ24103A (battery charger) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldBq24103a;
+
+/**
+ * @brief   BQ27500 (fuel gauge) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldBq27500;
+
+/**
+ * @brief   BQ27500 (fuela gauge) in combination with BQ24103A (battery charger) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldBq27500Bq24103a;
+
+/**
+ * @brief   INA219 (power monitor) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldIna219;
+
+/**
+ * @brief   Status LED unit test object.
+ */
+extern aos_unittest_t moduleUtAlldLed;
+
+/**
+ * @brief   MPR121 (touch sensor) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldMpr121;
+
+/**
+ * @brief   PCA9544A (I2C multiplexer) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldPca9544a;
+
+/**
+ * @brief   PKLCS1212E4001 (buzzer) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldPklcs1212e4001;
+
+/**
+ * @brief   TPS62113 (step-down converter) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldTps62113;
+
+/**
+ * @brief   TPS62113 (step-sown converter) in combination with INA219 (power monitor) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldTps62113Ina219;
+
+/**
+ * @brief   VCNL4020 (proximity sensor) unit test object.
+ */
+extern aos_unittest_t moduleUtAlldVcnl4020;
+
+#endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+
+/** @} */
+
+#endif /* _AMIROOS_MODULE_H_ */
diff --git a/os/modules/flash.mk b/os/modules/flash.mk
new file mode 100644
index 0000000..b26ecd7
--- /dev/null
+++ b/os/modules/flash.mk
@@ -0,0 +1,57 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+
+
+# the path to this makefile
+FLASH_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+include $(FLASH_DIR)../../bootloader/bootloader.mk
+
+#FLASH_MODULES = $(PROJECT)
+#FLASH_FILE = build/$(FLASH_MODULES).$(FLASHTOOL_EXT)
+
+# supported modules and according IDs
+#MODULES := DiWheelDrive_1-1 PowerManagement_1-1 LightRing_1-0
+#DiWheelDrive_1-1 := $(shell printf "%u" 0x01000101)
+#PowerManagement_1-1 := $(shell printf "%u" 0x01010101)
+#LightRing_1-0 := $(shell printf "%u" 0x017F0100)
+
+# the files to flash
+ifdef PROJECT
+  FLASH_MODULES = $(PROJECT)
+  FLASH_FILES = build/$(PROJECT).$(FLASHTOOL_EXT)
+else
+  FLASH_MODULES = $(MODULES)
+  FLASH_FILES = $(foreach module,$(MODULES),$(module)/build/$(module).$(FLASHTOOL_EXT))
+endif
+
+flash: $(FLASH_FILES)
+	$(info )
+ifeq ($(FLASHTOOL),SerialBoot)
+	$(info Flashing ($(FLASHTOOL)):)
+	$(FLASHTOOL_CMD) $(FLASHTOOL_ARGS)
+else
+	$(info ERROR: unable to flash the module (SerialBoot unavailable))
+endif
+
diff --git a/os/modules/modules.mk b/os/modules/modules.mk
new file mode 100644
index 0000000..34cbe48
--- /dev/null
+++ b/os/modules/modules.mk
@@ -0,0 +1,37 @@
+################################################################################
+# 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
+MODULES_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+# list of available modules
+MODULES = $(patsubst $(MODULES_DIR)/%/,%,$(sort $(dir $(wildcard $(MODULES_DIR)/*/*))))
+
+# include paths
+MODULESINC = $(MODULES_DIR)
+
+# C source files
+MODULESCSRC = $(MODULES_DIR)
+
diff --git a/os/unittests/lld/inc/ut_lld_adc.h b/os/unittests/lld/inc/ut_lld_adc.h
new file mode 100644
index 0000000..b3cae14
--- /dev/null
+++ b/os/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/os/unittests/lld/src/ut_lld_adc.c b/os/unittests/lld/src/ut_lld_adc.c
new file mode 100644
index 0000000..0d859ca
--- /dev/null
+++ b/os/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, LL_S2ST(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, LL_S2ST(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
new file mode 100644
index 0000000..3eaef77
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h b/os/unittests/periphery-lld/inc/ut_alld_at24c01bn-sh-b.h
new file mode 100644
index 0000000..1ed579e
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_bq24103a.h b/os/unittests/periphery-lld/inc/ut_alld_bq24103a.h
new file mode 100644
index 0000000..889ce22
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_bq27500.h b/os/unittests/periphery-lld/inc/ut_alld_bq27500.h
new file mode 100644
index 0000000..9818639
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h b/os/unittests/periphery-lld/inc/ut_alld_bq27500_bq24103a.h
new file mode 100644
index 0000000..58836ce
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_hmc5883l.h b/os/unittests/periphery-lld/inc/ut_alld_hmc5883l.h
new file mode 100644
index 0000000..e478c2f
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_ina219.h b/os/unittests/periphery-lld/inc/ut_alld_ina219.h
new file mode 100644
index 0000000..c386e5f
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_l3g4200d.h b/os/unittests/periphery-lld/inc/ut_alld_l3g4200d.h
new file mode 100644
index 0000000..ff55790
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_led.h b/os/unittests/periphery-lld/inc/ut_alld_led.h
new file mode 100644
index 0000000..d8a3e21
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_lis331dlh.h b/os/unittests/periphery-lld/inc/ut_alld_lis331dlh.h
new file mode 100644
index 0000000..41152f4
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_ltc4412.h b/os/unittests/periphery-lld/inc/ut_alld_ltc4412.h
new file mode 100644
index 0000000..9a68766
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_mpr121.h b/os/unittests/periphery-lld/inc/ut_alld_mpr121.h
new file mode 100644
index 0000000..019d521
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_pca9544a.h b/os/unittests/periphery-lld/inc/ut_alld_pca9544a.h
new file mode 100644
index 0000000..08e153c
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h b/os/unittests/periphery-lld/inc/ut_alld_pklcs1212e4001.h
new file mode 100644
index 0000000..9fc35c9
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_tlc5947.h b/os/unittests/periphery-lld/inc/ut_alld_tlc5947.h
new file mode 100644
index 0000000..5c31bdc
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h b/os/unittests/periphery-lld/inc/ut_alld_tps2051bdbv.h
new file mode 100644
index 0000000..10e1e38
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_tps62113.h b/os/unittests/periphery-lld/inc/ut_alld_tps62113.h
new file mode 100644
index 0000000..9915ea4
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h b/os/unittests/periphery-lld/inc/ut_alld_tps62113_ina219.h
new file mode 100644
index 0000000..034fd82
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/inc/ut_alld_vcnl4020.h b/os/unittests/periphery-lld/inc/ut_alld_vcnl4020.h
new file mode 100644
index 0000000..4c0c37f
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_a3906.c b/os/unittests/periphery-lld/src/ut_alld_a3906.c
new file mode 100644
index 0000000..f4bbe3f
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c b/os/unittests/periphery-lld/src/ut_alld_at24c01bn-sh-b.c
new file mode 100644
index 0000000..a841ba0
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_bq24103a.c b/os/unittests/periphery-lld/src/ut_alld_bq24103a.c
new file mode 100644
index 0000000..42a5ba0
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_bq27500.c b/os/unittests/periphery-lld/src/ut_alld_bq27500.c
new file mode 100644
index 0000000..6fad31f
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c b/os/unittests/periphery-lld/src/ut_alld_bq27500_bq24103a.c
new file mode 100644
index 0000000..f5dbfde
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_hmc5883l.c b/os/unittests/periphery-lld/src/ut_alld_hmc5883l.c
new file mode 100644
index 0000000..df013ea
--- /dev/null
+++ b/os/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), LL_US2ST(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), US2ST(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
new file mode 100644
index 0000000..06d0470
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_l3g4200d.c b/os/unittests/periphery-lld/src/ut_alld_l3g4200d.c
new file mode 100644
index 0000000..bbca210
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_led.c b/os/unittests/periphery-lld/src/ut_alld_led.c
new file mode 100644
index 0000000..53ac634
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_lis331dlh.c b/os/unittests/periphery-lld/src/ut_alld_lis331dlh.c
new file mode 100644
index 0000000..e10e06b
--- /dev/null
+++ b/os/unittests/periphery-lld/src/ut_alld_lis331dlh.c
@@ -0,0 +1,235 @@
+/*
+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);
+  }
+  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
new file mode 100644
index 0000000..40ee37f
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_mpr121.c b/os/unittests/periphery-lld/src/ut_alld_mpr121.c
new file mode 100644
index 0000000..e7baa3e
--- /dev/null
+++ b/os/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), LL_US2ST(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
new file mode 100644
index 0000000..827f557
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c b/os/unittests/periphery-lld/src/ut_alld_pklcs1212e4001.c
new file mode 100644
index 0000000..33d2a6a
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_tlc5947.c b/os/unittests/periphery-lld/src/ut_alld_tlc5947.c
new file mode 100644
index 0000000..deb93a3
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c b/os/unittests/periphery-lld/src/ut_alld_tps2051bdbv.c
new file mode 100644
index 0000000..ca74611
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_tps62113.c b/os/unittests/periphery-lld/src/ut_alld_tps62113.c
new file mode 100644
index 0000000..403579e
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c b/os/unittests/periphery-lld/src/ut_alld_tps62113_ina219.c
new file mode 100644
index 0000000..7ce0035
--- /dev/null
+++ b/os/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/os/unittests/periphery-lld/src/ut_alld_vcnl4020.c b/os/unittests/periphery-lld/src/ut_alld_vcnl4020.c
new file mode 100644
index 0000000..a5fa4f7
--- /dev/null
+++ b/os/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), LL_US2ST(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
new file mode 100644
index 0000000..dc28c50
--- /dev/null
+++ b/os/unittests/unittests.mk
@@ -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/>.        #
+#                                                                              #
+# 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 $(abspath $(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
+
diff --git a/patches/0001-ARM-fix-rounding-issue-with-WORKING_AREA-stack-size.patch b/patches/0001-ARM-fix-rounding-issue-with-WORKING_AREA-stack-size.patch
deleted file mode 100644
index 65b8518..0000000
--- a/patches/0001-ARM-fix-rounding-issue-with-WORKING_AREA-stack-size.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 8dc86a6495b16e656d5fff4d55b4b6f78e3b3c82 Mon Sep 17 00:00:00 2001
-From: Robert ABEL <rabel@cit-ec.uni-bielefeld.de>
-Date: Fri, 4 Jul 2014 16:51:30 +0200
-Subject: [PATCH] ARM: fix rounding issue with WORKING_AREA stack size
-
-Signed-off-by: Robert ABEL <rabel@cit-ec.uni-bielefeld.de>
----
- os/ports/GCC/ARMCMx/chcore_v6m.h | 2 +-
- os/ports/GCC/ARMCMx/chcore_v7m.h | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.h b/os/ports/GCC/ARMCMx/chcore_v6m.h
-index be1381e..2937be9 100644
---- a/os/ports/GCC/ARMCMx/chcore_v6m.h
-+++ b/os/ports/GCC/ARMCMx/chcore_v6m.h
-@@ -238,7 +238,7 @@ struct context {
-  * @details This macro is used to allocate a static thread working area
-  *          aligned as both position and size.
-  */
--#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)]
-+#define WORKING_AREA(s, n) stkalign_t s[(THD_WA_SIZE(n) + sizeof(stkalign_t) - 1) / sizeof(stkalign_t)]
- 
- /**
-  * @brief   IRQ prologue code.
-diff --git a/os/ports/GCC/ARMCMx/chcore_v7m.h b/os/ports/GCC/ARMCMx/chcore_v7m.h
-index 3706a92..5cb8867 100644
---- a/os/ports/GCC/ARMCMx/chcore_v7m.h
-+++ b/os/ports/GCC/ARMCMx/chcore_v7m.h
-@@ -338,7 +338,7 @@ struct context {
-  * @details This macro is used to allocate a static thread working area
-  *          aligned as both position and size.
-  */
--#define WORKING_AREA(s, n) stkalign_t s[THD_WA_SIZE(n) / sizeof(stkalign_t)]
-+#define WORKING_AREA(s, n) stkalign_t s[(THD_WA_SIZE(n) + sizeof(stkalign_t) - 1) / sizeof(stkalign_t)]
- 
- /**
-  * @brief   IRQ prologue code.
--- 
-1.8.4.msysgit.0
-
diff --git a/patches/0006-STM32F4xx-ADC-add-AWD-support.patch b/patches/0006-STM32F4xx-ADC-add-AWD-support.patch
deleted file mode 100644
index a05480d..0000000
--- a/patches/0006-STM32F4xx-ADC-add-AWD-support.patch
+++ /dev/null
@@ -1,101 +0,0 @@
-From: Thomas SCHÖPPING <tschoepp@techfak.uni-bielefeld.de>
-Date: Wed, 3 Mar 2015 15:43:17 +0200
-Subject: [PATCH] STM32F4xx: added support for the ADC analog watchdog
-
-Signed-off-by: Thomas SCHÖPPING <tschoepp@techfak.uni-bielefeld.de>
----
-diff --git a/os/hal/platforms/STM32F4xx/adc_lld.c b/os/hal/platforms/STM32F4xx/adc_lld.c
-index e5de44a..5495649 100644
---- a/os/hal/platforms/STM32F4xx/adc_lld.c
-+++ b/os/hal/platforms/STM32F4xx/adc_lld.c
-@@ -124,7 +124,10 @@ CH_IRQ_HANDLER(ADC1_2_3_IRQHandler) {
-     if (ADCD1.grpp != NULL)
-       _adc_isr_error_code(&ADCD1, ADC_ERR_OVERFLOW);
-   }
--  /* TODO: Add here analog watchdog handling.*/
-+  if (sr & ADC_SR_AWD) {
-+    if (ADCD1.grpp != NULL)
-+      _adc_isr_error_code(&ADCD1, ADC_ERR_WATCHDOG);
-+  }
- #endif /* STM32_ADC_USE_ADC1 */
- 
- #if STM32_ADC_USE_ADC2
-@@ -138,7 +141,10 @@ CH_IRQ_HANDLER(ADC1_2_3_IRQHandler) {
-     if (ADCD2.grpp != NULL)
-       _adc_isr_error_code(&ADCD2, ADC_ERR_OVERFLOW);
-   }
--  /* TODO: Add here analog watchdog handling.*/
-+  if (sr & ADC_SR_AWD) {
-+    if (ADCD1.grpp != NULL)
-+      _adc_isr_error_code(&ADCD2, ADC_ERR_WATCHDOG);
-+  }
- #endif /* STM32_ADC_USE_ADC2 */
- 
- #if STM32_ADC_USE_ADC3
-@@ -152,7 +158,10 @@ CH_IRQ_HANDLER(ADC1_2_3_IRQHandler) {
-     if (ADCD3.grpp != NULL)
-       _adc_isr_error_code(&ADCD3, ADC_ERR_OVERFLOW);
-   }
--  /* TODO: Add here analog watchdog handling.*/
-+  if (sr & ADC_SR_AWD) {
-+    if (ADCD1.grpp != NULL)
-+      _adc_isr_error_code(&ADCD3, ADC_ERR_WATCHDOG);
-+  }
- #endif /* STM32_ADC_USE_ADC3 */
- 
-   CH_IRQ_EPILOGUE();
-@@ -340,6 +349,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
-   adcp->adc->SR    = 0;
-   adcp->adc->SMPR1 = grpp->smpr1;
-   adcp->adc->SMPR2 = grpp->smpr2;
-+  adcp->adc->HTR   = grpp->htr;
-+  adcp->adc->LTR   = grpp->ltr;
-   adcp->adc->SQR1  = grpp->sqr1;
-   adcp->adc->SQR2  = grpp->sqr2;
-   adcp->adc->SQR3  = grpp->sqr3;
-diff --git a/os/hal/platforms/STM32F4xx/adc_lld.h b/os/hal/platforms/STM32F4xx/adc_lld.h
-index 7cda791..be81ed3 100644
---- a/os/hal/platforms/STM32F4xx/adc_lld.h
-+++ b/os/hal/platforms/STM32F4xx/adc_lld.h
-@@ -306,7 +306,8 @@ typedef uint16_t adc_channels_num_t;
-  */
- typedef enum {
-   ADC_ERR_DMAFAILURE = 0,                   /**< DMA operations failure.    */
--  ADC_ERR_OVERFLOW = 1                      /**< ADC overflow condition.    */
-+  ADC_ERR_OVERFLOW = 1,                     /**< ADC overflow condition.    */
-+  ADC_ERR_WATCHDOG = 2                      /**< ADC watchdog condition.    */
- } adcerror_t;
- 
- /**
-@@ -385,6 +386,16 @@ typedef struct {
-    */
-   uint32_t                  smpr2;
-   /**
-+   * @brief   ADC watchdog higher threshold register.
-+   * @details This filed defines the higher threshold for the analog watchdog.
-+   */
-+  uint16_t                  htr;
-+  /**
-+   * @brief   ADC watchdog lower threshold register.
-+   * @details This filed defines the lower threshold for the analog watchdog.
-+   */
-+  uint16_t                  ltr;
-+  /**
-    * @brief   ADC SQR1 register initialization data.
-    * @details Conversion group sequence 13...16 + sequence length.
-    */
-@@ -528,6 +539,14 @@ struct ADCDriver {
- #define ADC_SMPR1_SMP_VBAT(n)   ((n) << 24) /**< @brief VBAT sampling time. */
- /** @} */
- 
-+/**
-+ * @name    Threshold settings helper macros
-+ * @{
-+ */
-+#define ADC_HTR(n)              ((n > ADC_HTR_HT) ? ADC_HTR_HT : n) /**< @brief higher threshold limitation */
-+#define ADC_LTR(n)              ((n > ADC_LTR_LT) ? ADC_LTR_LT : n) /**< @brief lower threshold limitation  */
-+/** @} */
-+
- /*===========================================================================*/
- /* External declarations.                                                    */
- /*===========================================================================*/
diff --git a/patches/0007-SMT32-add-optional-I2C-non-DMA-driver-option.patch b/patches/0007-SMT32-add-optional-I2C-non-DMA-driver-option.patch
deleted file mode 100644
index f720c1b..0000000
--- a/patches/0007-SMT32-add-optional-I2C-non-DMA-driver-option.patch
+++ /dev/null
@@ -1,507 +0,0 @@
-From: Thomas SCHÖPPING <tschoepp@techfak.uni-bielefeld.de>
-Date: Wed, 29 Apr 2015 18:15:23 +0200
-Subject: [PATCH] STM32/I2Cv1: added the option to use I2C without DMA
-
-Signed-off-by: Thomas SCHÖPPING <tschoepp@techfak.uni-bielefeld.de>
----
-diff --git a/os/hal/platforms/STM32/I2Cv1/i2c_lld.c b/os/hal/platforms/STM32/I2Cv1/i2c_lld.c
-index 2a36776..4a27942 100644
---- a/os/hal/platforms/STM32/I2Cv1/i2c_lld.c
-+++ b/os/hal/platforms/STM32/I2Cv1/i2c_lld.c
-@@ -35,6 +35,7 @@
- /* Driver local definitions.                                                 */
- /*===========================================================================*/
- 
-+#if STM32_I2C_USE_DMA
- #define I2C1_RX_DMA_CHANNEL                                                 \
-   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM,                        \
-                        STM32_I2C1_RX_DMA_CHN)
-@@ -58,6 +59,7 @@
- #define I2C3_TX_DMA_CHANNEL                                                 \
-   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM,                        \
-                        STM32_I2C3_TX_DMA_CHN)
-+#endif /* STM32_I2C_USE_DMA */
- 
- /*===========================================================================*/
- /* Driver constants.                                                         */
-@@ -73,6 +75,20 @@
- #define I2C_EV6_MASTER_REC_MODE_SELECTED                                    \
-   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
- 
-+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED                                    \
-+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_RXNE))
-+
-+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP                               \
-+  ((uint32_t)(                                      I2C_SR1_RXNE))
-+
-+#define I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED                              \
-+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) |                         \
-+              I2C_SR1_BTF | I2C_SR1_RXNE))
-+
-+#define I2C_EV8_MASTER_BYTE_TRANSMITTING                                    \
-+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA)<< 16) |           \
-+              I2C_SR1_TXE))
-+
- #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED                                   \
-   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) |          \
-               I2C_SR1_BTF | I2C_SR1_TXE))
-@@ -148,9 +164,11 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
-   dp->CR2 = 0;
-   dp->SR1 = 0;
- 
-+#if STM32_I2C_USE_DMA
-   /* Stops the associated DMA streams.*/
-   dmaStreamDisable(i2cp->dmatx);
-   dmaStreamDisable(i2cp->dmarx);
-+#endif /* STM32_I2C_USE_DMA */
- }
- 
- /**
-@@ -242,7 +260,7 @@ static void i2c_lld_set_clock(I2CDriver *i2cp) {
- 
-     chDbgAssert(clock_div >= 0x01,
-                     "i2c_lld_set_clock(), #7",
--                    "Clock divider less then 0x04 not allowed");
-+                    "Clock divider less then 0x01 not allowed");
-     regCCR |= (I2C_CCR_FS | (clock_div & I2C_CCR_CCR));
- 
-     /* Sets the Maximum Rise Time for fast mode.*/
-@@ -295,12 +313,13 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
-   uint32_t regSR2 = dp->SR2;
-   uint32_t event = dp->SR1;
- 
-+#if STM32_I2C_USE_DMA
-   /* Interrupts are disabled just before dmaStreamEnable() because there
-      is no need of interrupts until next transaction begin. All the work is
-      done by the DMA.*/
-   switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
-   case I2C_EV5_MASTER_MODE_SELECT:
--    if ((i2cp->addr >> 8) > 0) { 
-+    if ((i2cp->addr >> 8) > 0) {
-       /* 10-bit address: 1 1 1 1 0 X X R/W */
-       dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
-     } else {
-@@ -340,8 +359,129 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
-   /* Clear ADDR flag. */
-   if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
-     (void)dp->SR2;
-+#else
-+  switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
-+  case I2C_EV5_MASTER_MODE_SELECT:
-+    dp->CR2 |= I2C_CR2_ITBUFEN;
-+    dp->DR = i2cp->addr;
-+    break;
-+  case I2C_EV6_MASTER_TRA_MODE_SELECTED:
-+    (void)dp->SR2; // clear ADDR flag
-+    /* EV8_1 */
-+    dp->DR = *(i2cp->txbuf);
-+
-+    ++i2cp->txbuf;
-+    --i2cp->txbytes;
-+
-+    /* if N == 1, skip the I2C_EV8_MASTER_BYTE_TRANSMITTING event
-+     * but enter I2C_EV8_2_MASTER_BYTE_TRANSMITTED next */
-+    if (i2cp->txbytes == 0) {
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+    }
-+    break;
-+  case I2C_EV6_MASTER_REC_MODE_SELECTED:
-+    switch (i2cp->rxbytes) {
-+    case 1:
-+      dp->CR1 &= ~I2C_CR1_ACK;
-+      (void)dp->SR2; // clear ADDR flag
-+      dp->CR1 |= I2C_CR1_STOP;
-+      break;
-+    case 2:
-+      (void)dp->SR2; // clear ADDR flag
-+      /* EV6_1 */
-+      dp->CR1 |= I2C_CR1_POS;
-+      dp->CR1 &= ~I2C_CR1_ACK;
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+      break;
-+    case 3: /* N == 3 is a very special case, since EV7 is completely skipped */
-+      (void)dp->SR2; // clear ADDR flag
-+      /* Disable the I2C_EV7_MASTER_REC_BYTE_RECEIVED event
-+       * but enter I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP next */
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+      break;
-+    default: /* N > 2 */
-+      (void)dp->SR2; // clear ADDR flag
-+      break;
-+    }
-+    break;
-+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
-+    if (i2cp->rxbytes > 3) {
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      --i2cp->rxbytes;
-+    }
-+    if (i2cp->rxbytes == 3) {
-+      /* Disable this event for DataN-2, but force into event
-+       * I2C_EV7_2_EV7_3_MASTER_REC_BYTE_RECEIVED_QUEUED by not reading dp->DR. */
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+    }
-+    break;
-+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP:
-+    chDbgAssert(i2cp->rxbytes == 1, "i2c_lld_serve_event_interrupt(), #1",
-+               "more than 1 byte to be received");
-+    *(i2cp->rxbuf) = dp->DR;
-+    --i2cp->rxbytes;
-+    dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
-+    wakeup_isr(i2cp, RDY_OK);
-+    break;
-+  case I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED:
-+    if (i2cp->rxbytes == 3) {
-+      /* EV7_2 (N > 2) */
-+      dp->CR1 &= ~I2C_CR1_ACK;
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      dp->CR1 |= I2C_CR1_STOP;
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      i2cp->rxbytes -= 2;
-+      /* enable I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP event */
-+      dp->CR2 |= I2C_CR2_ITBUFEN;
-+    } else {
-+      /* EV7_3 (N == 2) */
-+      dp->CR1 |= I2C_CR1_STOP;
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      *(i2cp->rxbuf) = dp->DR;
-+      i2cp->rxbytes -= 2;
-+
-+      dp->CR1 &= ~I2C_CR1_POS;
-+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
-+
-+      wakeup_isr(i2cp, RDY_OK);
-+    }
-+    break;
-+  case I2C_EV8_MASTER_BYTE_TRANSMITTING:
-+    dp->DR = *(i2cp->txbuf);
-+    ++i2cp->txbuf;
-+    --i2cp->txbytes;
-+
-+    /* if this was the last byte, ensure that this event is not entered again */
-+    if (i2cp->txbytes == 0) {
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+    }
-+    break;
-+  case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
-+    if (i2cp->rxbytes > 0) {
-+      /* start "read after write" operation (LSB of address = 1 -> read) */
-+      i2cp-> addr |= 0x01;
-+      dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
-+    } else {
-+      dp->CR1 |= I2C_CR1_STOP;
-+
-+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
-+
-+      wakeup_isr(i2cp, RDY_OK);
-+    }
-+    break;
-+  default:
-+    chDbgAssert(i2cp->rxbytes != 1, "i2c_lld_serve_event_interrupt(), #1",
-+               "more than 1 byte to be received");
-+    break;
-+  }
-+#endif /* STM32_I2C_USE_DMA */
- }
- 
-+#if STM32_I2C_USE_DMA
- /**
-  * @brief   DMA RX end IRQ handler.
-  *
-@@ -395,6 +535,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
-      of R/W transaction itself.*/
-   dp->CR2 |= I2C_CR2_ITEVTEN;
- }
-+#endif /* STM32_I2C_USE_DMA */
- 
- /**
-  * @brief   I2C error handler.
-@@ -406,9 +547,11 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
-  */
- static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
- 
-+#if STM32_I2C_USE_DMA
-   /* Clears interrupt flags just to be safe.*/
-   dmaStreamDisable(i2cp->dmatx);
-   dmaStreamDisable(i2cp->dmarx);
-+#endif /* STM32_I2C_USE_DMA */
- 
-   i2cp->errors = I2CD_NO_ERROR;
- 
-@@ -554,24 +697,30 @@ void i2c_lld_init(void) {
-   i2cObjectInit(&I2CD1);
-   I2CD1.thread = NULL;
-   I2CD1.i2c    = I2C1;
-+#if STM32_I2C_USE_DMA
-   I2CD1.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM);
-   I2CD1.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM);
-+#endif /* STM32_I2C_USE_DMA */
- #endif /* STM32_I2C_USE_I2C1 */
- 
- #if STM32_I2C_USE_I2C2
-   i2cObjectInit(&I2CD2);
-   I2CD2.thread = NULL;
-   I2CD2.i2c    = I2C2;
-+#if STM32_I2C_USE_DMA
-   I2CD2.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM);
-   I2CD2.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM);
-+#endif /* STM32_I2C_USE_DMA */
- #endif /* STM32_I2C_USE_I2C2 */
- 
- #if STM32_I2C_USE_I2C3
-   i2cObjectInit(&I2CD3);
-   I2CD3.thread = NULL;
-   I2CD3.i2c    = I2C3;
-+#if STM32_I2C_USE_DMA
-   I2CD3.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM);
-   I2CD3.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM);
-+#endif /* STM32_I2C_USE_DMA */
- #endif /* STM32_I2C_USE_I2C3 */
- }
- 
-@@ -585,6 +734,7 @@ void i2c_lld_init(void) {
- void i2c_lld_start(I2CDriver *i2cp) {
-   I2C_TypeDef *dp = i2cp->i2c;
- 
-+#if STM32_I2C_USE_DMA
-   i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
-                     STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
-                     STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
-@@ -593,15 +743,17 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                     STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
-                     STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
-                     STM32_DMA_CR_DIR_P2M;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* If in stopped state then enables the I2C and DMA clocks.*/
-   if (i2cp->state == I2C_STOP) {
- 
- #if STM32_I2C_USE_I2C1
-     if (&I2CD1 == i2cp) {
--      bool_t b;
- 
-       rccResetI2C1();
-+#if STM32_I2C_USE_DMA
-+      bool_t b;
-       b = dmaStreamAllocate(i2cp->dmarx,
-                             STM32_I2C_I2C1_IRQ_PRIORITY,
-                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
-@@ -612,24 +764,28 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
-                             (void *)i2cp);
-       chDbgAssert(!b, "i2c_lld_start(), #2", "stream already allocated");
-+#endif /* STM32_I2C_USE_DMA */
-       rccEnableI2C1(FALSE);
-       nvicEnableVector(I2C1_EV_IRQn,
-           CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
-       nvicEnableVector(I2C1_ER_IRQn,
-           CORTEX_PRIORITY_MASK(STM32_I2C_I2C1_IRQ_PRIORITY));
- 
-+#if STM32_I2C_USE_DMA
-       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
-       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
-+#endif /* STM32_I2C_USE_DMA */
-     }
- #endif /* STM32_I2C_USE_I2C1 */
- 
- #if STM32_I2C_USE_I2C2
-     if (&I2CD2 == i2cp) {
--      bool_t b;
- 
-       rccResetI2C2();
-+#if STM32_I2C_USE_DMA
-+      bool_t b;
-       b = dmaStreamAllocate(i2cp->dmarx,
-                             STM32_I2C_I2C2_IRQ_PRIORITY,
-                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
-@@ -640,24 +796,28 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
-                             (void *)i2cp);
-       chDbgAssert(!b, "i2c_lld_start(), #4", "stream already allocated");
-+#endif /* STM32_I2C_USE_DMA */
-       rccEnableI2C2(FALSE);
-       nvicEnableVector(I2C2_EV_IRQn,
-           CORTEX_PRIORITY_MASK(STM32_I2C_I2C2_IRQ_PRIORITY));
-       nvicEnableVector(I2C2_ER_IRQn,
-           CORTEX_PRIORITY_MASK(STM32_I2C_I2C2_IRQ_PRIORITY));
- 
-+#if STM32_I2C_USE_DMA
-       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
-       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
-+#endif /* STM32_I2C_USE_DMA */
-     }
- #endif /* STM32_I2C_USE_I2C2 */
- 
- #if STM32_I2C_USE_I2C3
-     if (&I2CD3 == i2cp) {
--      bool_t b;
- 
-       rccResetI2C3();
-+#if STM32_I2C_USE_DMA
-+      bool_t b;
-       b = dmaStreamAllocate(i2cp->dmarx,
-                             STM32_I2C_I2C3_IRQ_PRIORITY,
-                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
-@@ -668,28 +828,37 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
-                             (void *)i2cp);
-       chDbgAssert(!b, "i2c_lld_start(), #6", "stream already allocated");
-+#endif /* STM32_I2C_USE_DMA */
-       rccEnableI2C3(FALSE);
-       nvicEnableVector(I2C3_EV_IRQn,
-           CORTEX_PRIORITY_MASK(STM32_I2C_I2C3_IRQ_PRIORITY));
-       nvicEnableVector(I2C3_ER_IRQn,
-           CORTEX_PRIORITY_MASK(STM32_I2C_I2C3_IRQ_PRIORITY));
- 
-+#if STM32_I2C_USE_DMA
-       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
-       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
-+#endif /* STM32_I2C_USE_DMA */
-     }
- #endif /* STM32_I2C_USE_I2C3 */
-   }
- 
-+#if STM32_I2C_USE_DMA
-   /* I2C registers pointed by the DMA.*/
-   dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
-   dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Reset i2c peripheral.*/
-   dp->CR1 = I2C_CR1_SWRST;
-   dp->CR1 = 0;
-+#if STM32_I2C_USE_DMA
-   dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
-+#else
-+  dp->CR2 = I2C_CR2_ITERREN;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Setup I2C parameters.*/
-   i2c_lld_set_clock(i2cp);
-@@ -713,8 +882,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
- 
-     /* I2C disable.*/
-     i2c_lld_abort_operation(i2cp);
-+#if STM32_I2C_USE_DMA
-     dmaStreamRelease(i2cp->dmatx);
-     dmaStreamRelease(i2cp->dmarx);
-+#endif /* STM32_I2C_USE_DMA */
- 
- #if STM32_I2C_USE_I2C1
-     if (&I2CD1 == i2cp) {
-@@ -786,10 +957,15 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
-   i2cp->addr = (addr << 1) | 0x01;
-   i2cp->errors = 0;
- 
-+#if STM32_I2C_USE_DMA
-   /* RX DMA setup.*/
-   dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
-   dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
-   dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
-+#else
-+  i2cp->rxbuf = rxbuf;
-+  i2cp->rxbytes = rxbytes;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Waits until BUSY flag is reset and the STOP from the previous operation
-      is completed, alternatively for a timeout condition.*/
-@@ -869,6 +1045,7 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
-   i2cp->addr = addr << 1;
-   i2cp->errors = 0;
- 
-+#if STM32_I2C_USE_DMA
-   /* TX DMA setup.*/
-   dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
-   dmaStreamSetMemory0(i2cp->dmatx, txbuf);
-@@ -878,6 +1055,13 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
-   dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
-   dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
-   dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
-+#else
-+  i2cp->txbuf = txbuf;
-+  i2cp->txbytes = txbytes;
-+
-+  i2cp->rxbuf = rxbuf;
-+  i2cp->rxbytes = rxbytes;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Waits until BUSY flag is reset and the STOP from the previous operation
-      is completed, alternatively for a timeout condition.*/
-diff --git a/os/hal/platforms/STM32/I2Cv1/i2c_lld.h b/os/hal/platforms/STM32/I2Cv1/i2c_lld.h
-index 6b192dc..27b1263 100644
---- a/os/hal/platforms/STM32/I2Cv1/i2c_lld.h
-+++ b/os/hal/platforms/STM32/I2Cv1/i2c_lld.h
-@@ -76,6 +76,15 @@
- #endif
- 
- /**
-+ * @brief   I2C data transfer use dma switch.
-+ * @details If set to @p TRUE the support for I2C DMA is included.
-+ * @note    The default is @p FALSE.
-+ */
-+#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__)
-+#define STM32_I2C_USE_DMA               TRUE
-+#endif
-+
-+/**
-  * @brief   I2C1 interrupt priority level setting.
-  */
- #if !defined(STM32_I2C_I2C1_IRQ_PRIORITY) || defined(__DOXYGEN__)
-@@ -227,6 +236,7 @@
- #error "I2C driver activated but no I2C peripheral assigned"
- #endif
- 
-+#if STM32_I2C_USE_DMA
- #if STM32_I2C_USE_I2C1 &&                                                   \
-     !STM32_DMA_IS_VALID_ID(STM32_I2C_I2C1_RX_DMA_STREAM,                    \
-                            STM32_I2C1_RX_DMA_MSK)
-@@ -266,6 +276,7 @@
- #if !defined(STM32_DMA_REQUIRED)
- #define STM32_DMA_REQUIRED
- #endif
-+#endif /* STM32_I2C_USE_DMA */
- 
- /* Check clock range. */
- #if defined(STM32F4XX)
-@@ -386,6 +397,7 @@ struct I2CDriver {
-    * @brief     Current slave address without R/W bit.
-    */
-   i2caddr_t                 addr;
-+#if STM32_I2C_USE_DMA
-   /**
-    * @brief RX DMA mode bit mask.
-    */
-@@ -402,6 +414,24 @@ struct I2CDriver {
-    * @brief     Transmit DMA channel.
-    */
-   const stm32_dma_stream_t  *dmatx;
-+#else
-+  /**
-+   * @brief     Receive buffer.
-+   */
-+  uint8_t                   *rxbuf;
-+  /**
-+   * @brief     Receive buffer size.
-+   */
-+  size_t                    rxbytes;
-+  /**
-+   * @brief     Transmit buffer.
-+   */
-+   const uint8_t            *txbuf;
-+  /**
-+   * @brief     Transmit buffer size.
-+   */
-+  size_t                    txbytes;
-+#endif /* STM32_I2C_USE_DMA */
-   /**
-    * @brief     Pointer to the I2Cx registers block.
-    */
diff --git a/periphery-lld/AMiRo-LLD b/periphery-lld/AMiRo-LLD
new file mode 160000
index 0000000..d6728c5
--- /dev/null
+++ b/periphery-lld/AMiRo-LLD
@@ -0,0 +1 @@
+Subproject commit d6728c5bab8b0c24e530f047cc1692036f4ea335
diff --git a/periphery-lld/periphAL.h b/periphery-lld/periphAL.h
new file mode 100644
index 0000000..b42c4e3
--- /dev/null
+++ b/periphery-lld/periphAL.h
@@ -0,0 +1,557 @@
+/*
+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_PERIPHAL_H_
+#define _AMIROOS_PERIPHAL_H_
+
+/*============================================================================*/
+/* VERSION                                                                    */
+/*============================================================================*/
+
+/**
+ * @brief   The periphery abstraction layer interface major version.
+ * @note    Changes of the major version imply incompatibilities.
+ */
+#define PERIPHAL_VERSION_MAJOR    1
+
+/**
+ * @brief   The periphery abstraction layer interface minor version.
+ * @note    A higher minor version implies new functionalty, but all old interfaces are still available.
+ */
+#define PERIPHAL_VERSION_MINOR    0
+
+/*============================================================================*/
+/* DEPENDENCIES                                                               */
+/*============================================================================*/
+
+#include <periphALtypes.h>
+
+#include <hal.h>
+#include <hal_qei.h>
+#include <ch.h>
+#include <aos_debug.h>
+
+/*============================================================================*/
+/* GENERAL                                                                    */
+/*============================================================================*/
+
+/**
+ * @brief Delay execution by a specific number of microseconds.
+ *
+ * @param[in]   us    Time to sleep until execution continues in microseconds.
+ */
+static inline void usleep(apalTime_t us)
+{
+  // check if the specified time can be represented by the system
+  aosDbgCheck(us <= LL_ST2US(TIME_INFINITE));
+
+  const systime_t st = LL_US2ST(us);
+  // TIME_IMMEDIATE makes no sense and would even cause system halt
+  if (st != TIME_IMMEDIATE) {
+    chThdSleep(st);
+  }
+  return;
+}
+
+/*============================================================================*/
+/* GPIO                                                                       */
+/*============================================================================*/
+
+#if HAL_USE_PAL || defined (__DOXYGEN__)
+
+/**
+ * @brief GPIO driver type.
+ */
+struct apalGpio_t {
+  /*
+   * Workaround, since GPIOv2 (STM32F4XX) uses a different type than GPIOv1 (STM32F1XX).
+   */
+  #if defined(STM32F4XX)
+  stm32_gpio_t* port;
+  #elif defined(STM32F1XX)
+  GPIO_TypeDef* port;
+  #else
+  void* port;
+  #endif
+
+  uint8_t pad;
+} PACKED_VAR;
+
+/**
+ * @brief Read the current value of a GPIO pin.
+ *
+ * @param[in]   gpio  GPIO to read.
+ * @param[out]  val   Current value of the GPIO.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalGpioRead(apalGpio_t* gpio, apalGpioState_t* const val)
+{
+  aosDbgCheck(gpio != NULL);
+  aosDbgCheck(val != NULL);
+
+  *val = (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? APAL_GPIO_HIGH : APAL_GPIO_LOW;
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Set the value of a GPIO pin.
+ *
+ * @param[in] gpio  GPIO to write.
+ * @param[in] val   Value to set for the GPIO.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalGpioWrite(apalGpio_t* gpio, const apalGpioState_t val)
+{
+  aosDbgCheck(gpio != NULL);
+
+  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
+  syssts_t sysstatus = chSysGetStatusAndLockX();
+  palWritePad(gpio->port, gpio->pad, (val == APAL_GPIO_HIGH) ? PAL_HIGH : PAL_LOW);
+  chSysRestoreStatusX(sysstatus);
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Toggle the output of a GPIO.
+ *
+ * @param[in] gpio  GPIO to toggle.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalGpioToggle(apalGpio_t* gpio)
+{
+  aosDbgCheck(gpio != NULL);
+
+  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
+  syssts_t sysstatus = chSysGetStatusAndLockX();
+  palWritePad(gpio->port, gpio->pad, (palReadPad(gpio->port, gpio->pad) == PAL_HIGH) ? PAL_LOW : PAL_HIGH);
+  chSysRestoreStatusX(sysstatus);
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Get the current on/off state of a control GPIO.
+ *
+ * @param[in]   gpio  Control GPIO to read.
+ * @param[out]  val   Current activation status of the control GPIO.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalControlGpioGet(const apalControlGpio_t* const cgpio, apalControlGpioState_t* const val)
+{
+  aosDbgCheck(cgpio != NULL);
+  aosDbgCheck(cgpio->gpio != NULL);
+  aosDbgCheck(val != NULL);
+
+  *val = ((palReadPad(cgpio->gpio->port, cgpio->gpio->pad) == PAL_HIGH) ^ (cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH)) ? APAL_GPIO_OFF : APAL_GPIO_ON;
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Turn a control GPIO 'on' or 'off' respectively.
+ *
+ * @param[in] gpio  Control GPIO to set.
+ * @param[in] val   Activation value to set for the control GPIO.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalControlGpioSet(const apalControlGpio_t* const cgpio, const apalControlGpioState_t val)
+{
+  aosDbgCheck(cgpio != NULL);
+  aosDbgCheck(cgpio->gpio != NULL);
+  aosDbgCheck(cgpio->meta.direction == APAL_GPIO_DIRECTION_OUTPUT || cgpio->meta.direction == APAL_GPIO_DIRECTION_BIDIRECTIONAL);
+
+  // palWritePad() is not guaranteed to be atomic, thus the scheduler is locked.
+  syssts_t sysstatus = chSysGetStatusAndLockX();
+  palWritePad(cgpio->gpio->port, cgpio->gpio->pad, ((cgpio->meta.active == APAL_GPIO_ACTIVE_HIGH) ^ (val == APAL_GPIO_ON)) ? PAL_LOW : PAL_HIGH);
+  chSysRestoreStatusX(sysstatus);
+  return APAL_STATUS_OK;
+}
+
+#endif
+
+#if HAL_USE_EXT || defined(__DOXYGEN__)
+
+/**
+ * @brief   Converts an apalGpioEdge_t to an ChibiOS EXT edge.
+ */
+#define APAL2CH_EDGE(edge)                                        \
+  ((edge == APAL_GPIO_EDGE_RISING) ? EXT_CH_MODE_RISING_EDGE :    \
+    (edge == APAL_GPIO_EDGE_FALLING) ? EXT_CH_MODE_FALLING_EDGE : \
+     (edge == APAL_GPIO_EDGE_BOTH) ? EXT_CH_MODE_BOTH_EDGES : 0)
+
+#endif
+
+/*============================================================================*/
+/* PWM                                                                        */
+/*============================================================================*/
+
+#if HAL_USE_PWM || defined (__DOXYGEN__)
+
+/**
+ * @brief PWM driver type.
+ */
+typedef PWMDriver apalPWMDriver_t;
+
+/**
+ * @brief   Set the PWM with given parameters.
+ *
+ * @param[in] pwm       PWM driver to set.
+ * @param[in] channel   Channel of the PWM driver to set.
+ * @param[in] width     Width to set the channel to.
+ *
+ * @return  The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalPWMSet(apalPWMDriver_t* pwm, const apalPWMchannel_t channel, const apalPWMwidth_t width)
+{
+  aosDbgCheck(pwm != NULL);
+
+  pwmEnableChannel(pwm, (pwmchannel_t)channel, pwm->period * ((float)width / (float)APAL_PWM_WIDTH_MAX) + 0.5f);
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief   Retrieve the current frequency of the PWM.
+ *
+ * @param[in]  pwm        PWM driver to read.
+ * @param[out] frequency  The currently set frequency.
+ *
+ * @return  The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalPWMGetFrequency(apalPWMDriver_t* pwm, apalPWMfrequency_t* const frequency)
+{
+  aosDbgCheck(pwm != NULL);
+  aosDbgCheck(frequency != NULL);
+
+  *frequency = pwm->config->frequency;
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief   Retrieve the current period of the PWM.
+ *
+ * @param[in]   pwm     PWM driver to read.
+ * @param[out]  period  The currently set period.
+ *
+ * @return  The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalPWMGetPeriod(apalPWMDriver_t* pwm, apalPWMperiod_t* const period)
+{
+  aosDbgCheck(pwm != NULL);
+  aosDbgCheck(period != NULL);
+
+  *period = pwm->period;
+  return APAL_STATUS_OK;
+}
+
+#endif
+
+/*============================================================================*/
+/* QEI                                                                        */
+/*============================================================================*/
+
+#if HAL_USE_QEI || defined (__DOXYGEN__)
+
+/**
+ * @brief QEI driver type.
+ */
+typedef QEIDriver apalQEIDriver_t;
+
+/**
+ * @brief Gets the direction of the last transition.
+ *
+ * @param[in]   qei         The QEI driver to use.
+ * @param[out]  direction   The direction of the last transition.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalQEIGetDirection(apalQEIDriver_t* qei, apalQEIDirection_t* const direction)
+{
+  aosDbgCheck(qei != NULL);
+  aosDbgCheck(direction != NULL);
+
+  *direction = (qei_lld_get_direction(qei)) ? APAL_QEI_DIRECTION_DOWN : APAL_QEI_DIRECTION_UP;
+
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Gets the current position of the ecnoder.
+ *
+ * @param[in]   qei       The QEI driver to use.
+ * @param[out]  position  The current position of the encoder.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalQEIGetPosition(apalQEIDriver_t* qei, apalQEICount_t* const position)
+{
+  aosDbgCheck(qei != NULL);
+  aosDbgCheck(position != NULL);
+
+  *position = qei_lld_get_position(qei);
+
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Gets the value range of the encoder.
+ *
+ * @param[in]   qei     The QEI driver to use.
+ * @param[out]  range   The value range of the encoder.
+ *
+ * @return The status indicates whether the function call was successful.
+ */
+static inline apalExitStatus_t apalQEIGetRange(apalQEIDriver_t* qei, apalQEICount_t* const range)
+{
+  aosDbgCheck(qei != NULL);
+  aosDbgCheck(range != NULL);
+
+  *range = qei_lld_get_range(qei);
+
+  return APAL_STATUS_OK;
+}
+
+#endif
+
+/*============================================================================*/
+/* I2C                                                                        */
+/*============================================================================*/
+
+#if HAL_USE_I2C || defined(__DOXYGEN__)
+
+/**
+ * @brief I2C driver type.
+ */
+typedef I2CDriver apalI2CDriver_t;
+
+/**
+ * @brief Transmit data and receive a response.
+ *
+ * @param[in]   i2cd      The I2C driver to use.
+ * @param[in]   addr      Address to write to.
+ * @param[in]   txbuf     Buffer containing data to send.
+ * @param[in]   txbytes   Number of bytes to send.
+ * @param[out]  rxbuf     Buffer to store a response to.
+ * @param[in]   rxbytes   Number of bytes to receive.
+ * @param[in]   timeout   Timeout for the function to return (in microseconds).
+ *
+ * @return The status indicates whether the function call was succesful or a timeout occurred.
+ */
+static inline apalExitStatus_t apalI2CMasterTransmit(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, const uint8_t* const txbuf, const size_t txbytes, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
+{
+  aosDbgCheck(i2cd != NULL);
+
+#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
+  i2cAcquireBus(i2cd);
+#endif
+
+#if defined(STM32F1XX_I2C)
+  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
+  msg_t status = MSG_OK;
+  if (rxbytes == 1) {
+    uint8_t buffer[2];
+    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
+    rxbuf[0] = buffer[0];
+  } else {
+    status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
+  }
+#else
+  const msg_t status = i2cMasterTransmitTimeout(i2cd, addr, txbuf, txbytes, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
+#endif
+
+#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
+  i2cReleaseBus(i2cd);
+#endif
+
+  switch (status)
+  {
+    case MSG_OK:
+#if defined(STM32F1XX_I2C)
+      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
+#else
+      return APAL_STATUS_OK;
+#endif
+    case MSG_TIMEOUT:
+      return APAL_STATUS_TIMEOUT;
+    case MSG_RESET:
+    default:
+      return APAL_STATUS_ERROR;
+  }
+}
+
+/**
+ * @brief Read data from a specific address.
+ *
+ * @param[in]   i2cd      The I2C driver to use.
+ * @param[in]   addr      Address to read.
+ * @param[out]  rxbuf     Buffer to store the response to.
+ * @param[in]   rxbytes   Number of bytes to receive.
+ * @param[in]   timeout   Timeout for the function to return (in microseconds).
+ *
+ * @return The status indicates whether the function call was succesful or a timeout occurred.
+ */
+static inline apalExitStatus_t apalI2CMasterReceive(apalI2CDriver_t* i2cd, const apalI2Caddr_t addr, uint8_t* const rxbuf, const size_t rxbytes, const apalTime_t timeout)
+{
+  aosDbgCheck(i2cd != NULL);
+
+#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
+  i2cAcquireBus(i2cd);
+#endif
+
+#if defined(STM32F1XX_I2C)
+  // Due to a hardware limitation, for STM32F1 platform the minimum number of bytes that can be received is two.
+  msg_t status = MSG_OK;
+  if (rxbytes == 1) {
+    uint8_t buffer[2];
+    status = i2cMasterReceiveTimeout(i2cd, addr, buffer, 2, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
+    rxbuf[0] = buffer[0];
+  } else {
+    status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
+  }
+#else
+  const msg_t status = i2cMasterReceiveTimeout(i2cd, addr, rxbuf, rxbytes, ((timeout >= TIME_INFINITE) ? TIME_INFINITE : LL_US2ST(timeout)) );
+#endif
+
+#if (I2C_USE_MUTUAL_EXCLUSION == TRUE)
+  i2cReleaseBus(i2cd);
+#endif
+
+  switch (status)
+  {
+    case MSG_OK:
+#if defined(STM32F1XX_I2C)
+      return (rxbytes != 1) ? APAL_STATUS_OK : APAL_STATUS_WARNING;
+#else
+      return APAL_STATUS_OK;
+#endif
+    case MSG_TIMEOUT:
+      return APAL_STATUS_TIMEOUT;
+    case MSG_RESET:
+    default:
+      return APAL_STATUS_ERROR;
+  }
+}
+
+#endif
+
+/*============================================================================*/
+/* SPI                                                                        */
+/*============================================================================*/
+
+#if HAL_USE_SPI || defined(__DOXYGEN__)
+
+/**
+ * @brief SPI driver type.
+ */
+typedef SPIDriver apalSPIDriver_t;
+
+/**
+ * @brief Transmit and receive data from SPI
+ *
+ * @param[in]   spid      The SPI driver to use.
+ * @param[in]   txData    Buffer containing data to send.
+ * @param[out]  rxData    Buffer to store.
+ * @param[in]   length    Number of bytes to send.
+ *
+ * @return The status indicates whether the function call was succesful.
+ */
+static inline apalExitStatus_t apalSPIExchange(apalSPIDriver_t* spid, const uint8_t* const txData , uint8_t* const rxData, const size_t length)
+{
+  aosDbgCheck(spid != NULL);
+
+#if (SPI_USE_MUTUAL_EXCLUSION)
+  spiAcquireBus(spid);
+#endif
+  spiSelect(spid);
+  spiExchange(spid, length, txData, rxData);
+  spiUnselect(spid);
+#if (SPI_USE_MUTUAL_EXCLUSION)
+  spiReleaseBus(spid);
+#endif
+
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Receive data from SPI
+ *
+ * @param[in]   spid      The SPI driver to use.
+ * @param[out]  data      Buffer to store.
+ * @param[in]   length    Number of bytes to send.
+ *
+ * @return The status indicates whether the function call was succesful.
+ */
+static inline apalExitStatus_t apalSPIReceive(apalSPIDriver_t* spid, uint8_t* const data, const size_t length)
+{
+  aosDbgCheck(spid != NULL);
+
+#if (SPI_USE_MUTUAL_EXCLUSION)
+  spiAcquireBus(spid);
+#endif
+  spiSelect(spid);
+  spiReceive(spid, length, data);
+  spiUnselect(spid);
+#if (SPI_USE_MUTUAL_EXCLUSION)
+  spiReleaseBus(spid);
+#endif
+
+  return APAL_STATUS_OK;
+}
+
+/**
+ * @brief Transmit data to SPI
+ *
+ * @param[in]   spid      The SPI driver to use.
+ * @param[in]   data      Buffer containing data to send.
+ * @param[in]   length    Number of bytes to send.
+ *
+ * @return The status indicates whether the function call was succesful.
+ */
+static inline apalExitStatus_t apalSPITransmit(apalSPIDriver_t* spid, const uint8_t* const data, const size_t length)
+{
+  aosDbgCheck(spid != NULL);
+
+#if (SPI_USE_MUTUAL_EXCLUSION)
+  spiAcquireBus(spid);
+#endif
+  spiSelect(spid);
+  spiSend(spid, length, data);
+  spiUnselect(spid);
+#if (SPI_USE_MUTUAL_EXCLUSION)
+  spiReleaseBus(spid);
+#endif
+
+  return APAL_STATUS_OK;
+}
+
+#endif
+
+/*============================================================================*/
+/* DEBUG                                                                      */
+/*============================================================================*/
+
+/**
+ * @brief Assert function to check a given condition.
+ *
+ * @param[in] c   The condition to check.
+ */
+#define apalDbgAssert(c)   aosDbgAssert(c)
+
+#endif /* _AMIROOS_PERIPHAL_H_ */
diff --git a/periphery-lld/periphery-lld.mk b/periphery-lld/periphery-lld.mk
new file mode 100644
index 0000000..3c71773
--- /dev/null
+++ b/periphery-lld/periphery-lld.mk
@@ -0,0 +1,37 @@
+################################################################################
+# 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
+PERIPHERYLLD_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+
+include $(PERIPHERYLLD_DIR)AMiRo-LLD/Makefile
+
+# include path
+PERIPHERYLLDINC = $(AMIROLLD_INC) \
+                  $(PERIPHERYLLD_DIR)
+
+# C sources
+PERIPHERYLLDCSRC = $(AMIROLLD_CSRC)
+
diff --git a/periphery-lld/peripherylldsetup.sh b/periphery-lld/peripherylldsetup.sh
new file mode 100755
index 0000000..afd4952
--- /dev/null
+++ b/periphery-lld/peripherylldsetup.sh
@@ -0,0 +1,565 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+################################################################################
+# GENERIC FUNCTIONS                                                            #
+################################################################################
+
+### print an error message #####################################################
+# Prints a error <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printError <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printError {
+  local string="ERROR:   $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a warning message ####################################################
+# Prints a warning <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printMessage <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printWarning {
+  local string="WARNING: $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)"
+}
+
+### print an information message ###############################################
+# Prints an information <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printInfo <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printInfo {
+  local string="INFO:    $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)"
+}
+
+### print a message to file ####################################################
+# Appends a <message> to a log file, specified by the variable 'LOG_FILE'.
+#
+# usage       printLog <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printLog {
+  local string="LOG:     $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+}
+
+### exit the script normally ###################################################
+# Prints a delimiter and exits the script normally (returns 0).
+#
+# usage:      quitScript
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
+  exit 0
+}
+
+### read a user input ##########################################################
+# Reads a single character user input from a set up <options> and stores it in
+# a given <return> variable.
+#
+# usage:      readUserInput <options> <return>
+# arguments:  <options>
+#                 String definiing the set of valid characters.
+#                 If the string is empty, the user can input any character.
+#             <return>
+#                 Variable to store the selected character to.
+# return:     n/a
+#
+function readUserInput {
+  local input=""
+  # read user input
+  while [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); do
+    read -p "your selection: " -n 1 -e input
+    if [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); then
+      printWarning "[$input] is no valid action\n"
+    fi
+  done
+  printLog "[$input] has been selected\n"
+  eval $2="$input"
+}
+
+### check whether argument is an option ########################################
+# Checks a <string> whether it is an option.
+# Options are defined to either start with '--' followed by any string, or
+# to start with a single '-' followed by a single character, or
+# to start with a single '-' followed by a single character, a '=' and any string.
+# Examples: '--option', '--option=arg', '-o', '-o=arg', '--'
+#
+# usage:      parseIsOption <string>
+# arguments:  <string>
+#                 A string to check whether it is an option.
+# return:     0
+#                 <string> is an option.
+#             -1
+#                 <string> is not an option.
+#
+function parseIsOption {
+  if [[ "$1" =~ ^-(.$|.=.*) ]] || [[ "$1" =~ ^--.* ]]; then
+    return 0
+  else
+    return -1
+  fi
+}
+
+### set the log file ###########################################################
+# Sets a specified <infile> as log file and checks whether it already exists.
+# If so, the log may either be appended to the file, its content can be cleared,
+# or no log is generated at all.
+# The resulting path is stored in <outvar>.
+#
+# usage:      setLogFile [--option=<option>] [--quiet] <infile> <outvar>
+# arguments:  --option=<option>
+#                 Select what to do if <file> already exists.
+#                 Possible values are 'a', 'c', 'r' and 'n'.
+#                 - a: append (starts with a separator)
+#                 - c: continue (does not insert a seperator)
+#                 - r: delete and restart
+#                 - n: no log
+#                 If no option is secified but <file> exists, an interactive selection is provided.
+#             --quiet
+#                 Suppress all messages.
+#             <infile>
+#                 Path of the wanted log file.
+#             <outvar>
+#                 Variable to store the path of the log file to.
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: invalid input
+#
+function setLogFile {
+  local filepath=""
+  local option=""
+  local quiet=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -o=*|--option=*)
+          option=${1#*=}; shift 1;;
+        -o*|--option*)
+          option="$2"; shift 2;;
+        -q|--quiet)
+          quiet=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+  filepath=$(realpath ${otherargs[0]})
+
+  # if file already exists
+  if [ -e $filepath ]; then
+    # if no option was specified, ask what to do
+    if [ -z "$option" ]; then
+      printWarning "log file $filepath already esists\n"
+      local userinput=""
+      printf "Select what to do:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput "AaRrNn" userinput
+      option=${userinput,,}
+    fi
+    # evaluate option
+    case "$option" in
+      a|c)
+        if [ $quiet = false ]; then
+          printInfo "appending log to $filepath\n"
+        fi
+        if [ $option != c ]; then
+          printf "\n" >> $filepath
+          printf "######################################################################\n" >> $filepath
+          printf "\n" >> $filepath
+        fi
+        ;;
+      r)
+        echo -n "" > $filepath
+        if [ $quiet = false ]; then
+          printInfo "content of $filepath wiped\n"
+        fi
+        ;;
+      n)
+        if [ $quiet = false ]; then
+          printInfo "no log file will be generated\n"
+        fi
+        filepath=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $option\n"; return -1;;
+    esac
+  else
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
+  fi
+
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
+}
+
+################################################################################
+# SPECIFIC FUNCTIONS                                                           #
+################################################################################
+
+### print welcome text #########################################################
+# Prints a welcome message to standard out.
+#
+# usage:      printWelcomeText
+# arguments:  n/a
+# return:     n/a
+#
+function printWelcomeText {
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "#             Welcome to the AMiRo-LLD submodule setup!              #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+  printf "#                                                                    #\n"
+  printf "# This is free software; see the source for copying conditions.      #\n"
+  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+  printf "# Excellence Initiative.                                             #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+}
+
+### print help #################################################################
+# Prints a help text to standard out.
+#
+# usage:      printHelp
+# arguments:  n/a
+# return:     n/a
+#
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-i|--init] [-w|--wipe] [-q|--quit] [--log=<file>]\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -i, --init\n"
+  printf "              Initialize AMiRo-LLD submodule.\n"
+  printf "          -w, --wipe\n"
+  printf "              Wipe AMiRo-LLD submodule.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### initialize AMiRo-LLD submodule #############################################
+# Initialize the AMiRo-LLD submodule.
+#
+# usage:      initAmiroLld
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Arborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function initAmiroLld {
+  printInfo "initializing AMiRo-LLD submodule...\n"
+  local userdir=$(pwd)
+  local peripheryllddir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local amirollddir=${peripheryllddir}/AMiRo-LLD
+
+  # if the AMiRo-BLT folder is not empty
+  if [ ! -z "$(ls -A $amirollddir)" ]; then
+    printWarning "$(realpath $amirollddir) is not empty. Delete and reinitialize? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case $userinput in
+      Y|y)
+        wipeAmiroBlt
+        ;;
+      N|n)
+        printWarning "AMiRo-LLD initialization aborted by user\n"
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  fi
+
+  # initialize submodule to default branch
+  cd $peripheryllddir
+  git submodule update --init $amirollddir 2>&1 | tee -a $LOG_FILE
+  while [ ${PIPESTATUS[0]} -ne 0 ]; do
+    printWarning "initialitaion failed. Retry? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        git submodule update --init $amirollddir 2>&1 | tee -a $LOG_FILE;;
+      N|n)
+        printWarning "AMiRo-LLD initialization aborted by user\n"
+        cd $userdir
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  done
+  cd $userdir
+
+  return 0
+}
+
+### reset AMiRo-LLD submodule and wipe directory ###############################
+# Resets the AMiRo-LLD Git submodule and wipes the directory.
+#
+# usage:      wipeAmiroLld
+# arguments:  n/a
+# return:     n/a
+function wipeAmiroLld {
+  printInfo "reset and wipe Git submodule $amirollddir\n"
+  local userdir=$(pwd)
+  local peripheryllddir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local amirollddir=${peripheryllddir}/AMiRo-LLD
+
+  # if the AMiRo-LLD folder is empty
+  if [ -z "$(ls -A $amirollddir)" ]; then
+    printWarning "$amirollddir is already empty\n"
+    return 1
+  else
+    # get some information from Git
+    local userdir=$(pwd)
+    cd $peripheryllddir
+    local git_basehash=($(git ls-tree -d HEAD $amirollddir)); git_basehash=${git_basehash[2]}
+    cd $amirollddir
+    local git_branch_current=$(git rev-parse --abbrev-ref HEAD)
+    local git_difftobase="$(git diff ${git_basehash}..HEAD)"
+    local git_commits=$(git log --format=oneline ${git_basehash}..HEAD)
+    local git_dirtyfiles=($(git ls-files -dmo --exclude-standard --exclude=/doc))
+    cd $userdir
+    local issues=0
+    # if HEAD is ahead of submodule base commit
+    if [ -n "$git_difftobase" ]; then
+      issues=$((issues + 1))
+      printWarning "HEAD is ahead of submodule base\n"
+    fi
+    # if there are untracked, modified, or deleted files
+    if [ ${#git_dirtyfiles[@]} != 0 ]; then
+      issues=$((issues + 1))
+      printWarning "there are ${#git_dirtyfiles[@]} untracked, modified, or deleted files\n"
+    fi
+    if [ $issues -gt 0 ]; then
+      local userinput=""
+      printWarning "$issues issues detected. Do you want to continue? [y/n]\n"
+      readUserInput "YyNn" userinput
+      case "$userinput" in
+        Y|y)
+          ;;
+        N|n)
+          printfWarning "wiping AMiRo-LLD Git submodule aborted by user\n"
+          return 2
+          ;;
+        *) # sanity check (return error)
+          printError "unexpected input: $userinput\n"; return -1;;
+      esac
+    fi
+
+    # checkout base commit and delete all local branches
+    cd $peripheryllddir
+    git submodule update --force --checkout $amirollddir | tee -a $LOG_FILE
+    cd $amirollddir
+    local git_branches=($(git for-each-ref --format="%(refname)"))
+    for branch in $git_branches; do
+      if [[ $branch = *"heads/"* ]]; then
+        git branch -D ${branch##*/} | tee -a $LOG_FILE
+      fi
+    done
+    cd $userdir
+
+    # deinitialize AMiRo-LLD submodule and delete any remaining files
+    cd $peripheryllddir
+    git submodule deinit -f $amirollddir 2>&1 | tee -a $LOG_FILE
+    rm -rf $amirollddir/*
+    cd $userdir
+
+    return 0
+  fi
+}
+
+### main function of this script ###############################################
+# Initializes or wipes the AMiRo-LLD Git submodule.
+#
+# usage:      see function printHelp
+# arguments:  see function printHelp
+# return:     0
+#                 No error or warning occurred.
+#
+function main {
+  # print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  printf "\n"
+
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
+
+  # set log file if specified
+  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
+    # get the parameter (file name)
+    local cmdidx=1
+    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
+      cmdidx=$[cmdidx + 1]
+    done
+    local cmd="${!cmdidx}"
+    local logfile=""
+    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
+      logfile=${cmd#*=}
+    else
+      local filenameidx=$((cmdidx + 1))
+      logfile="${!filenameidx}"
+    fi
+    # optionally force silent appending
+    if [[ "$cmd" = "--LOG"* ]]; then
+      setLogFile --option=c --quiet "$logfile" LOG_FILE
+    else
+      setLogFile "$logfile" LOG_FILE
+      printf "\n"
+    fi
+  fi
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -i|--init)
+           initAmiroLld; printf "\n"; shift 1;;
+        -w|--wipe)
+           wipeAmiroLld; printf "\n"; shift 1;;
+        -q|--quit)
+          quitScript; shift 1;;
+        --log=*|--LOG=*) # already handled; ignore
+          shift 1;;
+        --log|--LOG) # already handled; ignore
+          shift 2;;
+        --noinfo) # already handled; ignore
+          shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "Periphery-LLD setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [I] - initialize AMiRo-LLD submodule\n"
+    printf "  [W] - wipe AMiRo-LLD submodule\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "IiPpDdWwQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      I|i)
+        initAmiroLld; printf "\n";;
+      W|w)
+        wipeAmiroLld; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
diff --git a/ports/STM32F103xE.ld b/ports/STM32F103xE.ld
deleted file mode 100644
index a07f77a..0000000
--- a/ports/STM32F103xE.ld
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * ST32F103xE memory setup.
- */
-__main_stack_size__     = 0x0400;
-__process_stack_size__  = 0x0400;
-
-MEMORY
-{
-    flash : org = 0x08006000, len = 512k-24k
-    ram : org = 0x20000000, len = 64k
-}
-
-__ram_start__           = ORIGIN(ram);
-__ram_size__            = LENGTH(ram);
-__ram_end__             = __ram_start__ + __ram_size__;
-
-__crc_start__		= ORIGIN(flash) + 0x150;
-
-ENTRY(ResetHandler)
-
-SECTIONS
-{
-    . = 0;
-    _text = .;
-
-    startup : ALIGN(16) SUBALIGN(16)
-    {
-        KEEP(*(vectors))
-    } > flash
-
-    crc __crc_start__ :
-    {
-        LONG(0x55aa11ee);
-    } > flash
-
-    constructors : ALIGN(4) SUBALIGN(4)
-    {
-        PROVIDE(__init_array_start = .);
-        KEEP(*(SORT(.init_array.*)))
-        KEEP(*(.init_array))
-        PROVIDE(__init_array_end = .);
-    } > flash
-
-    destructors : ALIGN(4) SUBALIGN(4)
-    {
-        PROVIDE(__fini_array_start = .);
-        KEEP(*(.fini_array))
-        KEEP(*(SORT(.fini_array.*)))
-        PROVIDE(__fini_array_end = .);
-    } > flash
-
-    .text : ALIGN(16) SUBALIGN(16)
-    {
-        *(.text.startup.*)
-        *(.text)
-        *(.text.*)
-        *(.rodata)
-        *(.rodata.*)
-        *(.glue_7t)
-        *(.glue_7)
-        *(.gcc*)
-    } > flash
-
-    .ARM.extab :
-    {
-        *(.ARM.extab* .gnu.linkonce.armextab.*)
-    } > flash
-
-    .ARM.exidx : {
-        PROVIDE(__exidx_start = .);
-        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
-        PROVIDE(__exidx_end = .);
-     } > flash
-
-    .eh_frame_hdr :
-    {
-        *(.eh_frame_hdr)
-    } > flash
-
-    .eh_frame : ONLY_IF_RO
-    {
-        *(.eh_frame)
-    } > flash
-    
-    .textalign : ONLY_IF_RO
-    {
-        . = ALIGN(8);
-    } > flash
-
-    . = ALIGN(4);
-    _etext = .;
-    _textdata = _etext;
-
-    .stacks :
-    {
-        . = ALIGN(8);
-        __main_stack_base__ = .;
-        . += __main_stack_size__;
-        . = ALIGN(8);
-        __main_stack_end__ = .;
-        __process_stack_base__ = .;
-        __main_thread_stack_base__ = .;
-        . += __process_stack_size__;
-        . = ALIGN(8);
-        __process_stack_end__ = .;
-        __main_thread_stack_end__ = .;
-    } > ram
-
-    .data ALIGN(4) : ALIGN(4)
-    {
-        . = ALIGN(4);
-        PROVIDE(_data = .);
-        *(.data)
-        *(.data.*)
-        *(.ramtext)
-        . = ALIGN(4);
-        PROVIDE(_edata = .);
-    } > ram AT > flash
-
-    .bss ALIGN(4) : ALIGN(4)
-    {
-        . = ALIGN(4);
-        PROVIDE(_bss_start = .);
-        *(.bss)
-        *(.bss.*)
-        *(COMMON)
-        . = ALIGN(4);
-        PROVIDE(_bss_end = .);
-    } > ram    
-}
-
-PROVIDE(end = .);
-_end            = .;
-
-__heap_base__   = _end;
-__heap_end__    = __ram_end__;
diff --git a/ports/STM32F405xG.ld b/ports/STM32F405xG.ld
deleted file mode 100644
index aced1ee..0000000
--- a/ports/STM32F405xG.ld
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * ST32F405xG memory setup.
- */
-__main_stack_size__     = 0x0400;
-__process_stack_size__  = 0x0400;
-
-MEMORY
-{
-    flash : org = 0x08008000, len = 1M-32k
-    ram : org = 0x20000000, len = 112k
-    ethram : org = 0x2001C000, len = 16k
-    ccmram : org = 0x10000000, len = 64k
-}
-
-__ram_start__           = ORIGIN(ram);
-__ram_size__            = LENGTH(ram);
-__ram_end__             = __ram_start__ + __ram_size__;
-
-__crc_start__		= ORIGIN(flash) + 0x1AC;
-
-ENTRY(ResetHandler)
-
-SECTIONS
-{
-    . = 0;
-    _text = .;
-
-    startup : ALIGN(16) SUBALIGN(16)
-    {
-        KEEP(*(vectors))
-    } > flash
-
-    crc __crc_start__ :
-    {
-        LONG(0x55AA11EE);
-    } > flash
-
-    constructors : ALIGN(4) SUBALIGN(4)
-    {
-        PROVIDE(__init_array_start = .);
-        KEEP(*(SORT(.init_array.*)))
-        KEEP(*(.init_array))
-        PROVIDE(__init_array_end = .);
-    } > flash
-
-    destructors : ALIGN(4) SUBALIGN(4)
-    {
-        PROVIDE(__fini_array_start = .);
-        KEEP(*(.fini_array))
-        KEEP(*(SORT(.fini_array.*)))
-        PROVIDE(__fini_array_end = .);
-    } > flash
-
-    .text : ALIGN(16) SUBALIGN(16)
-    {
-        *(.text.startup.*)
-        *(.text)
-        *(.text.*)
-        *(.rodata)
-        *(.rodata.*)
-        *(.glue_7t)
-        *(.glue_7)
-        *(.gcc*)
-    } > flash
-
-    .ARM.extab :
-    {
-        *(.ARM.extab* .gnu.linkonce.armextab.*)
-    } > flash
-
-    .ARM.exidx : {
-        PROVIDE(__exidx_start = .);
-        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
-        PROVIDE(__exidx_end = .);
-     } > flash
-
-    .eh_frame_hdr :
-    {
-        *(.eh_frame_hdr)
-    } > flash
-
-    .eh_frame : ONLY_IF_RO
-    {
-        *(.eh_frame)
-    } > flash
-    
-    .textalign : ONLY_IF_RO
-    {
-        . = ALIGN(8);
-    } > flash
-
-    . = ALIGN(4);
-    _etext = .;
-    _textdata = _etext;
-
-    .ccm (NOLOAD):
-    {
-        PROVIDE(_ccm_start = .);
-        . = ALIGN(4);
-        *(.ccm)
-        . = ALIGN(4);
-        *(.ccm.*)
-        . = ALIGN(4);
-        PROVIDE(_ccm_end = .);
-    } > ccmram
-
-    .stacks :
-    {
-        . = ALIGN(8);
-        __main_stack_base__ = .;
-        . += __main_stack_size__;
-        . = ALIGN(8);
-        __main_stack_end__ = .;
-        __process_stack_base__ = .;
-        __main_thread_stack_base__ = .;
-        . += __process_stack_size__;
-        . = ALIGN(8);
-        __process_stack_end__ = .;
-        __main_thread_stack_end__ = .;
-    } > ram
-
-    .data ALIGN(4) : ALIGN(4)
-    {
-        . = ALIGN(4);
-        PROVIDE(_data = .);
-        *(.data)
-        *(.data.*)
-        *(.ramtext)
-        . = ALIGN(4);
-        PROVIDE(_edata = .);
-    } > ram AT > flash
-
-    .bss ALIGN(4) : ALIGN(4)
-    {
-        . = ALIGN(4);
-        PROVIDE(_bss_start = .);
-        *(.bss)
-        *(.bss.*)
-        *(COMMON)
-        . = ALIGN(4);
-        PROVIDE(_bss_end = .);
-    } > ram
-
-    .eth (NOLOAD):
-    {
-        PROVIDE(_dma_start = .);
-        . = ALIGN(4);
-        *(.eth)
-        . = ALIGN(4);
-        *(.eth.*)
-        . = ALIGN(4);
-        PROVIDE(_dma_end = .);
-    } > ethram
-}
-
-PROVIDE(end = .);
-_end            = .;
-
-__heap_base__   = _end;
-__heap_end__    = __ram_end__;
diff --git a/ports/rules.mk b/ports/rules.mk
deleted file mode 100644
index 45dde0a..0000000
--- a/ports/rules.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-# ARM Cortex-Mx common makefile scripts and rules.
-
-##############################################################################
-# Processing options coming from the upper Makefile.
-#
-
-# Output directory and files
-SRECFILE = $(BUILDDIR)/$(PROJECT).srec
-
-#
-# Makefile rules
-#
-
-blt: $(SRECFILE)
-
-MAKE_ALL_RULE_HOOK: blt
-
-%.srec: %.elf $(LDSCRIPT)
-ifeq ($(USE_VERBOSE_COMPILE),yes)
-	$(SREC) $< $@
-else
-	@echo Creating $@
-	@$(SREC) $< $@
-endif
-
-# *** EOF ***
diff --git a/setup.sh b/setup.sh
new file mode 100755
index 0000000..036bdc4
--- /dev/null
+++ b/setup.sh
@@ -0,0 +1,605 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+################################################################################
+# GENERIC FUNCTIONS                                                            #
+################################################################################
+
+### print an error message #####################################################
+# Prints a error <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printError <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printError {
+  local string="ERROR:   $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a warning message ####################################################
+# Prints a warning <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printMessage <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printWarning {
+  local string="WARNING: $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)"
+}
+
+### print an information message ###############################################
+# Prints an information <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printInfo <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printInfo {
+  local string="INFO:    $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)"
+}
+
+### print a message to file ####################################################
+# Appends a <message> to a log file, specified by the variable 'LOG_FILE'.
+#
+# usage       printLog <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printLog {
+  local string="LOG:     $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+}
+
+### exit the script normally ###################################################
+# Prints a delimiter and exits the script normally (returns 0).
+#
+# usage:      quitScript
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
+  exit 0
+}
+
+### read a user input ##########################################################
+# Reads a single character user input from a set up <options> and stores it in
+# a given <return> variable.
+#
+# usage:      readUserInput <options> <return>
+# arguments:  <options>
+#                 String definiing the set of valid characters.
+#                 If the string is empty, the user can input any character.
+#             <return>
+#                 Variable to store the selected character to.
+# return:     n/a
+#
+function readUserInput {
+  local input=""
+  # read user input
+  while [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); do
+    read -p "your selection: " -n 1 -e input
+    if [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); then
+      printWarning "[$input] is no valid action\n"
+    fi
+  done
+  printLog "[$input] has been selected\n"
+  eval $2="$input"
+}
+
+### check whether argument is an option ########################################
+# Checks a <string> whether it is an option.
+# Options are defined to either start with '--' followed by any string, or
+# to start with a single '-' followed by a single character, or
+# to start with a single '-' followed by a single character, a '=' and any string.
+# Examples: '--option', '--option=arg', '-o', '-o=arg', '--'
+#
+# usage:      parseIsOption <string>
+# arguments:  <string>
+#                 A string to check whether it is an option.
+# return:     0
+#                 <string> is an option.
+#             -1
+#                 <string> is not an option.
+#
+function parseIsOption {
+  if [[ "$1" =~ ^-(.$|.=.*) ]] || [[ "$1" =~ ^--.* ]]; then
+    return 0
+  else
+    return -1
+  fi
+}
+
+### set the log file ###########################################################
+# Sets a specified <infile> as log file and checks whether it already exists.
+# If so, the log may either be appended to the file, its content can be cleared,
+# or no log is generated at all.
+# The resulting path is stored in <outvar>.
+#
+# usage:      setLogFile [--option=<option>] [--quiet] <infile> <outvar>
+# arguments:  --option=<option>
+#                 Select what to do if <file> already exists.
+#                 Possible values are 'a', 'c', 'r' and 'n'.
+#                 - a: append (starts with a separator)
+#                 - c: continue (does not insert a seperator)
+#                 - r: delete and restart
+#                 - n: no log
+#                 If no option is secified but <file> exists, an interactive selection is provided.
+#             --quiet
+#                 Suppress all messages.
+#             <infile>
+#                 Path of the wanted log file.
+#             <outvar>
+#                 Variable to store the path of the log file to.
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: invalid input
+#
+function setLogFile {
+  local filepath=""
+  local option=""
+  local quiet=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -o=*|--option=*)
+          option=${1#*=}; shift 1;;
+        -o*|--option*)
+          option="$2"; shift 2;;
+        -q|--quiet)
+          quiet=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+  filepath=$(realpath ${otherargs[0]})
+
+  # if file already exists
+  if [ -e $filepath ]; then
+    # if no option was specified, ask what to do
+    if [ -z "$option" ]; then
+      printWarning "log file $filepath already esists\n"
+      local userinput=""
+      printf "Select what to do:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput "AaRrNn" userinput
+      option=${userinput,,}
+    fi
+    # evaluate option
+    case "$option" in
+      a|c)
+        if [ $quiet = false ]; then
+          printInfo "appending log to $filepath\n"
+        fi
+        if [ $option != c ]; then
+          printf "\n" >> $filepath
+          printf "######################################################################\n" >> $filepath
+          printf "\n" >> $filepath
+        fi
+        ;;
+      r)
+        echo -n "" > $filepath
+        if [ $quiet = false ]; then
+          printInfo "content of $filepath wiped\n"
+        fi
+        ;;
+      n)
+        if [ $quiet = false ]; then
+          printInfo "no log file will be generated\n"
+        fi
+        filepath=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $option\n"; return -1;;
+    esac
+  else
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
+  fi
+
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
+}
+
+################################################################################
+# SPECIFIC FUNCTIONS                                                           #
+################################################################################
+
+### print welcome text #########################################################
+# Prints a welcome message to standard out.
+#
+# usage:      printWelcomeText
+# arguments:  n/a
+# return:     n/a
+#
+function printWelcomeText {
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "#                   Welcome to the AMiRo-OS setup!                   #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+  printf "#                                                                    #\n"
+  printf "# This is free software; see the source for copying conditions.      #\n"
+  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+  printf "# Excellence Initiative.                                             #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+}
+
+### print help #################################################################
+# Prints a help text to standard out.
+#
+# usage:      printHelp
+# arguments:  n/a
+# return:     n/a
+#
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-i|--init] [-k|--kernel] [-b|--bootloader] [-p|--periphery-LLD] [-c|--compiler] [--IDE] [-q|--quit] [--log=<file>]\n"
+  printf "\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -i, --init\n"
+  printf "              Run project initalization.\n"
+  printf "          -k, --kernel\n"
+  printf "              Enter kernel setup.\n"
+  printf "          -b, --bootloader\n"
+  printf "              Enter bootloader setup.\n"
+  printf "          -p, --periphery-LLD\n"
+  printf "              Enter periphery-LLD setup.\n"
+  printf "          -c, --compiler\n"
+  printf "              Enter compiler setup.\n"
+  printf "          --IDE\n"
+  printf "              Enter IDE setup.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### initialize whole project ###################################################
+# Initializes the whole project, including fetching all submodules and so on.
+#
+# usage:      projectInitialization
+# arguments:  n/a
+# return:     n/a
+#
+function projectInitialization {
+  printInfo "initializing project\n"
+  printf "\n"
+  if [ -z "$LOG_FILE" ]; then
+    printInfo "initializing kernel submodule...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/kernel/kernelsetup.sh --init --quit --noinfo
+    printf "\n"
+    printInfo "initializing ChibiOS...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/kernel/kernelsetup.sh --patch --documentation=g --quit --noinfo
+    printf "\n"
+
+    printInfo "initializing bootloader submodule...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/bootloadersetup.sh --init --quit --noinfo
+    printf "\n"
+    printInfo "initializing AMiRo-BLT...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/AMiRo-BLT/setup.sh --stm32flash --SerialBoot --quit --noinfo
+    printf "\n"
+
+    printInfo "initializing periphery-LLD (AMiRo-LLD)...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/periphery-lld/peripherylldsetup.sh --init --quit --noinfo
+    printf "\n"
+  else
+    printInfo "initializing kernel submodule...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/kernel/kernelsetup.sh --init --quit --LOG="$LOG_FILE" --noinfo
+    printf "\n"
+    printInfo "initializing ChibiOS...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/kernel/kernelsetup.sh --patch --documentation=g --quit --LOG="$LOG_FILE" --noinfo
+    printf "\n"
+
+    printInfo "initializing bootloader submodule...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/bootloadersetup.sh --init --quit --LOG="$LOG_FILE" --noinfo
+    printf "\n"
+    printInfo "initializing AMiRo-BLT...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/AMiRo-BLT/setup.sh --stm32flash --SerialBoot --quit --LOG="$LOG_FILE" --noinfo
+    printf "\n"
+
+    printInfo "initializing periphery-LLD (AMiRo-LLD)...\n"
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/periphery-lld/peripherylldsetup.sh --init --quit --LOG="$LOG_FILE" --noinfo
+    printf "\n"
+  fi
+  printInfo "initialization complete\n"
+}
+
+### enter kernel setup #########################################################
+# Enter the kernel setup.
+#
+# usage:      kernelSetup
+# arguments:  n/a
+# return:     n/a
+#
+function kernelSetup {
+  printInfo "entering kernel setup\n"
+  printf "\n"
+  if [ -z $LOG_FILE ]; then
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/kernel/kernelsetup.sh --noinfo
+  else
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/kernel/kernelsetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
+
+### enter bootloader setup #####################################################
+# Enter bootloader setup.
+#
+# usage:      bootloaderSetup
+# arguments:  n/a
+# return:     n/a
+#
+function bootloaderSetup {
+  printInfo "entering bootloader setup\n"
+  printf "\n"
+  if [ -z $LOG_FILE ]; then
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/bootloadersetup.sh --noinfo
+  else
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/bootloadersetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
+
+### enter periphery LLD setup ##################################################
+# Enter the Periphery-LLD setup.
+#
+# usage:      peripheryLldSetup
+# arguments:  n/a
+# return:     n/a
+#
+function peripheryLldSetup {
+  printInfo "entering periphery-LLD setup\n"
+  printf "\n"
+  if [ -z $LOG_FILE ]; then
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/periphery-lld/peripherylldsetup.sh --noinfo
+  else
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/periphery-lld/peripherylldsetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
+
+### enter compiler setup #######################################################
+# Enter the compiler setup of tzhe AMiRo-BLT submodule.
+#
+# usage:      compilerSetup
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: AMiRo-BLT submodule not nitialized yet-
+#
+function compilerSetup {
+  # check if the AMiRo-BLT submodule is initialized and the script file exists
+  local amirobltdir=$(dirname $(realpath ${BASH_SOURCE[0]}))/bootloader/AMiRo-BLT
+  local compilerscriptfile=${amirobltdir}/tools/compiler/compilersetup.sh
+  if [ -z "$(ls -A $amirobltdir)" ] || [ ! -f $compilerscriptfile ]; then
+    printWarning "Please initialize AMiRo-BLT submodule first.\n"
+    return 1
+  else
+    printInfo "entering compiler setup\n"
+    if [ -z "$LOG_FILE" ]; then
+      $compilerscriptfile --noinfo
+    else
+      $compilerscriptfile --LOG="$LOG_FILE" --noinfo
+    fi
+    return 0
+  fi
+}
+
+### enter IDE setup ############################################################
+# Enter IDE setup.
+#
+# usage:      ideSetup
+# arguments:  n/a
+# return:     n/a
+#
+function ideSetup {
+  printInfo "entering IDE setup\n"
+  printf "\n"
+  if [ -z $LOG_FILE ]; then
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/tools/ide/idesetup.sh --noinfo
+  else
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/tools/ide/idesetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
+
+### main function of this script ###############################################
+# Provides functions for project initialization, configuration of IDE and
+# compiler setup, as well as entry points to the several Git submodules.
+#
+# usage:      see function printHelp
+# arguments:  see function printHelp
+# return:     0
+#                 No error or warning occurred.
+#
+function main {
+  # print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  printf "\n"
+
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
+
+  # set log file if specified
+  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
+    # get the parameter (file name)
+    local cmdidx=1
+    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
+      cmdidx=$[cmdidx + 1]
+    done
+    local cmd="${!cmdidx}"
+    local logfile=""
+    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
+      logfile=${cmd#*=}
+    else
+      local filenameidx=$((cmdidx + 1))
+      logfile="${!filenameidx}"
+    fi
+    # optionally force silent appending
+    if [[ "$cmd" = "--LOG"* ]]; then
+      setLogFile --option=c --quiet "$logfile" LOG_FILE
+    else
+      setLogFile "$logfile" LOG_FILE
+      printf "\n"
+    fi
+  fi
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -i|--init)
+           projectInitialization; printf "\n"; shift 1;;
+        -k|--kernel)
+           kernelSetup; printf "\n"; shift 1;;
+        -b|--bootloader)
+           bootloaderSetup; printf "\n"; shift 1;;
+        -p|--periphery-LLD)
+           peripheryLldSetup; printf "\n"; shift 1;;
+        -c|--compiler)
+           compilerSetup; printf "\n"; shift 1;;
+        --IDE)
+           ideSetup; printf "\n"; shift 1;;
+        -q|--quit)
+          quitScript; shift 1;;
+        --log=*|--LOG=*) # already handled; ignore
+          shift 1;;
+        --log|--LOG) # already handled; ignore
+          shift 2;;
+        --noinfo) # already handled; ignore
+          shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "AMiRo-OS main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [I] - project initialization\n"
+    printf "  [K] - enter kernel setup\n"
+    printf "  [B] - enter bootloaders setup\n"
+    printf "  [P] - enter periphery-LLD setup\n"
+    printf "  [C] - enter compiler setup\n"
+    printf "  [E] - enter IDE project setup\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "IiKkBbPpCcEeQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      I|i)
+        projectInitialization; printf "\n";;
+      K|k)
+        kernelSetup; printf "\n";;
+      B|b)
+        bootloaderSetup; printf "\n";;
+      P|p)
+        peripheryLldSetup; printf "\n";;
+      C|c)
+        compilerSetup; printf "\n";;
+      E|e)
+        ideSetup; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
diff --git a/stubs.c b/stubs.c
deleted file mode 100644
index f0b9564..0000000
--- a/stubs.c
+++ /dev/null
@@ -1,26 +0,0 @@
-#include <errno.h>
-#undef errno
-extern int errno;
-
-/* libc stub */
-__attribute__((used)) void *__dso_handle = 0;
-
-/* libc stub */
-__attribute__((used)) int _getpid(void) {
-  return 1;
-}
-
-/* libc stub */
-__attribute__((used)) void _exit(int i) {
-  (void)i;
-  while(1);
-}
-
-/* libc stub */
-
-__attribute__((used)) int _kill(int pid, int sig) {
-  (void)pid;
-  (void)sig;
-  errno = EINVAL;
-  return -1;
-}
diff --git a/tools/cpplint/checkOS.sh b/tools/cpplint/checkOS.sh
new file mode 100755
index 0000000..a3d2baa
--- /dev/null
+++ b/tools/cpplint/checkOS.sh
@@ -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/>.        #
+#                                                                              #
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+# initial info text
+printf "######################################################################\n"
+printf "#                                                                    #\n"
+printf "#              Welcome to the AMiRo-OS CppLint checker               #\n"
+printf "#                                                                    #\n"
+printf "######################################################################\n"
+printf "#                                                                    #\n"
+printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+printf "#                                                                    #\n"
+printf "# This is free software; see the source for copying conditions.      #\n"
+printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+printf "# Excellence Initiative.                                             #\n"
+printf "#                                                                    #\n"
+printf "######################################################################\n"
+printf "\n"
+
+# print note
+printf "\n"
+printf "NOTE: This tool is rather a preview and was not optimized nor tested!\n"
+printf "      Expect bugs and other issues.\n"
+printf "\n"
+
+# check the OS
+ROOT_PATH="../../"
+read -p "root path:   " -i "$ROOT_PATH" -e ROOT_PATH
+read -p "output file: " -e OUTPUT_FILE
+
+if [ -z "$OUTPUT_FILE" ]; then
+  OUTPUT=""
+else
+  OUTPUT="2> ${OUTPUT_FILE}"
+fi
+
+python/cpplint.py --linelength=120 --extensions=h,c,hpp,cpp `find ${ROOT_PATH} \( -iname "*.h" -o -iname "*-c" -o -iname "*.hpp" -o -iname "*.cpp" \) -follow -type f -print` ${OUTPUT}
+
+unset ROOT_PATH
+unset OUTPUT_FILE
+unset OUTPUT
diff --git a/tools/cpplint/python/README b/tools/cpplint/python/README
new file mode 100644
index 0000000..a7735b7
--- /dev/null
+++ b/tools/cpplint/python/README
@@ -0,0 +1,45 @@
+This is automated checker to make sure a C++ file follows Google's C++ style
+guide (http://google.github.io/styleguide/cppguide.html). As it
+heavily relies on regular expressions, cpplint.py won't catch all violations of
+the style guide and will very occasionally report a false positive. There is a
+list of things we currently don't handle very well at the top of cpplint.py,
+and we welcome patches to improve it.
+
+The linting tool takes a list of files as input. For full usage instructions,
+please see the output of:
+
+  ./cpplint.py --help
+
+Unit tests are provided in cpplint_unittest.py. This file can safely be ignored
+by end users who have downloaded this package and only want to run the lint
+tool.
+
+---
+
+cpplint.py and its corresponding unit tests are Copyright (C) 2009 Google Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/cpplint/python/cpplint.py b/tools/cpplint/python/cpplint.py
new file mode 100755
index 0000000..ccc25d4
--- /dev/null
+++ b/tools/cpplint/python/cpplint.py
@@ -0,0 +1,6323 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#    * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Does google-lint on c++ files.
+
+The goal of this script is to identify places in the code that *may*
+be in non-compliance with google style.  It does not attempt to fix
+up these problems -- the point is to educate.  It does also not
+attempt to find all problems, or to ensure that everything it does
+find is legitimately a problem.
+
+In particular, we can get very confused by /* and // inside strings!
+We do a small hack, which is to ignore //'s with "'s after them on the
+same line, but it is far from perfect (in either direction).
+"""
+
+import codecs
+import copy
+import getopt
+import math  # for log
+import os
+import re
+import sre_compile
+import string
+import sys
+import unicodedata
+
+
+_USAGE = """
+Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
+                   [--counting=total|toplevel|detailed] [--root=subdir]
+                   [--linelength=digits]
+        <file> [file] ...
+
+  The style guidelines this tries to follow are those in
+    http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
+
+  Every problem is given a confidence score from 1-5, with 5 meaning we are
+  certain of the problem, and 1 meaning it could be a legitimate construct.
+  This will miss some errors, and is not a substitute for a code review.
+
+  To suppress false-positive errors of a certain category, add a
+  'NOLINT(category)' comment to the line.  NOLINT or NOLINT(*)
+  suppresses errors of all categories on that line.
+
+  The files passed in will be linted; at least one file must be provided.
+  Default linted extensions are .cc, .cpp, .cu, .cuh and .h.  Change the
+  extensions with the --extensions flag.
+
+  Flags:
+
+    output=vs7
+      By default, the output is formatted to ease emacs parsing.  Visual Studio
+      compatible output (vs7) may also be used.  Other formats are unsupported.
+
+    verbose=#
+      Specify a number 0-5 to restrict errors to certain verbosity levels.
+
+    filter=-x,+y,...
+      Specify a comma-separated list of category-filters to apply: only
+      error messages whose category names pass the filters will be printed.
+      (Category names are printed with the message and look like
+      "[whitespace/indent]".)  Filters are evaluated left to right.
+      "-FOO" and "FOO" means "do not print categories that start with FOO".
+      "+FOO" means "do print categories that start with FOO".
+
+      Examples: --filter=-whitespace,+whitespace/braces
+                --filter=whitespace,runtime/printf,+runtime/printf_format
+                --filter=-,+build/include_what_you_use
+
+      To see a list of all the categories used in cpplint, pass no arg:
+         --filter=
+
+    counting=total|toplevel|detailed
+      The total number of errors found is always printed. If
+      'toplevel' is provided, then the count of errors in each of
+      the top-level categories like 'build' and 'whitespace' will
+      also be printed. If 'detailed' is provided, then a count
+      is provided for each category like 'build/class'.
+
+    root=subdir
+      The root directory used for deriving header guard CPP variable.
+      By default, the header guard CPP variable is calculated as the relative
+      path to the directory that contains .git, .hg, or .svn.  When this flag
+      is specified, the relative path is calculated from the specified
+      directory. If the specified directory does not exist, this flag is
+      ignored.
+
+      Examples:
+        Assuming that src/.git exists, the header guard CPP variables for
+        src/chrome/browser/ui/browser.h are:
+
+        No flag => CHROME_BROWSER_UI_BROWSER_H_
+        --root=chrome => BROWSER_UI_BROWSER_H_
+        --root=chrome/browser => UI_BROWSER_H_
+
+    linelength=digits
+      This is the allowed line length for the project. The default value is
+      80 characters.
+
+      Examples:
+        --linelength=120
+
+    extensions=extension,extension,...
+      The allowed file extensions that cpplint will check
+
+      Examples:
+        --extensions=hpp,cpp
+
+    cpplint.py supports per-directory configurations specified in CPPLINT.cfg
+    files. CPPLINT.cfg file can contain a number of key=value pairs.
+    Currently the following options are supported:
+
+      set noparent
+      filter=+filter1,-filter2,...
+      exclude_files=regex
+      linelength=80
+
+    "set noparent" option prevents cpplint from traversing directory tree
+    upwards looking for more .cfg files in parent directories. This option
+    is usually placed in the top-level project directory.
+
+    The "filter" option is similar in function to --filter flag. It specifies
+    message filters in addition to the |_DEFAULT_FILTERS| and those specified
+    through --filter command-line flag.
+
+    "exclude_files" allows to specify a regular expression to be matched against
+    a file name. If the expression matches, the file is skipped and not run
+    through liner.
+
+    "linelength" allows to specify the allowed line length for the project.
+
+    CPPLINT.cfg has an effect on files in the same directory and all
+    sub-directories, unless overridden by a nested configuration file.
+
+      Example file:
+        filter=-build/include_order,+build/include_alpha
+        exclude_files=.*\.cc
+
+    The above example disables build/include_order warning and enables
+    build/include_alpha as well as excludes all .cc from being
+    processed by linter, in the current directory (where the .cfg
+    file is located) and all sub-directories.
+"""
+
+# We categorize each error message we print.  Here are the categories.
+# We want an explicit list so we can list them all in cpplint --filter=.
+# If you add a new error message with a new category, add it to the list
+# here!  cpplint_unittest.py should tell you if you forget to do this.
+_ERROR_CATEGORIES = [
+    'build/class',
+    'build/c++11',
+    'build/deprecated',
+    'build/endif_comment',
+    'build/explicit_make_pair',
+    'build/forward_decl',
+    'build/header_guard',
+    'build/include',
+    'build/include_alpha',
+    'build/include_order',
+    'build/include_what_you_use',
+    'build/namespaces',
+    'build/printf_format',
+    'build/storage_class',
+    'legal/copyright',
+    'readability/alt_tokens',
+    'readability/braces',
+    'readability/casting',
+    'readability/check',
+    'readability/constructors',
+    'readability/fn_size',
+    'readability/function',
+    'readability/inheritance',
+    'readability/multiline_comment',
+    'readability/multiline_string',
+    'readability/namespace',
+    'readability/nolint',
+    'readability/nul',
+    'readability/strings',
+    'readability/todo',
+    'readability/utf8',
+    'runtime/arrays',
+    'runtime/casting',
+    'runtime/explicit',
+    'runtime/int',
+    'runtime/init',
+    'runtime/invalid_increment',
+    'runtime/member_string_references',
+    'runtime/memset',
+    'runtime/indentation_namespace',
+    'runtime/operator',
+    'runtime/printf',
+    'runtime/printf_format',
+    'runtime/references',
+    'runtime/string',
+    'runtime/threadsafe_fn',
+    'runtime/vlog',
+    'whitespace/blank_line',
+    'whitespace/braces',
+    'whitespace/comma',
+    'whitespace/comments',
+    'whitespace/empty_conditional_body',
+    'whitespace/empty_loop_body',
+    'whitespace/end_of_line',
+    'whitespace/ending_newline',
+    'whitespace/forcolon',
+    'whitespace/indent',
+    'whitespace/line_length',
+    'whitespace/newline',
+    'whitespace/operators',
+    'whitespace/parens',
+    'whitespace/semicolon',
+    'whitespace/tab',
+    'whitespace/todo',
+    ]
+
+# These error categories are no longer enforced by cpplint, but for backwards-
+# compatibility they may still appear in NOLINT comments.
+_LEGACY_ERROR_CATEGORIES = [
+    'readability/streams',
+    ]
+
+# The default state of the category filter. This is overridden by the --filter=
+# flag. By default all errors are on, so only add here categories that should be
+# off by default (i.e., categories that must be enabled by the --filter= flags).
+# All entries here should start with a '-' or '+', as in the --filter= flag.
+_DEFAULT_FILTERS = ['-build/include_alpha']
+
+# We used to check for high-bit characters, but after much discussion we
+# decided those were OK, as long as they were in UTF-8 and didn't represent
+# hard-coded international strings, which belong in a separate i18n file.
+
+# C++ headers
+_CPP_HEADERS = frozenset([
+    # Legacy
+    'algobase.h',
+    'algo.h',
+    'alloc.h',
+    'builtinbuf.h',
+    'bvector.h',
+    'complex.h',
+    'defalloc.h',
+    'deque.h',
+    'editbuf.h',
+    'fstream.h',
+    'function.h',
+    'hash_map',
+    'hash_map.h',
+    'hash_set',
+    'hash_set.h',
+    'hashtable.h',
+    'heap.h',
+    'indstream.h',
+    'iomanip.h',
+    'iostream.h',
+    'istream.h',
+    'iterator.h',
+    'list.h',
+    'map.h',
+    'multimap.h',
+    'multiset.h',
+    'ostream.h',
+    'pair.h',
+    'parsestream.h',
+    'pfstream.h',
+    'procbuf.h',
+    'pthread_alloc',
+    'pthread_alloc.h',
+    'rope',
+    'rope.h',
+    'ropeimpl.h',
+    'set.h',
+    'slist',
+    'slist.h',
+    'stack.h',
+    'stdiostream.h',
+    'stl_alloc.h',
+    'stl_relops.h',
+    'streambuf.h',
+    'stream.h',
+    'strfile.h',
+    'strstream.h',
+    'tempbuf.h',
+    'tree.h',
+    'type_traits.h',
+    'vector.h',
+    # 17.6.1.2 C++ library headers
+    'algorithm',
+    'array',
+    'atomic',
+    'bitset',
+    'chrono',
+    'codecvt',
+    'complex',
+    'condition_variable',
+    'deque',
+    'exception',
+    'forward_list',
+    'fstream',
+    'functional',
+    'future',
+    'initializer_list',
+    'iomanip',
+    'ios',
+    'iosfwd',
+    'iostream',
+    'istream',
+    'iterator',
+    'limits',
+    'list',
+    'locale',
+    'map',
+    'memory',
+    'mutex',
+    'new',
+    'numeric',
+    'ostream',
+    'queue',
+    'random',
+    'ratio',
+    'regex',
+    'set',
+    'sstream',
+    'stack',
+    'stdexcept',
+    'streambuf',
+    'string',
+    'strstream',
+    'system_error',
+    'thread',
+    'tuple',
+    'typeindex',
+    'typeinfo',
+    'type_traits',
+    'unordered_map',
+    'unordered_set',
+    'utility',
+    'valarray',
+    'vector',
+    # 17.6.1.2 C++ headers for C library facilities
+    'cassert',
+    'ccomplex',
+    'cctype',
+    'cerrno',
+    'cfenv',
+    'cfloat',
+    'cinttypes',
+    'ciso646',
+    'climits',
+    'clocale',
+    'cmath',
+    'csetjmp',
+    'csignal',
+    'cstdalign',
+    'cstdarg',
+    'cstdbool',
+    'cstddef',
+    'cstdint',
+    'cstdio',
+    'cstdlib',
+    'cstring',
+    'ctgmath',
+    'ctime',
+    'cuchar',
+    'cwchar',
+    'cwctype',
+    ])
+
+
+# These headers are excluded from [build/include] and [build/include_order]
+# checks:
+# - Anything not following google file name conventions (containing an
+#   uppercase character, such as Python.h or nsStringAPI.h, for example).
+# - Lua headers.
+_THIRD_PARTY_HEADERS_PATTERN = re.compile(
+    r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$')
+
+
+# Assertion macros.  These are defined in base/logging.h and
+# testing/base/gunit.h.  Note that the _M versions need to come first
+# for substring matching to work.
+_CHECK_MACROS = [
+    'DCHECK', 'CHECK',
+    'EXPECT_TRUE_M', 'EXPECT_TRUE',
+    'ASSERT_TRUE_M', 'ASSERT_TRUE',
+    'EXPECT_FALSE_M', 'EXPECT_FALSE',
+    'ASSERT_FALSE_M', 'ASSERT_FALSE',
+    ]
+
+# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
+_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
+
+for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
+                        ('>=', 'GE'), ('>', 'GT'),
+                        ('<=', 'LE'), ('<', 'LT')]:
+  _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
+  _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
+  _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
+  _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
+  _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
+  _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
+
+for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
+                            ('>=', 'LT'), ('>', 'LE'),
+                            ('<=', 'GT'), ('<', 'GE')]:
+  _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
+  _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
+  _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
+  _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
+
+# Alternative tokens and their replacements.  For full list, see section 2.5
+# Alternative tokens [lex.digraph] in the C++ standard.
+#
+# Digraphs (such as '%:') are not included here since it's a mess to
+# match those on a word boundary.
+_ALT_TOKEN_REPLACEMENT = {
+    'and': '&&',
+    'bitor': '|',
+    'or': '||',
+    'xor': '^',
+    'compl': '~',
+    'bitand': '&',
+    'and_eq': '&=',
+    'or_eq': '|=',
+    'xor_eq': '^=',
+    'not': '!',
+    'not_eq': '!='
+    }
+
+# Compile regular expression that matches all the above keywords.  The "[ =()]"
+# bit is meant to avoid matching these keywords outside of boolean expressions.
+#
+# False positives include C-style multi-line comments and multi-line strings
+# but those have always been troublesome for cpplint.
+_ALT_TOKEN_REPLACEMENT_PATTERN = re.compile(
+    r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)')
+
+
+# These constants define types of headers for use with
+# _IncludeState.CheckNextIncludeOrder().
+_C_SYS_HEADER = 1
+_CPP_SYS_HEADER = 2
+_LIKELY_MY_HEADER = 3
+_POSSIBLE_MY_HEADER = 4
+_OTHER_HEADER = 5
+
+# These constants define the current inline assembly state
+_NO_ASM = 0       # Outside of inline assembly block
+_INSIDE_ASM = 1   # Inside inline assembly block
+_END_ASM = 2      # Last line of inline assembly block
+_BLOCK_ASM = 3    # The whole block is an inline assembly block
+
+# Match start of assembly blocks
+_MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)'
+                        r'(?:\s+(volatile|__volatile__))?'
+                        r'\s*[{(]')
+
+
+_regexp_compile_cache = {}
+
+# {str, set(int)}: a map from error categories to sets of linenumbers
+# on which those errors are expected and should be suppressed.
+_error_suppressions = {}
+
+# The root directory used for deriving header guard CPP variable.
+# This is set by --root flag.
+_root = None
+
+# The allowed line length of files.
+# This is set by --linelength flag.
+_line_length = 80
+
+# The allowed extensions for file names
+# This is set by --extensions flag.
+_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh'])
+
+def ParseNolintSuppressions(filename, raw_line, linenum, error):
+  """Updates the global list of error-suppressions.
+
+  Parses any NOLINT comments on the current line, updating the global
+  error_suppressions store.  Reports an error if the NOLINT comment
+  was malformed.
+
+  Args:
+    filename: str, the name of the input file.
+    raw_line: str, the line of input text, with comments.
+    linenum: int, the number of the current line.
+    error: function, an error handler.
+  """
+  matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line)
+  if matched:
+    if matched.group(1):
+      suppressed_line = linenum + 1
+    else:
+      suppressed_line = linenum
+    category = matched.group(2)
+    if category in (None, '(*)'):  # => "suppress all"
+      _error_suppressions.setdefault(None, set()).add(suppressed_line)
+    else:
+      if category.startswith('(') and category.endswith(')'):
+        category = category[1:-1]
+        if category in _ERROR_CATEGORIES:
+          _error_suppressions.setdefault(category, set()).add(suppressed_line)
+        elif category not in _LEGACY_ERROR_CATEGORIES:
+          error(filename, linenum, 'readability/nolint', 5,
+                'Unknown NOLINT error category: %s' % category)
+
+
+def ResetNolintSuppressions():
+  """Resets the set of NOLINT suppressions to empty."""
+  _error_suppressions.clear()
+
+
+def IsErrorSuppressedByNolint(category, linenum):
+  """Returns true if the specified error category is suppressed on this line.
+
+  Consults the global error_suppressions map populated by
+  ParseNolintSuppressions/ResetNolintSuppressions.
+
+  Args:
+    category: str, the category of the error.
+    linenum: int, the current line number.
+  Returns:
+    bool, True iff the error should be suppressed due to a NOLINT comment.
+  """
+  return (linenum in _error_suppressions.get(category, set()) or
+          linenum in _error_suppressions.get(None, set()))
+
+
+def Match(pattern, s):
+  """Matches the string with the pattern, caching the compiled regexp."""
+  # The regexp compilation caching is inlined in both Match and Search for
+  # performance reasons; factoring it out into a separate function turns out
+  # to be noticeably expensive.
+  if pattern not in _regexp_compile_cache:
+    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+  return _regexp_compile_cache[pattern].match(s)
+
+
+def ReplaceAll(pattern, rep, s):
+  """Replaces instances of pattern in a string with a replacement.
+
+  The compiled regex is kept in a cache shared by Match and Search.
+
+  Args:
+    pattern: regex pattern
+    rep: replacement text
+    s: search string
+
+  Returns:
+    string with replacements made (or original string if no replacements)
+  """
+  if pattern not in _regexp_compile_cache:
+    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+  return _regexp_compile_cache[pattern].sub(rep, s)
+
+
+def Search(pattern, s):
+  """Searches the string for the pattern, caching the compiled regexp."""
+  if pattern not in _regexp_compile_cache:
+    _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+  return _regexp_compile_cache[pattern].search(s)
+
+
+class _IncludeState(object):
+  """Tracks line numbers for includes, and the order in which includes appear.
+
+  include_list contains list of lists of (header, line number) pairs.
+  It's a lists of lists rather than just one flat list to make it
+  easier to update across preprocessor boundaries.
+
+  Call CheckNextIncludeOrder() once for each header in the file, passing
+  in the type constants defined above. Calls in an illegal order will
+  raise an _IncludeError with an appropriate error message.
+
+  """
+  # self._section will move monotonically through this set. If it ever
+  # needs to move backwards, CheckNextIncludeOrder will raise an error.
+  _INITIAL_SECTION = 0
+  _MY_H_SECTION = 1
+  _C_SECTION = 2
+  _CPP_SECTION = 3
+  _OTHER_H_SECTION = 4
+
+  _TYPE_NAMES = {
+      _C_SYS_HEADER: 'C system header',
+      _CPP_SYS_HEADER: 'C++ system header',
+      _LIKELY_MY_HEADER: 'header this file implements',
+      _POSSIBLE_MY_HEADER: 'header this file may implement',
+      _OTHER_HEADER: 'other header',
+      }
+  _SECTION_NAMES = {
+      _INITIAL_SECTION: "... nothing. (This can't be an error.)",
+      _MY_H_SECTION: 'a header this file implements',
+      _C_SECTION: 'C system header',
+      _CPP_SECTION: 'C++ system header',
+      _OTHER_H_SECTION: 'other header',
+      }
+
+  def __init__(self):
+    self.include_list = [[]]
+    self.ResetSection('')
+
+  def FindHeader(self, header):
+    """Check if a header has already been included.
+
+    Args:
+      header: header to check.
+    Returns:
+      Line number of previous occurrence, or -1 if the header has not
+      been seen before.
+    """
+    for section_list in self.include_list:
+      for f in section_list:
+        if f[0] == header:
+          return f[1]
+    return -1
+
+  def ResetSection(self, directive):
+    """Reset section checking for preprocessor directive.
+
+    Args:
+      directive: preprocessor directive (e.g. "if", "else").
+    """
+    # The name of the current section.
+    self._section = self._INITIAL_SECTION
+    # The path of last found header.
+    self._last_header = ''
+
+    # Update list of includes.  Note that we never pop from the
+    # include list.
+    if directive in ('if', 'ifdef', 'ifndef'):
+      self.include_list.append([])
+    elif directive in ('else', 'elif'):
+      self.include_list[-1] = []
+
+  def SetLastHeader(self, header_path):
+    self._last_header = header_path
+
+  def CanonicalizeAlphabeticalOrder(self, header_path):
+    """Returns a path canonicalized for alphabetical comparison.
+
+    - replaces "-" with "_" so they both cmp the same.
+    - removes '-inl' since we don't require them to be after the main header.
+    - lowercase everything, just in case.
+
+    Args:
+      header_path: Path to be canonicalized.
+
+    Returns:
+      Canonicalized path.
+    """
+    return header_path.replace('-inl.h', '.h').replace('-', '_').lower()
+
+  def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path):
+    """Check if a header is in alphabetical order with the previous header.
+
+    Args:
+      clean_lines: A CleansedLines instance containing the file.
+      linenum: The number of the line to check.
+      header_path: Canonicalized header to be checked.
+
+    Returns:
+      Returns true if the header is in alphabetical order.
+    """
+    # If previous section is different from current section, _last_header will
+    # be reset to empty string, so it's always less than current header.
+    #
+    # If previous line was a blank line, assume that the headers are
+    # intentionally sorted the way they are.
+    if (self._last_header > header_path and
+        Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])):
+      return False
+    return True
+
+  def CheckNextIncludeOrder(self, header_type):
+    """Returns a non-empty error message if the next header is out of order.
+
+    This function also updates the internal state to be ready to check
+    the next include.
+
+    Args:
+      header_type: One of the _XXX_HEADER constants defined above.
+
+    Returns:
+      The empty string if the header is in the right order, or an
+      error message describing what's wrong.
+
+    """
+    error_message = ('Found %s after %s' %
+                     (self._TYPE_NAMES[header_type],
+                      self._SECTION_NAMES[self._section]))
+
+    last_section = self._section
+
+    if header_type == _C_SYS_HEADER:
+      if self._section <= self._C_SECTION:
+        self._section = self._C_SECTION
+      else:
+        self._last_header = ''
+        return error_message
+    elif header_type == _CPP_SYS_HEADER:
+      if self._section <= self._CPP_SECTION:
+        self._section = self._CPP_SECTION
+      else:
+        self._last_header = ''
+        return error_message
+    elif header_type == _LIKELY_MY_HEADER:
+      if self._section <= self._MY_H_SECTION:
+        self._section = self._MY_H_SECTION
+      else:
+        self._section = self._OTHER_H_SECTION
+    elif header_type == _POSSIBLE_MY_HEADER:
+      if self._section <= self._MY_H_SECTION:
+        self._section = self._MY_H_SECTION
+      else:
+        # This will always be the fallback because we're not sure
+        # enough that the header is associated with this file.
+        self._section = self._OTHER_H_SECTION
+    else:
+      assert header_type == _OTHER_HEADER
+      self._section = self._OTHER_H_SECTION
+
+    if last_section != self._section:
+      self._last_header = ''
+
+    return ''
+
+
+class _CppLintState(object):
+  """Maintains module-wide state.."""
+
+  def __init__(self):
+    self.verbose_level = 1  # global setting.
+    self.error_count = 0    # global count of reported errors
+    # filters to apply when emitting error messages
+    self.filters = _DEFAULT_FILTERS[:]
+    # backup of filter list. Used to restore the state after each file.
+    self._filters_backup = self.filters[:]
+    self.counting = 'total'  # In what way are we counting errors?
+    self.errors_by_category = {}  # string to int dict storing error counts
+
+    # output format:
+    # "emacs" - format that emacs can parse (default)
+    # "vs7" - format that Microsoft Visual Studio 7 can parse
+    self.output_format = 'emacs'
+
+  def SetOutputFormat(self, output_format):
+    """Sets the output format for errors."""
+    self.output_format = output_format
+
+  def SetVerboseLevel(self, level):
+    """Sets the module's verbosity, and returns the previous setting."""
+    last_verbose_level = self.verbose_level
+    self.verbose_level = level
+    return last_verbose_level
+
+  def SetCountingStyle(self, counting_style):
+    """Sets the module's counting options."""
+    self.counting = counting_style
+
+  def SetFilters(self, filters):
+    """Sets the error-message filters.
+
+    These filters are applied when deciding whether to emit a given
+    error message.
+
+    Args:
+      filters: A string of comma-separated filters (eg "+whitespace/indent").
+               Each filter should start with + or -; else we die.
+
+    Raises:
+      ValueError: The comma-separated filters did not all start with '+' or '-'.
+                  E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter"
+    """
+    # Default filters always have less priority than the flag ones.
+    self.filters = _DEFAULT_FILTERS[:]
+    self.AddFilters(filters)
+
+  def AddFilters(self, filters):
+    """ Adds more filters to the existing list of error-message filters. """
+    for filt in filters.split(','):
+      clean_filt = filt.strip()
+      if clean_filt:
+        self.filters.append(clean_filt)
+    for filt in self.filters:
+      if not (filt.startswith('+') or filt.startswith('-')):
+        raise ValueError('Every filter in --filters must start with + or -'
+                         ' (%s does not)' % filt)
+
+  def BackupFilters(self):
+    """ Saves the current filter list to backup storage."""
+    self._filters_backup = self.filters[:]
+
+  def RestoreFilters(self):
+    """ Restores filters previously backed up."""
+    self.filters = self._filters_backup[:]
+
+  def ResetErrorCounts(self):
+    """Sets the module's error statistic back to zero."""
+    self.error_count = 0
+    self.errors_by_category = {}
+
+  def IncrementErrorCount(self, category):
+    """Bumps the module's error statistic."""
+    self.error_count += 1
+    if self.counting in ('toplevel', 'detailed'):
+      if self.counting != 'detailed':
+        category = category.split('/')[0]
+      if category not in self.errors_by_category:
+        self.errors_by_category[category] = 0
+      self.errors_by_category[category] += 1
+
+  def PrintErrorCounts(self):
+    """Print a summary of errors by category, and the total."""
+    for category, count in self.errors_by_category.iteritems():
+      sys.stderr.write('Category \'%s\' errors found: %d\n' %
+                       (category, count))
+    sys.stderr.write('Total errors found: %d\n' % self.error_count)
+
+_cpplint_state = _CppLintState()
+
+
+def _OutputFormat():
+  """Gets the module's output format."""
+  return _cpplint_state.output_format
+
+
+def _SetOutputFormat(output_format):
+  """Sets the module's output format."""
+  _cpplint_state.SetOutputFormat(output_format)
+
+
+def _VerboseLevel():
+  """Returns the module's verbosity setting."""
+  return _cpplint_state.verbose_level
+
+
+def _SetVerboseLevel(level):
+  """Sets the module's verbosity, and returns the previous setting."""
+  return _cpplint_state.SetVerboseLevel(level)
+
+
+def _SetCountingStyle(level):
+  """Sets the module's counting options."""
+  _cpplint_state.SetCountingStyle(level)
+
+
+def _Filters():
+  """Returns the module's list of output filters, as a list."""
+  return _cpplint_state.filters
+
+
+def _SetFilters(filters):
+  """Sets the module's error-message filters.
+
+  These filters are applied when deciding whether to emit a given
+  error message.
+
+  Args:
+    filters: A string of comma-separated filters (eg "whitespace/indent").
+             Each filter should start with + or -; else we die.
+  """
+  _cpplint_state.SetFilters(filters)
+
+def _AddFilters(filters):
+  """Adds more filter overrides.
+
+  Unlike _SetFilters, this function does not reset the current list of filters
+  available.
+
+  Args:
+    filters: A string of comma-separated filters (eg "whitespace/indent").
+             Each filter should start with + or -; else we die.
+  """
+  _cpplint_state.AddFilters(filters)
+
+def _BackupFilters():
+  """ Saves the current filter list to backup storage."""
+  _cpplint_state.BackupFilters()
+
+def _RestoreFilters():
+  """ Restores filters previously backed up."""
+  _cpplint_state.RestoreFilters()
+
+class _FunctionState(object):
+  """Tracks current function name and the number of lines in its body."""
+
+  _NORMAL_TRIGGER = 250  # for --v=0, 500 for --v=1, etc.
+  _TEST_TRIGGER = 400    # about 50% more than _NORMAL_TRIGGER.
+
+  def __init__(self):
+    self.in_a_function = False
+    self.lines_in_function = 0
+    self.current_function = ''
+
+  def Begin(self, function_name):
+    """Start analyzing function body.
+
+    Args:
+      function_name: The name of the function being tracked.
+    """
+    self.in_a_function = True
+    self.lines_in_function = 0
+    self.current_function = function_name
+
+  def Count(self):
+    """Count line in current function body."""
+    if self.in_a_function:
+      self.lines_in_function += 1
+
+  def Check(self, error, filename, linenum):
+    """Report if too many lines in function body.
+
+    Args:
+      error: The function to call with any errors found.
+      filename: The name of the current file.
+      linenum: The number of the line to check.
+    """
+    if Match(r'T(EST|est)', self.current_function):
+      base_trigger = self._TEST_TRIGGER
+    else:
+      base_trigger = self._NORMAL_TRIGGER
+    trigger = base_trigger * 2**_VerboseLevel()
+
+    if self.lines_in_function > trigger:
+      error_level = int(math.log(self.lines_in_function / base_trigger, 2))
+      # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
+      if error_level > 5:
+        error_level = 5
+      error(filename, linenum, 'readability/fn_size', error_level,
+            'Small and focused functions are preferred:'
+            ' %s has %d non-comment lines'
+            ' (error triggered by exceeding %d lines).'  % (
+                self.current_function, self.lines_in_function, trigger))
+
+  def End(self):
+    """Stop analyzing function body."""
+    self.in_a_function = False
+
+
+class _IncludeError(Exception):
+  """Indicates a problem with the include order in a file."""
+  pass
+
+
+class FileInfo(object):
+  """Provides utility functions for filenames.
+
+  FileInfo provides easy access to the components of a file's path
+  relative to the project root.
+  """
+
+  def __init__(self, filename):
+    self._filename = filename
+
+  def FullName(self):
+    """Make Windows paths like Unix."""
+    return os.path.abspath(self._filename).replace('\\', '/')
+
+  def RepositoryName(self):
+    """FullName after removing the local path to the repository.
+
+    If we have a real absolute path name here we can try to do something smart:
+    detecting the root of the checkout and truncating /path/to/checkout from
+    the name so that we get header guards that don't include things like
+    "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+    people on different computers who have checked the source out to different
+    locations won't see bogus errors.
+    """
+    fullname = self.FullName()
+
+    if os.path.exists(fullname):
+      project_dir = os.path.dirname(fullname)
+
+      if os.path.exists(os.path.join(project_dir, ".svn")):
+        # If there's a .svn file in the current directory, we recursively look
+        # up the directory tree for the top of the SVN checkout
+        root_dir = project_dir
+        one_up_dir = os.path.dirname(root_dir)
+        while os.path.exists(os.path.join(one_up_dir, ".svn")):
+          root_dir = os.path.dirname(root_dir)
+          one_up_dir = os.path.dirname(one_up_dir)
+
+        prefix = os.path.commonprefix([root_dir, project_dir])
+        return fullname[len(prefix) + 1:]
+
+      # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by
+      # searching up from the current path.
+      root_dir = os.path.dirname(fullname)
+      while (root_dir != os.path.dirname(root_dir) and
+             not os.path.exists(os.path.join(root_dir, ".git")) and
+             not os.path.exists(os.path.join(root_dir, ".hg")) and
+             not os.path.exists(os.path.join(root_dir, ".svn"))):
+        root_dir = os.path.dirname(root_dir)
+
+      if (os.path.exists(os.path.join(root_dir, ".git")) or
+          os.path.exists(os.path.join(root_dir, ".hg")) or
+          os.path.exists(os.path.join(root_dir, ".svn"))):
+        prefix = os.path.commonprefix([root_dir, project_dir])
+        return fullname[len(prefix) + 1:]
+
+    # Don't know what to do; header guard warnings may be wrong...
+    return fullname
+
+  def Split(self):
+    """Splits the file into the directory, basename, and extension.
+
+    For 'chrome/browser/browser.cc', Split() would
+    return ('chrome/browser', 'browser', '.cc')
+
+    Returns:
+      A tuple of (directory, basename, extension).
+    """
+
+    googlename = self.RepositoryName()
+    project, rest = os.path.split(googlename)
+    return (project,) + os.path.splitext(rest)
+
+  def BaseName(self):
+    """File base name - text after the final slash, before the final period."""
+    return self.Split()[1]
+
+  def Extension(self):
+    """File extension - text following the final period."""
+    return self.Split()[2]
+
+  def NoExtension(self):
+    """File has no source file extension."""
+    return '/'.join(self.Split()[0:2])
+
+  def IsSource(self):
+    """File has a source file extension."""
+    return self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
+
+
+def _ShouldPrintError(category, confidence, linenum):
+  """If confidence >= verbose, category passes filter and is not suppressed."""
+
+  # There are three ways we might decide not to print an error message:
+  # a "NOLINT(category)" comment appears in the source,
+  # the verbosity level isn't high enough, or the filters filter it out.
+  if IsErrorSuppressedByNolint(category, linenum):
+    return False
+
+  if confidence < _cpplint_state.verbose_level:
+    return False
+
+  is_filtered = False
+  for one_filter in _Filters():
+    if one_filter.startswith('-'):
+      if category.startswith(one_filter[1:]):
+        is_filtered = True
+    elif one_filter.startswith('+'):
+      if category.startswith(one_filter[1:]):
+        is_filtered = False
+    else:
+      assert False  # should have been checked for in SetFilter.
+  if is_filtered:
+    return False
+
+  return True
+
+
+def Error(filename, linenum, category, confidence, message):
+  """Logs the fact we've found a lint error.
+
+  We log where the error was found, and also our confidence in the error,
+  that is, how certain we are this is a legitimate style regression, and
+  not a misidentification or a use that's sometimes justified.
+
+  False positives can be suppressed by the use of
+  "cpplint(category)"  comments on the offending line.  These are
+  parsed into _error_suppressions.
+
+  Args:
+    filename: The name of the file containing the error.
+    linenum: The number of the line containing the error.
+    category: A string used to describe the "category" this bug
+      falls under: "whitespace", say, or "runtime".  Categories
+      may have a hierarchy separated by slashes: "whitespace/indent".
+    confidence: A number from 1-5 representing a confidence score for
+      the error, with 5 meaning that we are certain of the problem,
+      and 1 meaning that it could be a legitimate construct.
+    message: The error message.
+  """
+  if _ShouldPrintError(category, confidence, linenum):
+    _cpplint_state.IncrementErrorCount(category)
+    if _cpplint_state.output_format == 'vs7':
+      sys.stderr.write('%s(%s):  %s  [%s] [%d]\n' % (
+          filename, linenum, message, category, confidence))
+    elif _cpplint_state.output_format == 'eclipse':
+      sys.stderr.write('%s:%s: warning: %s  [%s] [%d]\n' % (
+          filename, linenum, message, category, confidence))
+    else:
+      sys.stderr.write('%s:%s:  %s  [%s] [%d]\n' % (
+          filename, linenum, message, category, confidence))
+
+
+# Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard.
+_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
+    r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
+# Match a single C style comment on the same line.
+_RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/'
+# Matches multi-line C style comments.
+# This RE is a little bit more complicated than one might expect, because we
+# have to take care of space removals tools so we can handle comments inside
+# statements better.
+# The current rule is: We only clear spaces from both sides when we're at the
+# end of the line. Otherwise, we try to remove spaces from the right side,
+# if this doesn't work we try on left side but only if there's a non-character
+# on the right.
+_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
+    r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' +
+    _RE_PATTERN_C_COMMENTS + r'\s+|' +
+    r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' +
+    _RE_PATTERN_C_COMMENTS + r')')
+
+
+def IsCppString(line):
+  """Does line terminate so, that the next symbol is in string constant.
+
+  This function does not consider single-line nor multi-line comments.
+
+  Args:
+    line: is a partial line of code starting from the 0..n.
+
+  Returns:
+    True, if next character appended to 'line' is inside a
+    string constant.
+  """
+
+  line = line.replace(r'\\', 'XX')  # after this, \\" does not match to \"
+  return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
+
+
+def CleanseRawStrings(raw_lines):
+  """Removes C++11 raw strings from lines.
+
+    Before:
+      static const char kData[] = R"(
+          multi-line string
+          )";
+
+    After:
+      static const char kData[] = ""
+          (replaced by blank line)
+          "";
+
+  Args:
+    raw_lines: list of raw lines.
+
+  Returns:
+    list of lines with C++11 raw strings replaced by empty strings.
+  """
+
+  delimiter = None
+  lines_without_raw_strings = []
+  for line in raw_lines:
+    if delimiter:
+      # Inside a raw string, look for the end
+      end = line.find(delimiter)
+      if end >= 0:
+        # Found the end of the string, match leading space for this
+        # line and resume copying the original lines, and also insert
+        # a "" on the last line.
+        leading_space = Match(r'^(\s*)\S', line)
+        line = leading_space.group(1) + '""' + line[end + len(delimiter):]
+        delimiter = None
+      else:
+        # Haven't found the end yet, append a blank line.
+        line = '""'
+
+    # Look for beginning of a raw string, and replace them with
+    # empty strings.  This is done in a loop to handle multiple raw
+    # strings on the same line.
+    while delimiter is None:
+      # Look for beginning of a raw string.
+      # See 2.14.15 [lex.string] for syntax.
+      matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line)
+      if matched:
+        delimiter = ')' + matched.group(2) + '"'
+
+        end = matched.group(3).find(delimiter)
+        if end >= 0:
+          # Raw string ended on same line
+          line = (matched.group(1) + '""' +
+                  matched.group(3)[end + len(delimiter):])
+          delimiter = None
+        else:
+          # Start of a multi-line raw string
+          line = matched.group(1) + '""'
+      else:
+        break
+
+    lines_without_raw_strings.append(line)
+
+  # TODO(unknown): if delimiter is not None here, we might want to
+  # emit a warning for unterminated string.
+  return lines_without_raw_strings
+
+
+def FindNextMultiLineCommentStart(lines, lineix):
+  """Find the beginning marker for a multiline comment."""
+  while lineix < len(lines):
+    if lines[lineix].strip().startswith('/*'):
+      # Only return this marker if the comment goes beyond this line
+      if lines[lineix].strip().find('*/', 2) < 0:
+        return lineix
+    lineix += 1
+  return len(lines)
+
+
+def FindNextMultiLineCommentEnd(lines, lineix):
+  """We are inside a comment, find the end marker."""
+  while lineix < len(lines):
+    if lines[lineix].strip().endswith('*/'):
+      return lineix
+    lineix += 1
+  return len(lines)
+
+
+def RemoveMultiLineCommentsFromRange(lines, begin, end):
+  """Clears a range of lines for multi-line comments."""
+  # Having // dummy comments makes the lines non-empty, so we will not get
+  # unnecessary blank line warnings later in the code.
+  for i in range(begin, end):
+    lines[i] = '/**/'
+
+
+def RemoveMultiLineComments(filename, lines, error):
+  """Removes multiline (c-style) comments from lines."""
+  lineix = 0
+  while lineix < len(lines):
+    lineix_begin = FindNextMultiLineCommentStart(lines, lineix)
+    if lineix_begin >= len(lines):
+      return
+    lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin)
+    if lineix_end >= len(lines):
+      error(filename, lineix_begin + 1, 'readability/multiline_comment', 5,
+            'Could not find end of multi-line comment')
+      return
+    RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1)
+    lineix = lineix_end + 1
+
+
+def CleanseComments(line):
+  """Removes //-comments and single-line C-style /* */ comments.
+
+  Args:
+    line: A line of C++ source.
+
+  Returns:
+    The line with single-line comments removed.
+  """
+  commentpos = line.find('//')
+  if commentpos != -1 and not IsCppString(line[:commentpos]):
+    line = line[:commentpos].rstrip()
+  # get rid of /* ... */
+  return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
+
+
+class CleansedLines(object):
+  """Holds 4 copies of all lines with different preprocessing applied to them.
+
+  1) elided member contains lines without strings and comments.
+  2) lines member contains lines without comments.
+  3) raw_lines member contains all the lines without processing.
+  4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw
+     strings removed.
+  All these members are of <type 'list'>, and of the same length.
+  """
+
+  def __init__(self, lines):
+    self.elided = []
+    self.lines = []
+    self.raw_lines = lines
+    self.num_lines = len(lines)
+    self.lines_without_raw_strings = CleanseRawStrings(lines)
+    for linenum in range(len(self.lines_without_raw_strings)):
+      self.lines.append(CleanseComments(
+          self.lines_without_raw_strings[linenum]))
+      elided = self._CollapseStrings(self.lines_without_raw_strings[linenum])
+      self.elided.append(CleanseComments(elided))
+
+  def NumLines(self):
+    """Returns the number of lines represented."""
+    return self.num_lines
+
+  @staticmethod
+  def _CollapseStrings(elided):
+    """Collapses strings and chars on a line to simple "" or '' blocks.
+
+    We nix strings first so we're not fooled by text like '"http://"'
+
+    Args:
+      elided: The line being processed.
+
+    Returns:
+      The line with collapsed strings.
+    """
+    if _RE_PATTERN_INCLUDE.match(elided):
+      return elided
+
+    # Remove escaped characters first to make quote/single quote collapsing
+    # basic.  Things that look like escaped characters shouldn't occur
+    # outside of strings and chars.
+    elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
+
+    # Replace quoted strings and digit separators.  Both single quotes
+    # and double quotes are processed in the same loop, otherwise
+    # nested quotes wouldn't work.
+    collapsed = ''
+    while True:
+      # Find the first quote character
+      match = Match(r'^([^\'"]*)([\'"])(.*)$', elided)
+      if not match:
+        collapsed += elided
+        break
+      head, quote, tail = match.groups()
+
+      if quote == '"':
+        # Collapse double quoted strings
+        second_quote = tail.find('"')
+        if second_quote >= 0:
+          collapsed += head + '""'
+          elided = tail[second_quote + 1:]
+        else:
+          # Unmatched double quote, don't bother processing the rest
+          # of the line since this is probably a multiline string.
+          collapsed += elided
+          break
+      else:
+        # Found single quote, check nearby text to eliminate digit separators.
+        #
+        # There is no special handling for floating point here, because
+        # the integer/fractional/exponent parts would all be parsed
+        # correctly as long as there are digits on both sides of the
+        # separator.  So we are fine as long as we don't see something
+        # like "0.'3" (gcc 4.9.0 will not allow this literal).
+        if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head):
+          match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail)
+          collapsed += head + match_literal.group(1).replace("'", '')
+          elided = match_literal.group(2)
+        else:
+          second_quote = tail.find('\'')
+          if second_quote >= 0:
+            collapsed += head + "''"
+            elided = tail[second_quote + 1:]
+          else:
+            # Unmatched single quote
+            collapsed += elided
+            break
+
+    return collapsed
+
+
+def FindEndOfExpressionInLine(line, startpos, stack):
+  """Find the position just after the end of current parenthesized expression.
+
+  Args:
+    line: a CleansedLines line.
+    startpos: start searching at this position.
+    stack: nesting stack at startpos.
+
+  Returns:
+    On finding matching end: (index just after matching end, None)
+    On finding an unclosed expression: (-1, None)
+    Otherwise: (-1, new stack at end of this line)
+  """
+  for i in xrange(startpos, len(line)):
+    char = line[i]
+    if char in '([{':
+      # Found start of parenthesized expression, push to expression stack
+      stack.append(char)
+    elif char == '<':
+      # Found potential start of template argument list
+      if i > 0 and line[i - 1] == '<':
+        # Left shift operator
+        if stack and stack[-1] == '<':
+          stack.pop()
+          if not stack:
+            return (-1, None)
+      elif i > 0 and Search(r'\boperator\s*$', line[0:i]):
+        # operator<, don't add to stack
+        continue
+      else:
+        # Tentative start of template argument list
+        stack.append('<')
+    elif char in ')]}':
+      # Found end of parenthesized expression.
+      #
+      # If we are currently expecting a matching '>', the pending '<'
+      # must have been an operator.  Remove them from expression stack.
+      while stack and stack[-1] == '<':
+        stack.pop()
+      if not stack:
+        return (-1, None)
+      if ((stack[-1] == '(' and char == ')') or
+          (stack[-1] == '[' and char == ']') or
+          (stack[-1] == '{' and char == '}')):
+        stack.pop()
+        if not stack:
+          return (i + 1, None)
+      else:
+        # Mismatched parentheses
+        return (-1, None)
+    elif char == '>':
+      # Found potential end of template argument list.
+
+      # Ignore "->" and operator functions
+      if (i > 0 and
+          (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))):
+        continue
+
+      # Pop the stack if there is a matching '<'.  Otherwise, ignore
+      # this '>' since it must be an operator.
+      if stack:
+        if stack[-1] == '<':
+          stack.pop()
+          if not stack:
+            return (i + 1, None)
+    elif char == ';':
+      # Found something that look like end of statements.  If we are currently
+      # expecting a '>', the matching '<' must have been an operator, since
+      # template argument list should not contain statements.
+      while stack and stack[-1] == '<':
+        stack.pop()
+      if not stack:
+        return (-1, None)
+
+  # Did not find end of expression or unbalanced parentheses on this line
+  return (-1, stack)
+
+
+def CloseExpression(clean_lines, linenum, pos):
+  """If input points to ( or { or [ or <, finds the position that closes it.
+
+  If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the
+  linenum/pos that correspond to the closing of the expression.
+
+  TODO(unknown): cpplint spends a fair bit of time matching parentheses.
+  Ideally we would want to index all opening and closing parentheses once
+  and have CloseExpression be just a simple lookup, but due to preprocessor
+  tricks, this is not so easy.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    pos: A position on the line.
+
+  Returns:
+    A tuple (line, linenum, pos) pointer *past* the closing brace, or
+    (line, len(lines), -1) if we never find a close.  Note we ignore
+    strings and comments when matching; and the line we return is the
+    'cleansed' line at linenum.
+  """
+
+  line = clean_lines.elided[linenum]
+  if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]):
+    return (line, clean_lines.NumLines(), -1)
+
+  # Check first line
+  (end_pos, stack) = FindEndOfExpressionInLine(line, pos, [])
+  if end_pos > -1:
+    return (line, linenum, end_pos)
+
+  # Continue scanning forward
+  while stack and linenum < clean_lines.NumLines() - 1:
+    linenum += 1
+    line = clean_lines.elided[linenum]
+    (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack)
+    if end_pos > -1:
+      return (line, linenum, end_pos)
+
+  # Did not find end of expression before end of file, give up
+  return (line, clean_lines.NumLines(), -1)
+
+
+def FindStartOfExpressionInLine(line, endpos, stack):
+  """Find position at the matching start of current expression.
+
+  This is almost the reverse of FindEndOfExpressionInLine, but note
+  that the input position and returned position differs by 1.
+
+  Args:
+    line: a CleansedLines line.
+    endpos: start searching at this position.
+    stack: nesting stack at endpos.
+
+  Returns:
+    On finding matching start: (index at matching start, None)
+    On finding an unclosed expression: (-1, None)
+    Otherwise: (-1, new stack at beginning of this line)
+  """
+  i = endpos
+  while i >= 0:
+    char = line[i]
+    if char in ')]}':
+      # Found end of expression, push to expression stack
+      stack.append(char)
+    elif char == '>':
+      # Found potential end of template argument list.
+      #
+      # Ignore it if it's a "->" or ">=" or "operator>"
+      if (i > 0 and
+          (line[i - 1] == '-' or
+           Match(r'\s>=\s', line[i - 1:]) or
+           Search(r'\boperator\s*$', line[0:i]))):
+        i -= 1
+      else:
+        stack.append('>')
+    elif char == '<':
+      # Found potential start of template argument list
+      if i > 0 and line[i - 1] == '<':
+        # Left shift operator
+        i -= 1
+      else:
+        # If there is a matching '>', we can pop the expression stack.
+        # Otherwise, ignore this '<' since it must be an operator.
+        if stack and stack[-1] == '>':
+          stack.pop()
+          if not stack:
+            return (i, None)
+    elif char in '([{':
+      # Found start of expression.
+      #
+      # If there are any unmatched '>' on the stack, they must be
+      # operators.  Remove those.
+      while stack and stack[-1] == '>':
+        stack.pop()
+      if not stack:
+        return (-1, None)
+      if ((char == '(' and stack[-1] == ')') or
+          (char == '[' and stack[-1] == ']') or
+          (char == '{' and stack[-1] == '}')):
+        stack.pop()
+        if not stack:
+          return (i, None)
+      else:
+        # Mismatched parentheses
+        return (-1, None)
+    elif char == ';':
+      # Found something that look like end of statements.  If we are currently
+      # expecting a '<', the matching '>' must have been an operator, since
+      # template argument list should not contain statements.
+      while stack and stack[-1] == '>':
+        stack.pop()
+      if not stack:
+        return (-1, None)
+
+    i -= 1
+
+  return (-1, stack)
+
+
+def ReverseCloseExpression(clean_lines, linenum, pos):
+  """If input points to ) or } or ] or >, finds the position that opens it.
+
+  If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the
+  linenum/pos that correspond to the opening of the expression.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    pos: A position on the line.
+
+  Returns:
+    A tuple (line, linenum, pos) pointer *at* the opening brace, or
+    (line, 0, -1) if we never find the matching opening brace.  Note
+    we ignore strings and comments when matching; and the line we
+    return is the 'cleansed' line at linenum.
+  """
+  line = clean_lines.elided[linenum]
+  if line[pos] not in ')}]>':
+    return (line, 0, -1)
+
+  # Check last line
+  (start_pos, stack) = FindStartOfExpressionInLine(line, pos, [])
+  if start_pos > -1:
+    return (line, linenum, start_pos)
+
+  # Continue scanning backward
+  while stack and linenum > 0:
+    linenum -= 1
+    line = clean_lines.elided[linenum]
+    (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack)
+    if start_pos > -1:
+      return (line, linenum, start_pos)
+
+  # Did not find start of expression before beginning of file, give up
+  return (line, 0, -1)
+
+
+def CheckForCopyright(filename, lines, error):
+  """Logs an error if no Copyright message appears at the top of the file."""
+
+  # We'll say it should occur by line 10. Don't forget there's a
+  # dummy line at the front.
+  for line in xrange(1, min(len(lines), 11)):
+    if re.search(r'Copyright', lines[line], re.I): break
+  else:                       # means no copyright line was found
+    error(filename, 0, 'legal/copyright', 5,
+          'No copyright message found.  '
+          'You should have a line: "Copyright [year] <Copyright Owner>"')
+
+
+def GetIndentLevel(line):
+  """Return the number of leading spaces in line.
+
+  Args:
+    line: A string to check.
+
+  Returns:
+    An integer count of leading spaces, possibly zero.
+  """
+  indent = Match(r'^( *)\S', line)
+  if indent:
+    return len(indent.group(1))
+  else:
+    return 0
+
+
+def GetHeaderGuardCPPVariable(filename):
+  """Returns the CPP variable that should be used as a header guard.
+
+  Args:
+    filename: The name of a C++ header file.
+
+  Returns:
+    The CPP variable that should be used as a header guard in the
+    named file.
+
+  """
+
+  # Restores original filename in case that cpplint is invoked from Emacs's
+  # flymake.
+  filename = re.sub(r'_flymake\.h$', '.h', filename)
+  filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename)
+  # Replace 'c++' with 'cpp'.
+  filename = filename.replace('C++', 'cpp').replace('c++', 'cpp')
+  
+  fileinfo = FileInfo(filename)
+  file_path_from_root = fileinfo.RepositoryName()
+  if _root:
+    file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root)
+  return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_'
+
+
+def CheckForHeaderGuard(filename, clean_lines, error):
+  """Checks that the file contains a header guard.
+
+  Logs an error if no #ifndef header guard is present.  For other
+  headers, checks that the full pathname is used.
+
+  Args:
+    filename: The name of the C++ header file.
+    clean_lines: A CleansedLines instance containing the file.
+    error: The function to call with any errors found.
+  """
+
+  # Don't check for header guards if there are error suppression
+  # comments somewhere in this file.
+  #
+  # Because this is silencing a warning for a nonexistent line, we
+  # only support the very specific NOLINT(build/header_guard) syntax,
+  # and not the general NOLINT or NOLINT(*) syntax.
+  raw_lines = clean_lines.lines_without_raw_strings
+  for i in raw_lines:
+    if Search(r'//\s*NOLINT\(build/header_guard\)', i):
+      return
+
+  cppvar = GetHeaderGuardCPPVariable(filename)
+
+  ifndef = ''
+  ifndef_linenum = 0
+  define = ''
+  endif = ''
+  endif_linenum = 0
+  for linenum, line in enumerate(raw_lines):
+    linesplit = line.split()
+    if len(linesplit) >= 2:
+      # find the first occurrence of #ifndef and #define, save arg
+      if not ifndef and linesplit[0] == '#ifndef':
+        # set ifndef to the header guard presented on the #ifndef line.
+        ifndef = linesplit[1]
+        ifndef_linenum = linenum
+      if not define and linesplit[0] == '#define':
+        define = linesplit[1]
+    # find the last occurrence of #endif, save entire line
+    if line.startswith('#endif'):
+      endif = line
+      endif_linenum = linenum
+
+  if not ifndef or not define or ifndef != define:
+    error(filename, 0, 'build/header_guard', 5,
+          'No #ifndef header guard found, suggested CPP variable is: %s' %
+          cppvar)
+    return
+
+  # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__
+  # for backward compatibility.
+  if ifndef != cppvar:
+    error_level = 0
+    if ifndef != cppvar + '_':
+      error_level = 5
+
+    ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum,
+                            error)
+    error(filename, ifndef_linenum, 'build/header_guard', error_level,
+          '#ifndef header guard has wrong style, please use: %s' % cppvar)
+
+  # Check for "//" comments on endif line.
+  ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum,
+                          error)
+  match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif)
+  if match:
+    if match.group(1) == '_':
+      # Issue low severity warning for deprecated double trailing underscore
+      error(filename, endif_linenum, 'build/header_guard', 0,
+            '#endif line should be "#endif  // %s"' % cppvar)
+    return
+
+  # Didn't find the corresponding "//" comment.  If this file does not
+  # contain any "//" comments at all, it could be that the compiler
+  # only wants "/**/" comments, look for those instead.
+  no_single_line_comments = True
+  for i in xrange(1, len(raw_lines) - 1):
+    line = raw_lines[i]
+    if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line):
+      no_single_line_comments = False
+      break
+
+  if no_single_line_comments:
+    match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif)
+    if match:
+      if match.group(1) == '_':
+        # Low severity warning for double trailing underscore
+        error(filename, endif_linenum, 'build/header_guard', 0,
+              '#endif line should be "#endif  /* %s */"' % cppvar)
+      return
+
+  # Didn't find anything
+  error(filename, endif_linenum, 'build/header_guard', 5,
+        '#endif line should be "#endif  // %s"' % cppvar)
+
+
+def CheckHeaderFileIncluded(filename, include_state, error):
+  """Logs an error if a .cc file does not include its header."""
+
+  # Do not check test files
+  if filename.endswith('_test.cc') or filename.endswith('_unittest.cc'):
+    return
+
+  fileinfo = FileInfo(filename)
+  headerfile = filename[0:len(filename) - 2] + 'h'
+  if not os.path.exists(headerfile):
+    return
+  headername = FileInfo(headerfile).RepositoryName()
+  first_include = 0
+  for section_list in include_state.include_list:
+    for f in section_list:
+      if headername in f[0] or f[0] in headername:
+        return
+      if not first_include:
+        first_include = f[1]
+
+  error(filename, first_include, 'build/include', 5,
+        '%s should include its header file %s' % (fileinfo.RepositoryName(),
+                                                  headername))
+
+
+def CheckForBadCharacters(filename, lines, error):
+  """Logs an error for each line containing bad characters.
+
+  Two kinds of bad characters:
+
+  1. Unicode replacement characters: These indicate that either the file
+  contained invalid UTF-8 (likely) or Unicode replacement characters (which
+  it shouldn't).  Note that it's possible for this to throw off line
+  numbering if the invalid UTF-8 occurred adjacent to a newline.
+
+  2. NUL bytes.  These are problematic for some tools.
+
+  Args:
+    filename: The name of the current file.
+    lines: An array of strings, each representing a line of the file.
+    error: The function to call with any errors found.
+  """
+  for linenum, line in enumerate(lines):
+    if u'\ufffd' in line:
+      error(filename, linenum, 'readability/utf8', 5,
+            'Line contains invalid UTF-8 (or Unicode replacement character).')
+    if '\0' in line:
+      error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.')
+
+
+def CheckForNewlineAtEOF(filename, lines, error):
+  """Logs an error if there is no newline char at the end of the file.
+
+  Args:
+    filename: The name of the current file.
+    lines: An array of strings, each representing a line of the file.
+    error: The function to call with any errors found.
+  """
+
+  # The array lines() was created by adding two newlines to the
+  # original file (go figure), then splitting on \n.
+  # To verify that the file ends in \n, we just have to make sure the
+  # last-but-two element of lines() exists and is empty.
+  if len(lines) < 3 or lines[-2]:
+    error(filename, len(lines) - 2, 'whitespace/ending_newline', 5,
+          'Could not find a newline character at the end of the file.')
+
+
+def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
+  """Logs an error if we see /* ... */ or "..." that extend past one line.
+
+  /* ... */ comments are legit inside macros, for one line.
+  Otherwise, we prefer // comments, so it's ok to warn about the
+  other.  Likewise, it's ok for strings to extend across multiple
+  lines, as long as a line continuation character (backslash)
+  terminates each line. Although not currently prohibited by the C++
+  style guide, it's ugly and unnecessary. We don't do well with either
+  in this lint program, so we warn about both.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Remove all \\ (escaped backslashes) from the line. They are OK, and the
+  # second (escaped) slash may trigger later \" detection erroneously.
+  line = line.replace('\\\\', '')
+
+  if line.count('/*') > line.count('*/'):
+    error(filename, linenum, 'readability/multiline_comment', 5,
+          'Complex multi-line /*...*/-style comment found. '
+          'Lint may give bogus warnings.  '
+          'Consider replacing these with //-style comments, '
+          'with #if 0...#endif, '
+          'or with more clearly structured multi-line comments.')
+
+  if (line.count('"') - line.count('\\"')) % 2:
+    error(filename, linenum, 'readability/multiline_string', 5,
+          'Multi-line string ("...") found.  This lint script doesn\'t '
+          'do well with such strings, and may give bogus warnings.  '
+          'Use C++11 raw strings or concatenation instead.')
+
+
+# (non-threadsafe name, thread-safe alternative, validation pattern)
+#
+# The validation pattern is used to eliminate false positives such as:
+#  _rand();               // false positive due to substring match.
+#  ->rand();              // some member function rand().
+#  ACMRandom rand(seed);  // some variable named rand.
+#  ISAACRandom rand();    // another variable named rand.
+#
+# Basically we require the return value of these functions to be used
+# in some expression context on the same line by matching on some
+# operator before the function name.  This eliminates constructors and
+# member function calls.
+_UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)'
+_THREADING_LIST = (
+    ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'),
+    ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'),
+    ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'),
+    ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'),
+    ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'),
+    ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'),
+    ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'),
+    ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'),
+    ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'),
+    ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'),
+    ('strtok(', 'strtok_r(',
+     _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'),
+    ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'),
+    )
+
+
+def CheckPosixThreading(filename, clean_lines, linenum, error):
+  """Checks for calls to thread-unsafe functions.
+
+  Much code has been originally written without consideration of
+  multi-threading. Also, engineers are relying on their old experience;
+  they have learned posix before threading extensions were added. These
+  tests guide the engineers to use thread-safe functions (when using
+  posix directly).
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+  for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST:
+    # Additional pattern matching check to confirm that this is the
+    # function we are looking for
+    if Search(pattern, line):
+      error(filename, linenum, 'runtime/threadsafe_fn', 2,
+            'Consider using ' + multithread_safe_func +
+            '...) instead of ' + single_thread_func +
+            '...) for improved thread safety.')
+
+
+def CheckVlogArguments(filename, clean_lines, linenum, error):
+  """Checks that VLOG() is only used for defining a logging level.
+
+  For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and
+  VLOG(FATAL) are not.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+  if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line):
+    error(filename, linenum, 'runtime/vlog', 5,
+          'VLOG() should be used with numeric verbosity level.  '
+          'Use LOG() if you want symbolic severity levels.')
+
+# Matches invalid increment: *count++, which moves pointer instead of
+# incrementing a value.
+_RE_PATTERN_INVALID_INCREMENT = re.compile(
+    r'^\s*\*\w+(\+\+|--);')
+
+
+def CheckInvalidIncrement(filename, clean_lines, linenum, error):
+  """Checks for invalid increment *count++.
+
+  For example following function:
+  void increment_counter(int* count) {
+    *count++;
+  }
+  is invalid, because it effectively does count++, moving pointer, and should
+  be replaced with ++*count, (*count)++ or *count += 1.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+  if _RE_PATTERN_INVALID_INCREMENT.match(line):
+    error(filename, linenum, 'runtime/invalid_increment', 5,
+          'Changing pointer instead of value (or unused value of operator*).')
+
+
+def IsMacroDefinition(clean_lines, linenum):
+  if Search(r'^#define', clean_lines[linenum]):
+    return True
+
+  if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]):
+    return True
+
+  return False
+
+
+def IsForwardClassDeclaration(clean_lines, linenum):
+  return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum])
+
+
+class _BlockInfo(object):
+  """Stores information about a generic block of code."""
+
+  def __init__(self, seen_open_brace):
+    self.seen_open_brace = seen_open_brace
+    self.open_parentheses = 0
+    self.inline_asm = _NO_ASM
+    self.check_namespace_indentation = False
+
+  def CheckBegin(self, filename, clean_lines, linenum, error):
+    """Run checks that applies to text up to the opening brace.
+
+    This is mostly for checking the text after the class identifier
+    and the "{", usually where the base class is specified.  For other
+    blocks, there isn't much to check, so we always pass.
+
+    Args:
+      filename: The name of the current file.
+      clean_lines: A CleansedLines instance containing the file.
+      linenum: The number of the line to check.
+      error: The function to call with any errors found.
+    """
+    pass
+
+  def CheckEnd(self, filename, clean_lines, linenum, error):
+    """Run checks that applies to text after the closing brace.
+
+    This is mostly used for checking end of namespace comments.
+
+    Args:
+      filename: The name of the current file.
+      clean_lines: A CleansedLines instance containing the file.
+      linenum: The number of the line to check.
+      error: The function to call with any errors found.
+    """
+    pass
+
+  def IsBlockInfo(self):
+    """Returns true if this block is a _BlockInfo.
+
+    This is convenient for verifying that an object is an instance of
+    a _BlockInfo, but not an instance of any of the derived classes.
+
+    Returns:
+      True for this class, False for derived classes.
+    """
+    return self.__class__ == _BlockInfo
+
+
+class _ExternCInfo(_BlockInfo):
+  """Stores information about an 'extern "C"' block."""
+
+  def __init__(self):
+    _BlockInfo.__init__(self, True)
+
+
+class _ClassInfo(_BlockInfo):
+  """Stores information about a class."""
+
+  def __init__(self, name, class_or_struct, clean_lines, linenum):
+    _BlockInfo.__init__(self, False)
+    self.name = name
+    self.starting_linenum = linenum
+    self.is_derived = False
+    self.check_namespace_indentation = True
+    if class_or_struct == 'struct':
+      self.access = 'public'
+      self.is_struct = True
+    else:
+      self.access = 'private'
+      self.is_struct = False
+
+    # Remember initial indentation level for this class.  Using raw_lines here
+    # instead of elided to account for leading comments.
+    self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum])
+
+    # Try to find the end of the class.  This will be confused by things like:
+    #   class A {
+    #   } *x = { ...
+    #
+    # But it's still good enough for CheckSectionSpacing.
+    self.last_line = 0
+    depth = 0
+    for i in range(linenum, clean_lines.NumLines()):
+      line = clean_lines.elided[i]
+      depth += line.count('{') - line.count('}')
+      if not depth:
+        self.last_line = i
+        break
+
+  def CheckBegin(self, filename, clean_lines, linenum, error):
+    # Look for a bare ':'
+    if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]):
+      self.is_derived = True
+
+  def CheckEnd(self, filename, clean_lines, linenum, error):
+    # If there is a DISALLOW macro, it should appear near the end of
+    # the class.
+    seen_last_thing_in_class = False
+    for i in xrange(linenum - 1, self.starting_linenum, -1):
+      match = Search(
+          r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' +
+          self.name + r'\)',
+          clean_lines.elided[i])
+      if match:
+        if seen_last_thing_in_class:
+          error(filename, i, 'readability/constructors', 3,
+                match.group(1) + ' should be the last thing in the class')
+        break
+
+      if not Match(r'^\s*$', clean_lines.elided[i]):
+        seen_last_thing_in_class = True
+
+    # Check that closing brace is aligned with beginning of the class.
+    # Only do this if the closing brace is indented by only whitespaces.
+    # This means we will not check single-line class definitions.
+    indent = Match(r'^( *)\}', clean_lines.elided[linenum])
+    if indent and len(indent.group(1)) != self.class_indent:
+      if self.is_struct:
+        parent = 'struct ' + self.name
+      else:
+        parent = 'class ' + self.name
+      error(filename, linenum, 'whitespace/indent', 3,
+            'Closing brace should be aligned with beginning of %s' % parent)
+
+
+class _NamespaceInfo(_BlockInfo):
+  """Stores information about a namespace."""
+
+  def __init__(self, name, linenum):
+    _BlockInfo.__init__(self, False)
+    self.name = name or ''
+    self.starting_linenum = linenum
+    self.check_namespace_indentation = True
+
+  def CheckEnd(self, filename, clean_lines, linenum, error):
+    """Check end of namespace comments."""
+    line = clean_lines.raw_lines[linenum]
+
+    # Check how many lines is enclosed in this namespace.  Don't issue
+    # warning for missing namespace comments if there aren't enough
+    # lines.  However, do apply checks if there is already an end of
+    # namespace comment and it's incorrect.
+    #
+    # TODO(unknown): We always want to check end of namespace comments
+    # if a namespace is large, but sometimes we also want to apply the
+    # check if a short namespace contained nontrivial things (something
+    # other than forward declarations).  There is currently no logic on
+    # deciding what these nontrivial things are, so this check is
+    # triggered by namespace size only, which works most of the time.
+    if (linenum - self.starting_linenum < 10
+        and not Match(r'};*\s*(//|/\*).*\bnamespace\b', line)):
+      return
+
+    # Look for matching comment at end of namespace.
+    #
+    # Note that we accept C style "/* */" comments for terminating
+    # namespaces, so that code that terminate namespaces inside
+    # preprocessor macros can be cpplint clean.
+    #
+    # We also accept stuff like "// end of namespace <name>." with the
+    # period at the end.
+    #
+    # Besides these, we don't accept anything else, otherwise we might
+    # get false negatives when existing comment is a substring of the
+    # expected namespace.
+    if self.name:
+      # Named namespace
+      if not Match((r'};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) +
+                    r'[\*/\.\\\s]*$'),
+                   line):
+        error(filename, linenum, 'readability/namespace', 5,
+              'Namespace should be terminated with "// namespace %s"' %
+              self.name)
+    else:
+      # Anonymous namespace
+      if not Match(r'};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line):
+        # If "// namespace anonymous" or "// anonymous namespace (more text)",
+        # mention "// anonymous namespace" as an acceptable form
+        if Match(r'}.*\b(namespace anonymous|anonymous namespace)\b', line):
+          error(filename, linenum, 'readability/namespace', 5,
+                'Anonymous namespace should be terminated with "// namespace"'
+                ' or "// anonymous namespace"')
+        else:
+          error(filename, linenum, 'readability/namespace', 5,
+                'Anonymous namespace should be terminated with "// namespace"')
+
+
+class _PreprocessorInfo(object):
+  """Stores checkpoints of nesting stacks when #if/#else is seen."""
+
+  def __init__(self, stack_before_if):
+    # The entire nesting stack before #if
+    self.stack_before_if = stack_before_if
+
+    # The entire nesting stack up to #else
+    self.stack_before_else = []
+
+    # Whether we have already seen #else or #elif
+    self.seen_else = False
+
+
+class NestingState(object):
+  """Holds states related to parsing braces."""
+
+  def __init__(self):
+    # Stack for tracking all braces.  An object is pushed whenever we
+    # see a "{", and popped when we see a "}".  Only 3 types of
+    # objects are possible:
+    # - _ClassInfo: a class or struct.
+    # - _NamespaceInfo: a namespace.
+    # - _BlockInfo: some other type of block.
+    self.stack = []
+
+    # Top of the previous stack before each Update().
+    #
+    # Because the nesting_stack is updated at the end of each line, we
+    # had to do some convoluted checks to find out what is the current
+    # scope at the beginning of the line.  This check is simplified by
+    # saving the previous top of nesting stack.
+    #
+    # We could save the full stack, but we only need the top.  Copying
+    # the full nesting stack would slow down cpplint by ~10%.
+    self.previous_stack_top = []
+
+    # Stack of _PreprocessorInfo objects.
+    self.pp_stack = []
+
+  def SeenOpenBrace(self):
+    """Check if we have seen the opening brace for the innermost block.
+
+    Returns:
+      True if we have seen the opening brace, False if the innermost
+      block is still expecting an opening brace.
+    """
+    return (not self.stack) or self.stack[-1].seen_open_brace
+
+  def InNamespaceBody(self):
+    """Check if we are currently one level inside a namespace body.
+
+    Returns:
+      True if top of the stack is a namespace block, False otherwise.
+    """
+    return self.stack and isinstance(self.stack[-1], _NamespaceInfo)
+
+  def InExternC(self):
+    """Check if we are currently one level inside an 'extern "C"' block.
+
+    Returns:
+      True if top of the stack is an extern block, False otherwise.
+    """
+    return self.stack and isinstance(self.stack[-1], _ExternCInfo)
+
+  def InClassDeclaration(self):
+    """Check if we are currently one level inside a class or struct declaration.
+
+    Returns:
+      True if top of the stack is a class/struct, False otherwise.
+    """
+    return self.stack and isinstance(self.stack[-1], _ClassInfo)
+
+  def InAsmBlock(self):
+    """Check if we are currently one level inside an inline ASM block.
+
+    Returns:
+      True if the top of the stack is a block containing inline ASM.
+    """
+    return self.stack and self.stack[-1].inline_asm != _NO_ASM
+
+  def InTemplateArgumentList(self, clean_lines, linenum, pos):
+    """Check if current position is inside template argument list.
+
+    Args:
+      clean_lines: A CleansedLines instance containing the file.
+      linenum: The number of the line to check.
+      pos: position just after the suspected template argument.
+    Returns:
+      True if (linenum, pos) is inside template arguments.
+    """
+    while linenum < clean_lines.NumLines():
+      # Find the earliest character that might indicate a template argument
+      line = clean_lines.elided[linenum]
+      match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:])
+      if not match:
+        linenum += 1
+        pos = 0
+        continue
+      token = match.group(1)
+      pos += len(match.group(0))
+
+      # These things do not look like template argument list:
+      #   class Suspect {
+      #   class Suspect x; }
+      if token in ('{', '}', ';'): return False
+
+      # These things look like template argument list:
+      #   template <class Suspect>
+      #   template <class Suspect = default_value>
+      #   template <class Suspect[]>
+      #   template <class Suspect...>
+      if token in ('>', '=', '[', ']', '.'): return True
+
+      # Check if token is an unmatched '<'.
+      # If not, move on to the next character.
+      if token != '<':
+        pos += 1
+        if pos >= len(line):
+          linenum += 1
+          pos = 0
+        continue
+
+      # We can't be sure if we just find a single '<', and need to
+      # find the matching '>'.
+      (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1)
+      if end_pos < 0:
+        # Not sure if template argument list or syntax error in file
+        return False
+      linenum = end_line
+      pos = end_pos
+    return False
+
+  def UpdatePreprocessor(self, line):
+    """Update preprocessor stack.
+
+    We need to handle preprocessors due to classes like this:
+      #ifdef SWIG
+      struct ResultDetailsPageElementExtensionPoint {
+      #else
+      struct ResultDetailsPageElementExtensionPoint : public Extension {
+      #endif
+
+    We make the following assumptions (good enough for most files):
+    - Preprocessor condition evaluates to true from #if up to first
+      #else/#elif/#endif.
+
+    - Preprocessor condition evaluates to false from #else/#elif up
+      to #endif.  We still perform lint checks on these lines, but
+      these do not affect nesting stack.
+
+    Args:
+      line: current line to check.
+    """
+    if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line):
+      # Beginning of #if block, save the nesting stack here.  The saved
+      # stack will allow us to restore the parsing state in the #else case.
+      self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack)))
+    elif Match(r'^\s*#\s*(else|elif)\b', line):
+      # Beginning of #else block
+      if self.pp_stack:
+        if not self.pp_stack[-1].seen_else:
+          # This is the first #else or #elif block.  Remember the
+          # whole nesting stack up to this point.  This is what we
+          # keep after the #endif.
+          self.pp_stack[-1].seen_else = True
+          self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack)
+
+        # Restore the stack to how it was before the #if
+        self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if)
+      else:
+        # TODO(unknown): unexpected #else, issue warning?
+        pass
+    elif Match(r'^\s*#\s*endif\b', line):
+      # End of #if or #else blocks.
+      if self.pp_stack:
+        # If we saw an #else, we will need to restore the nesting
+        # stack to its former state before the #else, otherwise we
+        # will just continue from where we left off.
+        if self.pp_stack[-1].seen_else:
+          # Here we can just use a shallow copy since we are the last
+          # reference to it.
+          self.stack = self.pp_stack[-1].stack_before_else
+        # Drop the corresponding #if
+        self.pp_stack.pop()
+      else:
+        # TODO(unknown): unexpected #endif, issue warning?
+        pass
+
+  # TODO(unknown): Update() is too long, but we will refactor later.
+  def Update(self, filename, clean_lines, linenum, error):
+    """Update nesting state with current line.
+
+    Args:
+      filename: The name of the current file.
+      clean_lines: A CleansedLines instance containing the file.
+      linenum: The number of the line to check.
+      error: The function to call with any errors found.
+    """
+    line = clean_lines.elided[linenum]
+
+    # Remember top of the previous nesting stack.
+    #
+    # The stack is always pushed/popped and not modified in place, so
+    # we can just do a shallow copy instead of copy.deepcopy.  Using
+    # deepcopy would slow down cpplint by ~28%.
+    if self.stack:
+      self.previous_stack_top = self.stack[-1]
+    else:
+      self.previous_stack_top = None
+
+    # Update pp_stack
+    self.UpdatePreprocessor(line)
+
+    # Count parentheses.  This is to avoid adding struct arguments to
+    # the nesting stack.
+    if self.stack:
+      inner_block = self.stack[-1]
+      depth_change = line.count('(') - line.count(')')
+      inner_block.open_parentheses += depth_change
+
+      # Also check if we are starting or ending an inline assembly block.
+      if inner_block.inline_asm in (_NO_ASM, _END_ASM):
+        if (depth_change != 0 and
+            inner_block.open_parentheses == 1 and
+            _MATCH_ASM.match(line)):
+          # Enter assembly block
+          inner_block.inline_asm = _INSIDE_ASM
+        else:
+          # Not entering assembly block.  If previous line was _END_ASM,
+          # we will now shift to _NO_ASM state.
+          inner_block.inline_asm = _NO_ASM
+      elif (inner_block.inline_asm == _INSIDE_ASM and
+            inner_block.open_parentheses == 0):
+        # Exit assembly block
+        inner_block.inline_asm = _END_ASM
+
+    # Consume namespace declaration at the beginning of the line.  Do
+    # this in a loop so that we catch same line declarations like this:
+    #   namespace proto2 { namespace bridge { class MessageSet; } }
+    while True:
+      # Match start of namespace.  The "\b\s*" below catches namespace
+      # declarations even if it weren't followed by a whitespace, this
+      # is so that we don't confuse our namespace checker.  The
+      # missing spaces will be flagged by CheckSpacing.
+      namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line)
+      if not namespace_decl_match:
+        break
+
+      new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum)
+      self.stack.append(new_namespace)
+
+      line = namespace_decl_match.group(2)
+      if line.find('{') != -1:
+        new_namespace.seen_open_brace = True
+        line = line[line.find('{') + 1:]
+
+    # Look for a class declaration in whatever is left of the line
+    # after parsing namespaces.  The regexp accounts for decorated classes
+    # such as in:
+    #   class LOCKABLE API Object {
+    #   };
+    class_decl_match = Match(
+        r'^(\s*(?:template\s*<[\w\s<>,:]*>\s*)?'
+        r'(class|struct)\s+(?:[A-Z_]+\s+)*(\w+(?:::\w+)*))'
+        r'(.*)$', line)
+    if (class_decl_match and
+        (not self.stack or self.stack[-1].open_parentheses == 0)):
+      # We do not want to accept classes that are actually template arguments:
+      #   template <class Ignore1,
+      #             class Ignore2 = Default<Args>,
+      #             template <Args> class Ignore3>
+      #   void Function() {};
+      #
+      # To avoid template argument cases, we scan forward and look for
+      # an unmatched '>'.  If we see one, assume we are inside a
+      # template argument list.
+      end_declaration = len(class_decl_match.group(1))
+      if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration):
+        self.stack.append(_ClassInfo(
+            class_decl_match.group(3), class_decl_match.group(2),
+            clean_lines, linenum))
+        line = class_decl_match.group(4)
+
+    # If we have not yet seen the opening brace for the innermost block,
+    # run checks here.
+    if not self.SeenOpenBrace():
+      self.stack[-1].CheckBegin(filename, clean_lines, linenum, error)
+
+    # Update access control if we are inside a class/struct
+    if self.stack and isinstance(self.stack[-1], _ClassInfo):
+      classinfo = self.stack[-1]
+      access_match = Match(
+          r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?'
+          r':(?:[^:]|$)',
+          line)
+      if access_match:
+        classinfo.access = access_match.group(2)
+
+        # Check that access keywords are indented +1 space.  Skip this
+        # check if the keywords are not preceded by whitespaces.
+        indent = access_match.group(1)
+        if (len(indent) != classinfo.class_indent + 1 and
+            Match(r'^\s*$', indent)):
+          if classinfo.is_struct:
+            parent = 'struct ' + classinfo.name
+          else:
+            parent = 'class ' + classinfo.name
+          slots = ''
+          if access_match.group(3):
+            slots = access_match.group(3)
+          error(filename, linenum, 'whitespace/indent', 3,
+                '%s%s: should be indented +1 space inside %s' % (
+                    access_match.group(2), slots, parent))
+
+    # Consume braces or semicolons from what's left of the line
+    while True:
+      # Match first brace, semicolon, or closed parenthesis.
+      matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line)
+      if not matched:
+        break
+
+      token = matched.group(1)
+      if token == '{':
+        # If namespace or class hasn't seen a opening brace yet, mark
+        # namespace/class head as complete.  Push a new block onto the
+        # stack otherwise.
+        if not self.SeenOpenBrace():
+          self.stack[-1].seen_open_brace = True
+        elif Match(r'^extern\s*"[^"]*"\s*\{', line):
+          self.stack.append(_ExternCInfo())
+        else:
+          self.stack.append(_BlockInfo(True))
+          if _MATCH_ASM.match(line):
+            self.stack[-1].inline_asm = _BLOCK_ASM
+
+      elif token == ';' or token == ')':
+        # If we haven't seen an opening brace yet, but we already saw
+        # a semicolon, this is probably a forward declaration.  Pop
+        # the stack for these.
+        #
+        # Similarly, if we haven't seen an opening brace yet, but we
+        # already saw a closing parenthesis, then these are probably
+        # function arguments with extra "class" or "struct" keywords.
+        # Also pop these stack for these.
+        if not self.SeenOpenBrace():
+          self.stack.pop()
+      else:  # token == '}'
+        # Perform end of block checks and pop the stack.
+        if self.stack:
+          self.stack[-1].CheckEnd(filename, clean_lines, linenum, error)
+          self.stack.pop()
+      line = matched.group(2)
+
+  def InnermostClass(self):
+    """Get class info on the top of the stack.
+
+    Returns:
+      A _ClassInfo object if we are inside a class, or None otherwise.
+    """
+    for i in range(len(self.stack), 0, -1):
+      classinfo = self.stack[i - 1]
+      if isinstance(classinfo, _ClassInfo):
+        return classinfo
+    return None
+
+  def CheckCompletedBlocks(self, filename, error):
+    """Checks that all classes and namespaces have been completely parsed.
+
+    Call this when all lines in a file have been processed.
+    Args:
+      filename: The name of the current file.
+      error: The function to call with any errors found.
+    """
+    # Note: This test can result in false positives if #ifdef constructs
+    # get in the way of brace matching. See the testBuildClass test in
+    # cpplint_unittest.py for an example of this.
+    for obj in self.stack:
+      if isinstance(obj, _ClassInfo):
+        error(filename, obj.starting_linenum, 'build/class', 5,
+              'Failed to find complete declaration of class %s' %
+              obj.name)
+      elif isinstance(obj, _NamespaceInfo):
+        error(filename, obj.starting_linenum, 'build/namespaces', 5,
+              'Failed to find complete declaration of namespace %s' %
+              obj.name)
+
+
+def CheckForNonStandardConstructs(filename, clean_lines, linenum,
+                                  nesting_state, error):
+  r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
+
+  Complain about several constructs which gcc-2 accepts, but which are
+  not standard C++.  Warning about these in lint is one way to ease the
+  transition to new compilers.
+  - put storage class first (e.g. "static const" instead of "const static").
+  - "%lld" instead of %qd" in printf-type functions.
+  - "%1$d" is non-standard in printf-type functions.
+  - "\%" is an undefined character escape sequence.
+  - text after #endif is not allowed.
+  - invalid inner-style forward declaration.
+  - >? and <? operators, and their >?= and <?= cousins.
+
+  Additionally, check for constructor/destructor style violations and reference
+  members, as it is very convenient to do so while checking for
+  gcc-2 compliance.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: A callable to which errors are reported, which takes 4 arguments:
+           filename, line number, error level, and message
+  """
+
+  # Remove comments from the line, but leave in strings for now.
+  line = clean_lines.lines[linenum]
+
+  if Search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
+    error(filename, linenum, 'runtime/printf_format', 3,
+          '%q in format strings is deprecated.  Use %ll instead.')
+
+  if Search(r'printf\s*\(.*".*%\d+\$', line):
+    error(filename, linenum, 'runtime/printf_format', 2,
+          '%N$ formats are unconventional.  Try rewriting to avoid them.')
+
+  # Remove escaped backslashes before looking for undefined escapes.
+  line = line.replace('\\\\', '')
+
+  if Search(r'("|\').*\\(%|\[|\(|{)', line):
+    error(filename, linenum, 'build/printf_format', 3,
+          '%, [, (, and { are undefined character escapes.  Unescape them.')
+
+  # For the rest, work with both comments and strings removed.
+  line = clean_lines.elided[linenum]
+
+  if Search(r'\b(const|volatile|void|char|short|int|long'
+            r'|float|double|signed|unsigned'
+            r'|schar|u?int8|u?int16|u?int32|u?int64)'
+            r'\s+(register|static|extern|typedef)\b',
+            line):
+    error(filename, linenum, 'build/storage_class', 5,
+          'Storage class (static, extern, typedef, etc) should be first.')
+
+  if Match(r'\s*#\s*endif\s*[^/\s]+', line):
+    error(filename, linenum, 'build/endif_comment', 5,
+          'Uncommented text after #endif is non-standard.  Use a comment.')
+
+  if Match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
+    error(filename, linenum, 'build/forward_decl', 5,
+          'Inner-style forward declarations are invalid.  Remove this line.')
+
+  if Search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?',
+            line):
+    error(filename, linenum, 'build/deprecated', 3,
+          '>? and <? (max and min) operators are non-standard and deprecated.')
+
+  if Search(r'^\s*const\s*string\s*&\s*\w+\s*;', line):
+    # TODO(unknown): Could it be expanded safely to arbitrary references,
+    # without triggering too many false positives? The first
+    # attempt triggered 5 warnings for mostly benign code in the regtest, hence
+    # the restriction.
+    # Here's the original regexp, for the reference:
+    # type_name = r'\w+((\s*::\s*\w+)|(\s*<\s*\w+?\s*>))?'
+    # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;'
+    error(filename, linenum, 'runtime/member_string_references', 2,
+          'const string& members are dangerous. It is much better to use '
+          'alternatives, such as pointers or simple constants.')
+
+  # Everything else in this function operates on class declarations.
+  # Return early if the top of the nesting stack is not a class, or if
+  # the class head is not completed yet.
+  classinfo = nesting_state.InnermostClass()
+  if not classinfo or not classinfo.seen_open_brace:
+    return
+
+  # The class may have been declared with namespace or classname qualifiers.
+  # The constructor and destructor will not have those qualifiers.
+  base_classname = classinfo.name.split('::')[-1]
+
+  # Look for single-argument constructors that aren't marked explicit.
+  # Technically a valid construct, but against style. Also look for
+  # non-single-argument constructors which are also technically valid, but
+  # strongly suggest something is wrong.
+  explicit_constructor_match = Match(
+      r'\s+(?:inline\s+)?(explicit\s+)?(?:inline\s+)?%s\s*'
+      r'\(((?:[^()]|\([^()]*\))*)\)'
+      % re.escape(base_classname),
+      line)
+
+  if explicit_constructor_match:
+    is_marked_explicit = explicit_constructor_match.group(1)
+
+    if not explicit_constructor_match.group(2):
+      constructor_args = []
+    else:
+      constructor_args = explicit_constructor_match.group(2).split(',')
+
+    # collapse arguments so that commas in template parameter lists and function
+    # argument parameter lists don't split arguments in two
+    i = 0
+    while i < len(constructor_args):
+      constructor_arg = constructor_args[i]
+      while (constructor_arg.count('<') > constructor_arg.count('>') or
+             constructor_arg.count('(') > constructor_arg.count(')')):
+        constructor_arg += ',' + constructor_args[i + 1]
+        del constructor_args[i + 1]
+      constructor_args[i] = constructor_arg
+      i += 1
+
+    defaulted_args = [arg for arg in constructor_args if '=' in arg]
+    noarg_constructor = (not constructor_args or  # empty arg list
+                         # 'void' arg specifier
+                         (len(constructor_args) == 1 and
+                          constructor_args[0].strip() == 'void'))
+    onearg_constructor = ((len(constructor_args) == 1 and  # exactly one arg
+                           not noarg_constructor) or
+                          # all but at most one arg defaulted
+                          (len(constructor_args) >= 1 and
+                           not noarg_constructor and
+                           len(defaulted_args) >= len(constructor_args) - 1))
+    initializer_list_constructor = bool(
+        onearg_constructor and
+        Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
+    copy_constructor = bool(
+        onearg_constructor and
+        Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
+              % re.escape(base_classname), constructor_args[0].strip()))
+
+    if (not is_marked_explicit and
+        onearg_constructor and
+        not initializer_list_constructor and
+        not copy_constructor):
+      if defaulted_args:
+        error(filename, linenum, 'runtime/explicit', 5,
+              'Constructors callable with one argument '
+              'should be marked explicit.')
+      else:
+        error(filename, linenum, 'runtime/explicit', 5,
+              'Single-parameter constructors should be marked explicit.')
+    elif is_marked_explicit and not onearg_constructor:
+      if noarg_constructor:
+        error(filename, linenum, 'runtime/explicit', 5,
+              'Zero-parameter constructors should not be marked explicit.')
+      else:
+        error(filename, linenum, 'runtime/explicit', 0,
+              'Constructors that require multiple arguments '
+              'should not be marked explicit.')
+
+
+def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error):
+  """Checks for the correctness of various spacing around function calls.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Since function calls often occur inside if/for/while/switch
+  # expressions - which have their own, more liberal conventions - we
+  # first see if we should be looking inside such an expression for a
+  # function call, to which we can apply more strict standards.
+  fncall = line    # if there's no control flow construct, look at whole line
+  for pattern in (r'\bif\s*\((.*)\)\s*{',
+                  r'\bfor\s*\((.*)\)\s*{',
+                  r'\bwhile\s*\((.*)\)\s*[{;]',
+                  r'\bswitch\s*\((.*)\)\s*{'):
+    match = Search(pattern, line)
+    if match:
+      fncall = match.group(1)    # look inside the parens for function calls
+      break
+
+  # Except in if/for/while/switch, there should never be space
+  # immediately inside parens (eg "f( 3, 4 )").  We make an exception
+  # for nested parens ( (a+b) + c ).  Likewise, there should never be
+  # a space before a ( when it's a function argument.  I assume it's a
+  # function argument when the char before the whitespace is legal in
+  # a function name (alnum + _) and we're not starting a macro. Also ignore
+  # pointers and references to arrays and functions coz they're too tricky:
+  # we use a very simple way to recognize these:
+  # " (something)(maybe-something)" or
+  # " (something)(maybe-something," or
+  # " (something)[something]"
+  # Note that we assume the contents of [] to be short enough that
+  # they'll never need to wrap.
+  if (  # Ignore control structures.
+      not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b',
+                 fncall) and
+      # Ignore pointers/references to functions.
+      not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and
+      # Ignore pointers/references to arrays.
+      not Search(r' \([^)]+\)\[[^\]]+\]', fncall)):
+    if Search(r'\w\s*\(\s(?!\s*\\$)', fncall):      # a ( used for a fn call
+      error(filename, linenum, 'whitespace/parens', 4,
+            'Extra space after ( in function call')
+    elif Search(r'\(\s+(?!(\s*\\)|\()', fncall):
+      error(filename, linenum, 'whitespace/parens', 2,
+            'Extra space after (')
+    if (Search(r'\w\s+\(', fncall) and
+        not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and
+        not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and
+        not Search(r'\bcase\s+\(', fncall)):
+      # TODO(unknown): Space after an operator function seem to be a common
+      # error, silence those for now by restricting them to highest verbosity.
+      if Search(r'\boperator_*\b', line):
+        error(filename, linenum, 'whitespace/parens', 0,
+              'Extra space before ( in function call')
+      else:
+        error(filename, linenum, 'whitespace/parens', 4,
+              'Extra space before ( in function call')
+    # If the ) is followed only by a newline or a { + newline, assume it's
+    # part of a control statement (if/while/etc), and don't complain
+    if Search(r'[^)]\s+\)\s*[^{\s]', fncall):
+      # If the closing parenthesis is preceded by only whitespaces,
+      # try to give a more descriptive error message.
+      if Search(r'^\s+\)', fncall):
+        error(filename, linenum, 'whitespace/parens', 2,
+              'Closing ) should be moved to the previous line')
+      else:
+        error(filename, linenum, 'whitespace/parens', 2,
+              'Extra space before )')
+
+
+def IsBlankLine(line):
+  """Returns true if the given line is blank.
+
+  We consider a line to be blank if the line is empty or consists of
+  only white spaces.
+
+  Args:
+    line: A line of a string.
+
+  Returns:
+    True, if the given line is blank.
+  """
+  return not line or line.isspace()
+
+
+def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
+                                 error):
+  is_namespace_indent_item = (
+      len(nesting_state.stack) > 1 and
+      nesting_state.stack[-1].check_namespace_indentation and
+      isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and
+      nesting_state.previous_stack_top == nesting_state.stack[-2])
+
+  if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
+                                     clean_lines.elided, line):
+    CheckItemIndentationInNamespace(filename, clean_lines.elided,
+                                    line, error)
+
+
+def CheckForFunctionLengths(filename, clean_lines, linenum,
+                            function_state, error):
+  """Reports for long function bodies.
+
+  For an overview why this is done, see:
+  http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
+
+  Uses a simplistic algorithm assuming other style guidelines
+  (especially spacing) are followed.
+  Only checks unindented functions, so class members are unchecked.
+  Trivial bodies are unchecked, so constructors with huge initializer lists
+  may be missed.
+  Blank/comment lines are not counted so as to avoid encouraging the removal
+  of vertical space and comments just to get through a lint check.
+  NOLINT *on the last line of a function* disables this check.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    function_state: Current function name and lines in body so far.
+    error: The function to call with any errors found.
+  """
+  lines = clean_lines.lines
+  line = lines[linenum]
+  joined_line = ''
+
+  starting_func = False
+  regexp = r'(\w(\w|::|\*|\&|\s)*)\('  # decls * & space::name( ...
+  match_result = Match(regexp, line)
+  if match_result:
+    # If the name is all caps and underscores, figure it's a macro and
+    # ignore it, unless it's TEST or TEST_F.
+    function_name = match_result.group(1).split()[-1]
+    if function_name == 'TEST' or function_name == 'TEST_F' or (
+        not Match(r'[A-Z_]+$', function_name)):
+      starting_func = True
+
+  if starting_func:
+    body_found = False
+    for start_linenum in xrange(linenum, clean_lines.NumLines()):
+      start_line = lines[start_linenum]
+      joined_line += ' ' + start_line.lstrip()
+      if Search(r'(;|})', start_line):  # Declarations and trivial functions
+        body_found = True
+        break                              # ... ignore
+      elif Search(r'{', start_line):
+        body_found = True
+        function = Search(r'((\w|:)*)\(', line).group(1)
+        if Match(r'TEST', function):    # Handle TEST... macros
+          parameter_regexp = Search(r'(\(.*\))', joined_line)
+          if parameter_regexp:             # Ignore bad syntax
+            function += parameter_regexp.group(1)
+        else:
+          function += '()'
+        function_state.Begin(function)
+        break
+    if not body_found:
+      # No body for the function (or evidence of a non-function) was found.
+      error(filename, linenum, 'readability/fn_size', 5,
+            'Lint failed to find start of function body.')
+  elif Match(r'^\}\s*$', line):  # function end
+    function_state.Check(error, filename, linenum)
+    function_state.End()
+  elif not Match(r'^\s*$', line):
+    function_state.Count()  # Count non-blank/non-comment lines.
+
+
+_RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?')
+
+
+def CheckComment(line, filename, linenum, next_line_start, error):
+  """Checks for common mistakes in comments.
+
+  Args:
+    line: The line in question.
+    filename: The name of the current file.
+    linenum: The number of the line to check.
+    next_line_start: The first non-whitespace column of the next line.
+    error: The function to call with any errors found.
+  """
+  commentpos = line.find('//')
+  if commentpos != -1:
+    # Check if the // may be in quotes.  If so, ignore it
+    # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
+    if (line.count('"', 0, commentpos) -
+        line.count('\\"', 0, commentpos)) % 2 == 0:   # not in quotes
+      # Allow one space for new scopes, two spaces otherwise:
+      if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and
+          ((commentpos >= 1 and
+            line[commentpos-1] not in string.whitespace) or
+           (commentpos >= 2 and
+            line[commentpos-2] not in string.whitespace))):
+        error(filename, linenum, 'whitespace/comments', 2,
+              'At least two spaces is best between code and comments')
+
+      # Checks for common mistakes in TODO comments.
+      comment = line[commentpos:]
+      match = _RE_PATTERN_TODO.match(comment)
+      if match:
+        # One whitespace is correct; zero whitespace is handled elsewhere.
+        leading_whitespace = match.group(1)
+        if len(leading_whitespace) > 1:
+          error(filename, linenum, 'whitespace/todo', 2,
+                'Too many spaces before TODO')
+
+        username = match.group(2)
+        if not username:
+          error(filename, linenum, 'readability/todo', 2,
+                'Missing username in TODO; it should look like '
+                '"// TODO(my_username): Stuff."')
+
+        middle_whitespace = match.group(3)
+        # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison
+        if middle_whitespace != ' ' and middle_whitespace != '':
+          error(filename, linenum, 'whitespace/todo', 2,
+                'TODO(my_username) should be followed by a space')
+
+      # If the comment contains an alphanumeric character, there
+      # should be a space somewhere between it and the // unless
+      # it's a /// or //! Doxygen comment.
+      if (Match(r'//[^ ]*\w', comment) and
+          not Match(r'(///|//\!)(\s+|$)', comment)):
+        error(filename, linenum, 'whitespace/comments', 4,
+              'Should have a space between // and comment')
+
+
+def CheckAccess(filename, clean_lines, linenum, nesting_state, error):
+  """Checks for improper use of DISALLOW* macros.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]  # get rid of comments and strings
+
+  matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|'
+                   r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line)
+  if not matched:
+    return
+  if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo):
+    if nesting_state.stack[-1].access != 'private':
+      error(filename, linenum, 'readability/constructors', 3,
+            '%s must be in the private: section' % matched.group(1))
+
+  else:
+    # Found DISALLOW* macro outside a class declaration, or perhaps it
+    # was used inside a function when it should have been part of the
+    # class declaration.  We could issue a warning here, but it
+    # probably resulted in a compiler error already.
+    pass
+
+
+def CheckSpacing(filename, clean_lines, linenum, nesting_state, error):
+  """Checks for the correctness of various spacing issues in the code.
+
+  Things we check for: spaces around operators, spaces after
+  if/for/while/switch, no spaces around parens in function calls, two
+  spaces between code and comment, don't start a block with a blank
+  line, don't end a function with a blank line, don't add a blank line
+  after public/protected/private, don't have too many blank lines in a row.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: The function to call with any errors found.
+  """
+
+  # Don't use "elided" lines here, otherwise we can't check commented lines.
+  # Don't want to use "raw" either, because we don't want to check inside C++11
+  # raw strings,
+  raw = clean_lines.lines_without_raw_strings
+  line = raw[linenum]
+
+  # Before nixing comments, check if the line is blank for no good
+  # reason.  This includes the first line after a block is opened, and
+  # blank lines at the end of a function (ie, right before a line like '}'
+  #
+  # Skip all the blank line checks if we are immediately inside a
+  # namespace body.  In other words, don't issue blank line warnings
+  # for this block:
+  #   namespace {
+  #
+  #   }
+  #
+  # A warning about missing end of namespace comments will be issued instead.
+  #
+  # Also skip blank line checks for 'extern "C"' blocks, which are formatted
+  # like namespaces.
+  if (IsBlankLine(line) and
+      not nesting_state.InNamespaceBody() and
+      not nesting_state.InExternC()):
+    elided = clean_lines.elided
+    prev_line = elided[linenum - 1]
+    prevbrace = prev_line.rfind('{')
+    # TODO(unknown): Don't complain if line before blank line, and line after,
+    #                both start with alnums and are indented the same amount.
+    #                This ignores whitespace at the start of a namespace block
+    #                because those are not usually indented.
+    if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1:
+      # OK, we have a blank line at the start of a code block.  Before we
+      # complain, we check if it is an exception to the rule: The previous
+      # non-empty line has the parameters of a function header that are indented
+      # 4 spaces (because they did not fit in a 80 column line when placed on
+      # the same line as the function name).  We also check for the case where
+      # the previous line is indented 6 spaces, which may happen when the
+      # initializers of a constructor do not fit into a 80 column line.
+      exception = False
+      if Match(r' {6}\w', prev_line):  # Initializer list?
+        # We are looking for the opening column of initializer list, which
+        # should be indented 4 spaces to cause 6 space indentation afterwards.
+        search_position = linenum-2
+        while (search_position >= 0
+               and Match(r' {6}\w', elided[search_position])):
+          search_position -= 1
+        exception = (search_position >= 0
+                     and elided[search_position][:5] == '    :')
+      else:
+        # Search for the function arguments or an initializer list.  We use a
+        # simple heuristic here: If the line is indented 4 spaces; and we have a
+        # closing paren, without the opening paren, followed by an opening brace
+        # or colon (for initializer lists) we assume that it is the last line of
+        # a function header.  If we have a colon indented 4 spaces, it is an
+        # initializer list.
+        exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
+                           prev_line)
+                     or Match(r' {4}:', prev_line))
+
+      if not exception:
+        error(filename, linenum, 'whitespace/blank_line', 2,
+              'Redundant blank line at the start of a code block '
+              'should be deleted.')
+    # Ignore blank lines at the end of a block in a long if-else
+    # chain, like this:
+    #   if (condition1) {
+    #     // Something followed by a blank line
+    #
+    #   } else if (condition2) {
+    #     // Something else
+    #   }
+    if linenum + 1 < clean_lines.NumLines():
+      next_line = raw[linenum + 1]
+      if (next_line
+          and Match(r'\s*}', next_line)
+          and next_line.find('} else ') == -1):
+        error(filename, linenum, 'whitespace/blank_line', 3,
+              'Redundant blank line at the end of a code block '
+              'should be deleted.')
+
+    matched = Match(r'\s*(public|protected|private):', prev_line)
+    if matched:
+      error(filename, linenum, 'whitespace/blank_line', 3,
+            'Do not leave a blank line after "%s:"' % matched.group(1))
+
+  # Next, check comments
+  next_line_start = 0
+  if linenum + 1 < clean_lines.NumLines():
+    next_line = raw[linenum + 1]
+    next_line_start = len(next_line) - len(next_line.lstrip())
+  CheckComment(line, filename, linenum, next_line_start, error)
+
+  # get rid of comments and strings
+  line = clean_lines.elided[linenum]
+
+  # You shouldn't have spaces before your brackets, except maybe after
+  # 'delete []' or 'return []() {};'
+  if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
+    error(filename, linenum, 'whitespace/braces', 5,
+          'Extra space before [')
+
+  # In range-based for, we wanted spaces before and after the colon, but
+  # not around "::" tokens that might appear.
+  if (Search(r'for *\(.*[^:]:[^: ]', line) or
+      Search(r'for *\(.*[^: ]:[^:]', line)):
+    error(filename, linenum, 'whitespace/forcolon', 2,
+          'Missing space around colon in range-based for loop')
+
+
+def CheckOperatorSpacing(filename, clean_lines, linenum, error):
+  """Checks for horizontal spacing around operators.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Don't try to do spacing checks for operator methods.  Do this by
+  # replacing the troublesome characters with something else,
+  # preserving column position for all other characters.
+  #
+  # The replacement is done repeatedly to avoid false positives from
+  # operators that call operators.
+  while True:
+    match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line)
+    if match:
+      line = match.group(1) + ('_' * len(match.group(2))) + match.group(3)
+    else:
+      break
+
+  # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )".
+  # Otherwise not.  Note we only check for non-spaces on *both* sides;
+  # sometimes people put non-spaces on one side when aligning ='s among
+  # many lines (not that this is behavior that I approve of...)
+  if ((Search(r'[\w.]=', line) or
+       Search(r'=[\w.]', line))
+      and not Search(r'\b(if|while|for) ', line)
+      # Operators taken from [lex.operators] in C++11 standard.
+      and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line)
+      and not Search(r'operator=', line)):
+    error(filename, linenum, 'whitespace/operators', 4,
+          'Missing spaces around =')
+
+  # It's ok not to have spaces around binary operators like + - * /, but if
+  # there's too little whitespace, we get concerned.  It's hard to tell,
+  # though, so we punt on this one for now.  TODO.
+
+  # You should always have whitespace around binary operators.
+  #
+  # Check <= and >= first to avoid false positives with < and >, then
+  # check non-include lines for spacing around < and >.
+  #
+  # If the operator is followed by a comma, assume it's be used in a
+  # macro context and don't do any checks.  This avoids false
+  # positives.
+  #
+  # Note that && is not included here.  Those are checked separately
+  # in CheckRValueReference
+  match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line)
+  if match:
+    error(filename, linenum, 'whitespace/operators', 3,
+          'Missing spaces around %s' % match.group(1))
+  elif not Match(r'#.*include', line):
+    # Look for < that is not surrounded by spaces.  This is only
+    # triggered if both sides are missing spaces, even though
+    # technically should should flag if at least one side is missing a
+    # space.  This is done to avoid some false positives with shifts.
+    match = Match(r'^(.*[^\s<])<[^\s=<,]', line)
+    if match:
+      (_, _, end_pos) = CloseExpression(
+          clean_lines, linenum, len(match.group(1)))
+      if end_pos <= -1:
+        error(filename, linenum, 'whitespace/operators', 3,
+              'Missing spaces around <')
+
+    # Look for > that is not surrounded by spaces.  Similar to the
+    # above, we only trigger if both sides are missing spaces to avoid
+    # false positives with shifts.
+    match = Match(r'^(.*[^-\s>])>[^\s=>,]', line)
+    if match:
+      (_, _, start_pos) = ReverseCloseExpression(
+          clean_lines, linenum, len(match.group(1)))
+      if start_pos <= -1:
+        error(filename, linenum, 'whitespace/operators', 3,
+              'Missing spaces around >')
+
+  # We allow no-spaces around << when used like this: 10<<20, but
+  # not otherwise (particularly, not when used as streams)
+  #
+  # We also allow operators following an opening parenthesis, since
+  # those tend to be macros that deal with operators.
+  match = Search(r'(operator|[^\s(<])(?:L|UL|ULL|l|ul|ull)?<<([^\s,=<])', line)
+  if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and
+      not (match.group(1) == 'operator' and match.group(2) == ';')):
+    error(filename, linenum, 'whitespace/operators', 3,
+          'Missing spaces around <<')
+
+  # We allow no-spaces around >> for almost anything.  This is because
+  # C++11 allows ">>" to close nested templates, which accounts for
+  # most cases when ">>" is not followed by a space.
+  #
+  # We still warn on ">>" followed by alpha character, because that is
+  # likely due to ">>" being used for right shifts, e.g.:
+  #   value >> alpha
+  #
+  # When ">>" is used to close templates, the alphanumeric letter that
+  # follows would be part of an identifier, and there should still be
+  # a space separating the template type and the identifier.
+  #   type<type<type>> alpha
+  match = Search(r'>>[a-zA-Z_]', line)
+  if match:
+    error(filename, linenum, 'whitespace/operators', 3,
+          'Missing spaces around >>')
+
+  # There shouldn't be space around unary operators
+  match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
+  if match:
+    error(filename, linenum, 'whitespace/operators', 4,
+          'Extra space for operator %s' % match.group(1))
+
+
+def CheckParenthesisSpacing(filename, clean_lines, linenum, error):
+  """Checks for horizontal spacing around parentheses.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # No spaces after an if, while, switch, or for
+  match = Search(r' (if\(|for\(|while\(|switch\()', line)
+  if match:
+    error(filename, linenum, 'whitespace/parens', 5,
+          'Missing space before ( in %s' % match.group(1))
+
+  # For if/for/while/switch, the left and right parens should be
+  # consistent about how many spaces are inside the parens, and
+  # there should either be zero or one spaces inside the parens.
+  # We don't want: "if ( foo)" or "if ( foo   )".
+  # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
+  match = Search(r'\b(if|for|while|switch)\s*'
+                 r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$',
+                 line)
+  if match:
+    if len(match.group(2)) != len(match.group(4)):
+      if not (match.group(3) == ';' and
+              len(match.group(2)) == 1 + len(match.group(4)) or
+              not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)):
+        error(filename, linenum, 'whitespace/parens', 5,
+              'Mismatching spaces inside () in %s' % match.group(1))
+    if len(match.group(2)) not in [0, 1]:
+      error(filename, linenum, 'whitespace/parens', 5,
+            'Should have zero or one spaces inside ( and ) in %s' %
+            match.group(1))
+
+
+def CheckCommaSpacing(filename, clean_lines, linenum, error):
+  """Checks for horizontal spacing near commas and semicolons.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  raw = clean_lines.lines_without_raw_strings
+  line = clean_lines.elided[linenum]
+
+  # You should always have a space after a comma (either as fn arg or operator)
+  #
+  # This does not apply when the non-space character following the
+  # comma is another comma, since the only time when that happens is
+  # for empty macro arguments.
+  #
+  # We run this check in two passes: first pass on elided lines to
+  # verify that lines contain missing whitespaces, second pass on raw
+  # lines to confirm that those missing whitespaces are not due to
+  # elided comments.
+  if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and
+      Search(r',[^,\s]', raw[linenum])):
+    error(filename, linenum, 'whitespace/comma', 3,
+          'Missing space after ,')
+
+  # You should always have a space after a semicolon
+  # except for few corner cases
+  # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more
+  # space after ;
+  if Search(r';[^\s};\\)/]', line):
+    error(filename, linenum, 'whitespace/semicolon', 3,
+          'Missing space after ;')
+
+
+def CheckBracesSpacing(filename, clean_lines, linenum, error):
+  """Checks for horizontal spacing near commas.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Except after an opening paren, or after another opening brace (in case of
+  # an initializer list, for instance), you should have spaces before your
+  # braces. And since you should never have braces at the beginning of a line,
+  # this is an easy test.
+  match = Match(r'^(.*[^ ({>]){', line)
+  if match:
+    # Try a bit harder to check for brace initialization.  This
+    # happens in one of the following forms:
+    #   Constructor() : initializer_list_{} { ... }
+    #   Constructor{}.MemberFunction()
+    #   Type variable{};
+    #   FunctionCall(type{}, ...);
+    #   LastArgument(..., type{});
+    #   LOG(INFO) << type{} << " ...";
+    #   map_of_type[{...}] = ...;
+    #   ternary = expr ? new type{} : nullptr;
+    #   OuterTemplate<InnerTemplateConstructor<Type>{}>
+    #
+    # We check for the character following the closing brace, and
+    # silence the warning if it's one of those listed above, i.e.
+    # "{.;,)<>]:".
+    #
+    # To account for nested initializer list, we allow any number of
+    # closing braces up to "{;,)<".  We can't simply silence the
+    # warning on first sight of closing brace, because that would
+    # cause false negatives for things that are not initializer lists.
+    #   Silence this:         But not this:
+    #     Outer{                if (...) {
+    #       Inner{...}            if (...){  // Missing space before {
+    #     };                    }
+    #
+    # There is a false negative with this approach if people inserted
+    # spurious semicolons, e.g. "if (cond){};", but we will catch the
+    # spurious semicolon with a separate check.
+    (endline, endlinenum, endpos) = CloseExpression(
+        clean_lines, linenum, len(match.group(1)))
+    trailing_text = ''
+    if endpos > -1:
+      trailing_text = endline[endpos:]
+    for offset in xrange(endlinenum + 1,
+                         min(endlinenum + 3, clean_lines.NumLines() - 1)):
+      trailing_text += clean_lines.elided[offset]
+    if not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text):
+      error(filename, linenum, 'whitespace/braces', 5,
+            'Missing space before {')
+
+  # Make sure '} else {' has spaces.
+  if Search(r'}else', line):
+    error(filename, linenum, 'whitespace/braces', 5,
+          'Missing space before else')
+
+  # You shouldn't have a space before a semicolon at the end of the line.
+  # There's a special case for "for" since the style guide allows space before
+  # the semicolon there.
+  if Search(r':\s*;\s*$', line):
+    error(filename, linenum, 'whitespace/semicolon', 5,
+          'Semicolon defining empty statement. Use {} instead.')
+  elif Search(r'^\s*;\s*$', line):
+    error(filename, linenum, 'whitespace/semicolon', 5,
+          'Line contains only semicolon. If this should be an empty statement, '
+          'use {} instead.')
+  elif (Search(r'\s+;\s*$', line) and
+        not Search(r'\bfor\b', line)):
+    error(filename, linenum, 'whitespace/semicolon', 5,
+          'Extra space before last semicolon. If this should be an empty '
+          'statement, use {} instead.')
+
+
+def IsDecltype(clean_lines, linenum, column):
+  """Check if the token ending on (linenum, column) is decltype().
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: the number of the line to check.
+    column: end column of the token to check.
+  Returns:
+    True if this token is decltype() expression, False otherwise.
+  """
+  (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column)
+  if start_col < 0:
+    return False
+  if Search(r'\bdecltype\s*$', text[0:start_col]):
+    return True
+  return False
+
+
+def IsTemplateParameterList(clean_lines, linenum, column):
+  """Check if the token ending on (linenum, column) is the end of template<>.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: the number of the line to check.
+    column: end column of the token to check.
+  Returns:
+    True if this token is end of a template parameter list, False otherwise.
+  """
+  (_, startline, startpos) = ReverseCloseExpression(
+      clean_lines, linenum, column)
+  if (startpos > -1 and
+      Search(r'\btemplate\s*$', clean_lines.elided[startline][0:startpos])):
+    return True
+  return False
+
+
+def IsRValueType(typenames, clean_lines, nesting_state, linenum, column):
+  """Check if the token ending on (linenum, column) is a type.
+
+  Assumes that text to the right of the column is "&&" or a function
+  name.
+
+  Args:
+    typenames: set of type names from template-argument-list.
+    clean_lines: A CleansedLines instance containing the file.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    linenum: the number of the line to check.
+    column: end column of the token to check.
+  Returns:
+    True if this token is a type, False if we are not sure.
+  """
+  prefix = clean_lines.elided[linenum][0:column]
+
+  # Get one word to the left.  If we failed to do so, this is most
+  # likely not a type, since it's unlikely that the type name and "&&"
+  # would be split across multiple lines.
+  match = Match(r'^(.*)(\b\w+|[>*)&])\s*$', prefix)
+  if not match:
+    return False
+
+  # Check text following the token.  If it's "&&>" or "&&," or "&&...", it's
+  # most likely a rvalue reference used inside a template.
+  suffix = clean_lines.elided[linenum][column:]
+  if Match(r'&&\s*(?:[>,]|\.\.\.)', suffix):
+    return True
+
+  # Check for known types and end of templates:
+  #   int&& variable
+  #   vector<int>&& variable
+  #
+  # Because this function is called recursively, we also need to
+  # recognize pointer and reference types:
+  #   int* Function()
+  #   int& Function()
+  if (match.group(2) in typenames or
+      match.group(2) in ['char', 'char16_t', 'char32_t', 'wchar_t', 'bool',
+                         'short', 'int', 'long', 'signed', 'unsigned',
+                         'float', 'double', 'void', 'auto', '>', '*', '&']):
+    return True
+
+  # If we see a close parenthesis, look for decltype on the other side.
+  # decltype would unambiguously identify a type, anything else is
+  # probably a parenthesized expression and not a type.
+  if match.group(2) == ')':
+    return IsDecltype(
+        clean_lines, linenum, len(match.group(1)) + len(match.group(2)) - 1)
+
+  # Check for casts and cv-qualifiers.
+  #   match.group(1)  remainder
+  #   --------------  ---------
+  #   const_cast<     type&&
+  #   const           type&&
+  #   type            const&&
+  if Search(r'\b(?:const_cast\s*<|static_cast\s*<|dynamic_cast\s*<|'
+            r'reinterpret_cast\s*<|\w+\s)\s*$',
+            match.group(1)):
+    return True
+
+  # Look for a preceding symbol that might help differentiate the context.
+  # These are the cases that would be ambiguous:
+  #   match.group(1)  remainder
+  #   --------------  ---------
+  #   Call         (   expression &&
+  #   Declaration  (   type&&
+  #   sizeof       (   type&&
+  #   if           (   expression &&
+  #   while        (   expression &&
+  #   for          (   type&&
+  #   for(         ;   expression &&
+  #   statement    ;   type&&
+  #   block        {   type&&
+  #   constructor  {   expression &&
+  start = linenum
+  line = match.group(1)
+  match_symbol = None
+  while start >= 0:
+    # We want to skip over identifiers and commas to get to a symbol.
+    # Commas are skipped so that we can find the opening parenthesis
+    # for function parameter lists.
+    match_symbol = Match(r'^(.*)([^\w\s,])[\w\s,]*$', line)
+    if match_symbol:
+      break
+    start -= 1
+    line = clean_lines.elided[start]
+
+  if not match_symbol:
+    # Probably the first statement in the file is an rvalue reference
+    return True
+
+  if match_symbol.group(2) == '}':
+    # Found closing brace, probably an indicate of this:
+    #   block{} type&&
+    return True
+
+  if match_symbol.group(2) == ';':
+    # Found semicolon, probably one of these:
+    #   for(; expression &&
+    #   statement; type&&
+
+    # Look for the previous 'for(' in the previous lines.
+    before_text = match_symbol.group(1)
+    for i in xrange(start - 1, max(start - 6, 0), -1):
+      before_text = clean_lines.elided[i] + before_text
+    if Search(r'for\s*\([^{};]*$', before_text):
+      # This is the condition inside a for-loop
+      return False
+
+    # Did not find a for-init-statement before this semicolon, so this
+    # is probably a new statement and not a condition.
+    return True
+
+  if match_symbol.group(2) == '{':
+    # Found opening brace, probably one of these:
+    #   block{ type&& = ... ; }
+    #   constructor{ expression && expression }
+
+    # Look for a closing brace or a semicolon.  If we see a semicolon
+    # first, this is probably a rvalue reference.
+    line = clean_lines.elided[start][0:len(match_symbol.group(1)) + 1]
+    end = start
+    depth = 1
+    while True:
+      for ch in line:
+        if ch == ';':
+          return True
+        elif ch == '{':
+          depth += 1
+        elif ch == '}':
+          depth -= 1
+          if depth == 0:
+            return False
+      end += 1
+      if end >= clean_lines.NumLines():
+        break
+      line = clean_lines.elided[end]
+    # Incomplete program?
+    return False
+
+  if match_symbol.group(2) == '(':
+    # Opening parenthesis.  Need to check what's to the left of the
+    # parenthesis.  Look back one extra line for additional context.
+    before_text = match_symbol.group(1)
+    if linenum > 1:
+      before_text = clean_lines.elided[linenum - 1] + before_text
+    before_text = match_symbol.group(1)
+
+    # Patterns that are likely to be types:
+    #   [](type&&
+    #   for (type&&
+    #   sizeof(type&&
+    #   operator=(type&&
+    #
+    if Search(r'(?:\]|\bfor|\bsizeof|\boperator\s*\S+\s*)\s*$', before_text):
+      return True
+
+    # Patterns that are likely to be expressions:
+    #   if (expression &&
+    #   while (expression &&
+    #   : initializer(expression &&
+    #   , initializer(expression &&
+    #   ( FunctionCall(expression &&
+    #   + FunctionCall(expression &&
+    #   + (expression &&
+    #
+    # The last '+' represents operators such as '+' and '-'.
+    if Search(r'(?:\bif|\bwhile|[-+=%^(<!?:,&*]\s*)$', before_text):
+      return False
+
+    # Something else.  Check that tokens to the left look like
+    #   return_type function_name
+    match_func = Match(r'^(.*\S.*)\s+\w(?:\w|::)*(?:<[^<>]*>)?\s*$',
+                       match_symbol.group(1))
+    if match_func:
+      # Check for constructors, which don't have return types.
+      if Search(r'\b(?:explicit|inline)$', match_func.group(1)):
+        return True
+      implicit_constructor = Match(r'\s*(\w+)\((?:const\s+)?(\w+)', prefix)
+      if (implicit_constructor and
+          implicit_constructor.group(1) == implicit_constructor.group(2)):
+        return True
+      return IsRValueType(typenames, clean_lines, nesting_state, linenum,
+                          len(match_func.group(1)))
+
+    # Nothing before the function name.  If this is inside a block scope,
+    # this is probably a function call.
+    return not (nesting_state.previous_stack_top and
+                nesting_state.previous_stack_top.IsBlockInfo())
+
+  if match_symbol.group(2) == '>':
+    # Possibly a closing bracket, check that what's on the other side
+    # looks like the start of a template.
+    return IsTemplateParameterList(
+        clean_lines, start, len(match_symbol.group(1)))
+
+  # Some other symbol, usually something like "a=b&&c".  This is most
+  # likely not a type.
+  return False
+
+
+def IsDeletedOrDefault(clean_lines, linenum):
+  """Check if current constructor or operator is deleted or default.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+  Returns:
+    True if this is a deleted or default constructor.
+  """
+  open_paren = clean_lines.elided[linenum].find('(')
+  if open_paren < 0:
+    return False
+  (close_line, _, close_paren) = CloseExpression(
+      clean_lines, linenum, open_paren)
+  if close_paren < 0:
+    return False
+  return Match(r'\s*=\s*(?:delete|default)\b', close_line[close_paren:])
+
+
+def IsRValueAllowed(clean_lines, linenum, typenames):
+  """Check if RValue reference is allowed on a particular line.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    typenames: set of type names from template-argument-list.
+  Returns:
+    True if line is within the region where RValue references are allowed.
+  """
+  # Allow region marked by PUSH/POP macros
+  for i in xrange(linenum, 0, -1):
+    line = clean_lines.elided[i]
+    if Match(r'GOOGLE_ALLOW_RVALUE_REFERENCES_(?:PUSH|POP)', line):
+      if not line.endswith('PUSH'):
+        return False
+      for j in xrange(linenum, clean_lines.NumLines(), 1):
+        line = clean_lines.elided[j]
+        if Match(r'GOOGLE_ALLOW_RVALUE_REFERENCES_(?:PUSH|POP)', line):
+          return line.endswith('POP')
+
+  # Allow operator=
+  line = clean_lines.elided[linenum]
+  if Search(r'\boperator\s*=\s*\(', line):
+    return IsDeletedOrDefault(clean_lines, linenum)
+
+  # Allow constructors
+  match = Match(r'\s*(?:[\w<>]+::)*([\w<>]+)\s*::\s*([\w<>]+)\s*\(', line)
+  if match and match.group(1) == match.group(2):
+    return IsDeletedOrDefault(clean_lines, linenum)
+  if Search(r'\b(?:explicit|inline)\s+[\w<>]+\s*\(', line):
+    return IsDeletedOrDefault(clean_lines, linenum)
+
+  if Match(r'\s*[\w<>]+\s*\(', line):
+    previous_line = 'ReturnType'
+    if linenum > 0:
+      previous_line = clean_lines.elided[linenum - 1]
+    if Match(r'^\s*$', previous_line) or Search(r'[{}:;]\s*$', previous_line):
+      return IsDeletedOrDefault(clean_lines, linenum)
+
+  # Reject types not mentioned in template-argument-list
+  while line:
+    match = Match(r'^.*?(\w+)\s*&&(.*)$', line)
+    if not match:
+      break
+    if match.group(1) not in typenames:
+      return False
+    line = match.group(2)
+
+  # All RValue types that were in template-argument-list should have
+  # been removed by now.  Those were allowed, assuming that they will
+  # be forwarded.
+  #
+  # If there are no remaining RValue types left (i.e. types that were
+  # not found in template-argument-list), flag those as not allowed.
+  return line.find('&&') < 0
+
+
+def GetTemplateArgs(clean_lines, linenum):
+  """Find list of template arguments associated with this function declaration.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: Line number containing the start of the function declaration,
+             usually one line after the end of the template-argument-list.
+  Returns:
+    Set of type names, or empty set if this does not appear to have
+    any template parameters.
+  """
+  # Find start of function
+  func_line = linenum
+  while func_line > 0:
+    line = clean_lines.elided[func_line]
+    if Match(r'^\s*$', line):
+      return set()
+    if line.find('(') >= 0:
+      break
+    func_line -= 1
+  if func_line == 0:
+    return set()
+
+  # Collapse template-argument-list into a single string
+  argument_list = ''
+  match = Match(r'^(\s*template\s*)<', clean_lines.elided[func_line])
+  if match:
+    # template-argument-list on the same line as function name
+    start_col = len(match.group(1))
+    _, end_line, end_col = CloseExpression(clean_lines, func_line, start_col)
+    if end_col > -1 and end_line == func_line:
+      start_col += 1  # Skip the opening bracket
+      argument_list = clean_lines.elided[func_line][start_col:end_col]
+
+  elif func_line > 1:
+    # template-argument-list one line before function name
+    match = Match(r'^(.*)>\s*$', clean_lines.elided[func_line - 1])
+    if match:
+      end_col = len(match.group(1))
+      _, start_line, start_col = ReverseCloseExpression(
+          clean_lines, func_line - 1, end_col)
+      if start_col > -1:
+        start_col += 1  # Skip the opening bracket
+        while start_line < func_line - 1:
+          argument_list += clean_lines.elided[start_line][start_col:]
+          start_col = 0
+          start_line += 1
+        argument_list += clean_lines.elided[func_line - 1][start_col:end_col]
+
+  if not argument_list:
+    return set()
+
+  # Extract type names
+  typenames = set()
+  while True:
+    match = Match(r'^[,\s]*(?:typename|class)(?:\.\.\.)?\s+(\w+)(.*)$',
+                  argument_list)
+    if not match:
+      break
+    typenames.add(match.group(1))
+    argument_list = match.group(2)
+  return typenames
+
+
+def CheckRValueReference(filename, clean_lines, linenum, nesting_state, error):
+  """Check for rvalue references.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: The function to call with any errors found.
+  """
+  # Find lines missing spaces around &&.
+  # TODO(unknown): currently we don't check for rvalue references
+  # with spaces surrounding the && to avoid false positives with
+  # boolean expressions.
+  line = clean_lines.elided[linenum]
+  match = Match(r'^(.*\S)&&', line)
+  if not match:
+    match = Match(r'(.*)&&\S', line)
+  if (not match) or '(&&)' in line or Search(r'\boperator\s*$', match.group(1)):
+    return
+
+  # Either poorly formed && or an rvalue reference, check the context
+  # to get a more accurate error message.  Mostly we want to determine
+  # if what's to the left of "&&" is a type or not.
+  typenames = GetTemplateArgs(clean_lines, linenum)
+  and_pos = len(match.group(1))
+  if IsRValueType(typenames, clean_lines, nesting_state, linenum, and_pos):
+    if not IsRValueAllowed(clean_lines, linenum, typenames):
+      error(filename, linenum, 'build/c++11', 3,
+            'RValue references are an unapproved C++ feature.')
+  else:
+    error(filename, linenum, 'whitespace/operators', 3,
+          'Missing spaces around &&')
+
+
+def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error):
+  """Checks for additional blank line issues related to sections.
+
+  Currently the only thing checked here is blank line before protected/private.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    class_info: A _ClassInfo objects.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  # Skip checks if the class is small, where small means 25 lines or less.
+  # 25 lines seems like a good cutoff since that's the usual height of
+  # terminals, and any class that can't fit in one screen can't really
+  # be considered "small".
+  #
+  # Also skip checks if we are on the first line.  This accounts for
+  # classes that look like
+  #   class Foo { public: ... };
+  #
+  # If we didn't find the end of the class, last_line would be zero,
+  # and the check will be skipped by the first condition.
+  if (class_info.last_line - class_info.starting_linenum <= 24 or
+      linenum <= class_info.starting_linenum):
+    return
+
+  matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum])
+  if matched:
+    # Issue warning if the line before public/protected/private was
+    # not a blank line, but don't do this if the previous line contains
+    # "class" or "struct".  This can happen two ways:
+    #  - We are at the beginning of the class.
+    #  - We are forward-declaring an inner class that is semantically
+    #    private, but needed to be public for implementation reasons.
+    # Also ignores cases where the previous line ends with a backslash as can be
+    # common when defining classes in C macros.
+    prev_line = clean_lines.lines[linenum - 1]
+    if (not IsBlankLine(prev_line) and
+        not Search(r'\b(class|struct)\b', prev_line) and
+        not Search(r'\\$', prev_line)):
+      # Try a bit harder to find the beginning of the class.  This is to
+      # account for multi-line base-specifier lists, e.g.:
+      #   class Derived
+      #       : public Base {
+      end_class_head = class_info.starting_linenum
+      for i in range(class_info.starting_linenum, linenum):
+        if Search(r'\{\s*$', clean_lines.lines[i]):
+          end_class_head = i
+          break
+      if end_class_head < linenum - 1:
+        error(filename, linenum, 'whitespace/blank_line', 3,
+              '"%s:" should be preceded by a blank line' % matched.group(1))
+
+
+def GetPreviousNonBlankLine(clean_lines, linenum):
+  """Return the most recent non-blank line and its line number.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file contents.
+    linenum: The number of the line to check.
+
+  Returns:
+    A tuple with two elements.  The first element is the contents of the last
+    non-blank line before the current line, or the empty string if this is the
+    first non-blank line.  The second is the line number of that line, or -1
+    if this is the first non-blank line.
+  """
+
+  prevlinenum = linenum - 1
+  while prevlinenum >= 0:
+    prevline = clean_lines.elided[prevlinenum]
+    if not IsBlankLine(prevline):     # if not a blank line...
+      return (prevline, prevlinenum)
+    prevlinenum -= 1
+  return ('', -1)
+
+
+def CheckBraces(filename, clean_lines, linenum, error):
+  """Looks for misplaced braces (e.g. at the end of line).
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+
+  line = clean_lines.elided[linenum]        # get rid of comments and strings
+
+  if Match(r'\s*{\s*$', line):
+    # We allow an open brace to start a line in the case where someone is using
+    # braces in a block to explicitly create a new scope, which is commonly used
+    # to control the lifetime of stack-allocated variables.  Braces are also
+    # used for brace initializers inside function calls.  We don't detect this
+    # perfectly: we just don't complain if the last non-whitespace character on
+    # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the
+    # previous line starts a preprocessor block.
+    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+    if (not Search(r'[,;:}{(]\s*$', prevline) and
+        not Match(r'\s*#', prevline)):
+      error(filename, linenum, 'whitespace/braces', 4,
+            '{ should almost always be at the end of the previous line')
+
+  # An else clause should be on the same line as the preceding closing brace.
+  if Match(r'\s*else\b\s*(?:if\b|\{|$)', line):
+    prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+    if Match(r'\s*}\s*$', prevline):
+      error(filename, linenum, 'whitespace/newline', 4,
+            'An else should appear on the same line as the preceding }')
+
+  # If braces come on one side of an else, they should be on both.
+  # However, we have to worry about "else if" that spans multiple lines!
+  if Search(r'else if\s*\(', line):       # could be multi-line if
+    brace_on_left = bool(Search(r'}\s*else if\s*\(', line))
+    # find the ( after the if
+    pos = line.find('else if')
+    pos = line.find('(', pos)
+    if pos > 0:
+      (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos)
+      brace_on_right = endline[endpos:].find('{') != -1
+      if brace_on_left != brace_on_right:    # must be brace after if
+        error(filename, linenum, 'readability/braces', 5,
+              'If an else has a brace on one side, it should have it on both')
+  elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line):
+    error(filename, linenum, 'readability/braces', 5,
+          'If an else has a brace on one side, it should have it on both')
+
+  # Likewise, an else should never have the else clause on the same line
+  if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line):
+    error(filename, linenum, 'whitespace/newline', 4,
+          'Else clause should never be on same line as else (use 2 lines)')
+
+  # In the same way, a do/while should never be on one line
+  if Match(r'\s*do [^\s{]', line):
+    error(filename, linenum, 'whitespace/newline', 4,
+          'do/while clauses should not be on a single line')
+
+  # Check single-line if/else bodies. The style guide says 'curly braces are not
+  # required for single-line statements'. We additionally allow multi-line,
+  # single statements, but we reject anything with more than one semicolon in
+  # it. This means that the first semicolon after the if should be at the end of
+  # its line, and the line after that should have an indent level equal to or
+  # lower than the if. We also check for ambiguous if/else nesting without
+  # braces.
+  if_else_match = Search(r'\b(if\s*\(|else\b)', line)
+  if if_else_match and not Match(r'\s*#', line):
+    if_indent = GetIndentLevel(line)
+    endline, endlinenum, endpos = line, linenum, if_else_match.end()
+    if_match = Search(r'\bif\s*\(', line)
+    if if_match:
+      # This could be a multiline if condition, so find the end first.
+      pos = if_match.end() - 1
+      (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos)
+    # Check for an opening brace, either directly after the if or on the next
+    # line. If found, this isn't a single-statement conditional.
+    if (not Match(r'\s*{', endline[endpos:])
+        and not (Match(r'\s*$', endline[endpos:])
+                 and endlinenum < (len(clean_lines.elided) - 1)
+                 and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))):
+      while (endlinenum < len(clean_lines.elided)
+             and ';' not in clean_lines.elided[endlinenum][endpos:]):
+        endlinenum += 1
+        endpos = 0
+      if endlinenum < len(clean_lines.elided):
+        endline = clean_lines.elided[endlinenum]
+        # We allow a mix of whitespace and closing braces (e.g. for one-liner
+        # methods) and a single \ after the semicolon (for macros)
+        endpos = endline.find(';')
+        if not Match(r';[\s}]*(\\?)$', endline[endpos:]):
+          # Semicolon isn't the last character, there's something trailing.
+          # Output a warning if the semicolon is not contained inside
+          # a lambda expression.
+          if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$',
+                       endline):
+            error(filename, linenum, 'readability/braces', 4,
+                  'If/else bodies with multiple statements require braces')
+        elif endlinenum < len(clean_lines.elided) - 1:
+          # Make sure the next line is dedented
+          next_line = clean_lines.elided[endlinenum + 1]
+          next_indent = GetIndentLevel(next_line)
+          # With ambiguous nested if statements, this will error out on the
+          # if that *doesn't* match the else, regardless of whether it's the
+          # inner one or outer one.
+          if (if_match and Match(r'\s*else\b', next_line)
+              and next_indent != if_indent):
+            error(filename, linenum, 'readability/braces', 4,
+                  'Else clause should be indented at the same level as if. '
+                  'Ambiguous nested if/else chains require braces.')
+          elif next_indent > if_indent:
+            error(filename, linenum, 'readability/braces', 4,
+                  'If/else bodies with multiple statements require braces')
+
+
+def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
+  """Looks for redundant trailing semicolon.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+
+  line = clean_lines.elided[linenum]
+
+  # Block bodies should not be followed by a semicolon.  Due to C++11
+  # brace initialization, there are more places where semicolons are
+  # required than not, so we use a whitelist approach to check these
+  # rather than a blacklist.  These are the places where "};" should
+  # be replaced by just "}":
+  # 1. Some flavor of block following closing parenthesis:
+  #    for (;;) {};
+  #    while (...) {};
+  #    switch (...) {};
+  #    Function(...) {};
+  #    if (...) {};
+  #    if (...) else if (...) {};
+  #
+  # 2. else block:
+  #    if (...) else {};
+  #
+  # 3. const member function:
+  #    Function(...) const {};
+  #
+  # 4. Block following some statement:
+  #    x = 42;
+  #    {};
+  #
+  # 5. Block at the beginning of a function:
+  #    Function(...) {
+  #      {};
+  #    }
+  #
+  #    Note that naively checking for the preceding "{" will also match
+  #    braces inside multi-dimensional arrays, but this is fine since
+  #    that expression will not contain semicolons.
+  #
+  # 6. Block following another block:
+  #    while (true) {}
+  #    {};
+  #
+  # 7. End of namespaces:
+  #    namespace {};
+  #
+  #    These semicolons seems far more common than other kinds of
+  #    redundant semicolons, possibly due to people converting classes
+  #    to namespaces.  For now we do not warn for this case.
+  #
+  # Try matching case 1 first.
+  match = Match(r'^(.*\)\s*)\{', line)
+  if match:
+    # Matched closing parenthesis (case 1).  Check the token before the
+    # matching opening parenthesis, and don't warn if it looks like a
+    # macro.  This avoids these false positives:
+    #  - macro that defines a base class
+    #  - multi-line macro that defines a base class
+    #  - macro that defines the whole class-head
+    #
+    # But we still issue warnings for macros that we know are safe to
+    # warn, specifically:
+    #  - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P
+    #  - TYPED_TEST
+    #  - INTERFACE_DEF
+    #  - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED:
+    #
+    # We implement a whitelist of safe macros instead of a blacklist of
+    # unsafe macros, even though the latter appears less frequently in
+    # google code and would have been easier to implement.  This is because
+    # the downside for getting the whitelist wrong means some extra
+    # semicolons, while the downside for getting the blacklist wrong
+    # would result in compile errors.
+    #
+    # In addition to macros, we also don't want to warn on
+    #  - Compound literals
+    #  - Lambdas
+    #  - alignas specifier with anonymous structs:
+    closing_brace_pos = match.group(1).rfind(')')
+    opening_parenthesis = ReverseCloseExpression(
+        clean_lines, linenum, closing_brace_pos)
+    if opening_parenthesis[2] > -1:
+      line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]]
+      macro = Search(r'\b([A-Z_]+)\s*$', line_prefix)
+      func = Match(r'^(.*\])\s*$', line_prefix)
+      if ((macro and
+           macro.group(1) not in (
+               'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST',
+               'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED',
+               'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or
+          (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or
+          Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or
+          Search(r'\s+=\s*$', line_prefix)):
+        match = None
+    if (match and
+        opening_parenthesis[1] > 1 and
+        Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])):
+      # Multi-line lambda-expression
+      match = None
+
+  else:
+    # Try matching cases 2-3.
+    match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line)
+    if not match:
+      # Try matching cases 4-6.  These are always matched on separate lines.
+      #
+      # Note that we can't simply concatenate the previous line to the
+      # current line and do a single match, otherwise we may output
+      # duplicate warnings for the blank line case:
+      #   if (cond) {
+      #     // blank line
+      #   }
+      prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0]
+      if prevline and Search(r'[;{}]\s*$', prevline):
+        match = Match(r'^(\s*)\{', line)
+
+  # Check matching closing brace
+  if match:
+    (endline, endlinenum, endpos) = CloseExpression(
+        clean_lines, linenum, len(match.group(1)))
+    if endpos > -1 and Match(r'^\s*;', endline[endpos:]):
+      # Current {} pair is eligible for semicolon check, and we have found
+      # the redundant semicolon, output warning here.
+      #
+      # Note: because we are scanning forward for opening braces, and
+      # outputting warnings for the matching closing brace, if there are
+      # nested blocks with trailing semicolons, we will get the error
+      # messages in reversed order.
+      error(filename, endlinenum, 'readability/braces', 4,
+            "You don't need a ; after a }")
+
+
+def CheckEmptyBlockBody(filename, clean_lines, linenum, error):
+  """Look for empty loop/conditional body with only a single semicolon.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+
+  # Search for loop keywords at the beginning of the line.  Because only
+  # whitespaces are allowed before the keywords, this will also ignore most
+  # do-while-loops, since those lines should start with closing brace.
+  #
+  # We also check "if" blocks here, since an empty conditional block
+  # is likely an error.
+  line = clean_lines.elided[linenum]
+  matched = Match(r'\s*(for|while|if)\s*\(', line)
+  if matched:
+    # Find the end of the conditional expression
+    (end_line, end_linenum, end_pos) = CloseExpression(
+        clean_lines, linenum, line.find('('))
+
+    # Output warning if what follows the condition expression is a semicolon.
+    # No warning for all other cases, including whitespace or newline, since we
+    # have a separate check for semicolons preceded by whitespace.
+    if end_pos >= 0 and Match(r';', end_line[end_pos:]):
+      if matched.group(1) == 'if':
+        error(filename, end_linenum, 'whitespace/empty_conditional_body', 5,
+              'Empty conditional bodies should use {}')
+      else:
+        error(filename, end_linenum, 'whitespace/empty_loop_body', 5,
+              'Empty loop bodies should use {} or continue')
+
+
+def FindCheckMacro(line):
+  """Find a replaceable CHECK-like macro.
+
+  Args:
+    line: line to search on.
+  Returns:
+    (macro name, start position), or (None, -1) if no replaceable
+    macro is found.
+  """
+  for macro in _CHECK_MACROS:
+    i = line.find(macro)
+    if i >= 0:
+      # Find opening parenthesis.  Do a regular expression match here
+      # to make sure that we are matching the expected CHECK macro, as
+      # opposed to some other macro that happens to contain the CHECK
+      # substring.
+      matched = Match(r'^(.*\b' + macro + r'\s*)\(', line)
+      if not matched:
+        continue
+      return (macro, len(matched.group(1)))
+  return (None, -1)
+
+
+def CheckCheck(filename, clean_lines, linenum, error):
+  """Checks the use of CHECK and EXPECT macros.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+
+  # Decide the set of replacement macros that should be suggested
+  lines = clean_lines.elided
+  (check_macro, start_pos) = FindCheckMacro(lines[linenum])
+  if not check_macro:
+    return
+
+  # Find end of the boolean expression by matching parentheses
+  (last_line, end_line, end_pos) = CloseExpression(
+      clean_lines, linenum, start_pos)
+  if end_pos < 0:
+    return
+
+  # If the check macro is followed by something other than a
+  # semicolon, assume users will log their own custom error messages
+  # and don't suggest any replacements.
+  if not Match(r'\s*;', last_line[end_pos:]):
+    return
+
+  if linenum == end_line:
+    expression = lines[linenum][start_pos + 1:end_pos - 1]
+  else:
+    expression = lines[linenum][start_pos + 1:]
+    for i in xrange(linenum + 1, end_line):
+      expression += lines[i]
+    expression += last_line[0:end_pos - 1]
+
+  # Parse expression so that we can take parentheses into account.
+  # This avoids false positives for inputs like "CHECK((a < 4) == b)",
+  # which is not replaceable by CHECK_LE.
+  lhs = ''
+  rhs = ''
+  operator = None
+  while expression:
+    matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||'
+                    r'==|!=|>=|>|<=|<|\()(.*)$', expression)
+    if matched:
+      token = matched.group(1)
+      if token == '(':
+        # Parenthesized operand
+        expression = matched.group(2)
+        (end, _) = FindEndOfExpressionInLine(expression, 0, ['('])
+        if end < 0:
+          return  # Unmatched parenthesis
+        lhs += '(' + expression[0:end]
+        expression = expression[end:]
+      elif token in ('&&', '||'):
+        # Logical and/or operators.  This means the expression
+        # contains more than one term, for example:
+        #   CHECK(42 < a && a < b);
+        #
+        # These are not replaceable with CHECK_LE, so bail out early.
+        return
+      elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'):
+        # Non-relational operator
+        lhs += token
+        expression = matched.group(2)
+      else:
+        # Relational operator
+        operator = token
+        rhs = matched.group(2)
+        break
+    else:
+      # Unparenthesized operand.  Instead of appending to lhs one character
+      # at a time, we do another regular expression match to consume several
+      # characters at once if possible.  Trivial benchmark shows that this
+      # is more efficient when the operands are longer than a single
+      # character, which is generally the case.
+      matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression)
+      if not matched:
+        matched = Match(r'^(\s*\S)(.*)$', expression)
+        if not matched:
+          break
+      lhs += matched.group(1)
+      expression = matched.group(2)
+
+  # Only apply checks if we got all parts of the boolean expression
+  if not (lhs and operator and rhs):
+    return
+
+  # Check that rhs do not contain logical operators.  We already know
+  # that lhs is fine since the loop above parses out && and ||.
+  if rhs.find('&&') > -1 or rhs.find('||') > -1:
+    return
+
+  # At least one of the operands must be a constant literal.  This is
+  # to avoid suggesting replacements for unprintable things like
+  # CHECK(variable != iterator)
+  #
+  # The following pattern matches decimal, hex integers, strings, and
+  # characters (in that order).
+  lhs = lhs.strip()
+  rhs = rhs.strip()
+  match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$'
+  if Match(match_constant, lhs) or Match(match_constant, rhs):
+    # Note: since we know both lhs and rhs, we can provide a more
+    # descriptive error message like:
+    #   Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42)
+    # Instead of:
+    #   Consider using CHECK_EQ instead of CHECK(a == b)
+    #
+    # We are still keeping the less descriptive message because if lhs
+    # or rhs gets long, the error message might become unreadable.
+    error(filename, linenum, 'readability/check', 2,
+          'Consider using %s instead of %s(a %s b)' % (
+              _CHECK_REPLACEMENT[check_macro][operator],
+              check_macro, operator))
+
+
+def CheckAltTokens(filename, clean_lines, linenum, error):
+  """Check alternative keywords being used in boolean expressions.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Avoid preprocessor lines
+  if Match(r'^\s*#', line):
+    return
+
+  # Last ditch effort to avoid multi-line comments.  This will not help
+  # if the comment started before the current line or ended after the
+  # current line, but it catches most of the false positives.  At least,
+  # it provides a way to workaround this warning for people who use
+  # multi-line comments in preprocessor macros.
+  #
+  # TODO(unknown): remove this once cpplint has better support for
+  # multi-line comments.
+  if line.find('/*') >= 0 or line.find('*/') >= 0:
+    return
+
+  for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line):
+    error(filename, linenum, 'readability/alt_tokens', 2,
+          'Use operator %s instead of %s' % (
+              _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1)))
+
+
+def GetLineWidth(line):
+  """Determines the width of the line in column positions.
+
+  Args:
+    line: A string, which may be a Unicode string.
+
+  Returns:
+    The width of the line in column positions, accounting for Unicode
+    combining characters and wide characters.
+  """
+  if isinstance(line, unicode):
+    width = 0
+    for uc in unicodedata.normalize('NFC', line):
+      if unicodedata.east_asian_width(uc) in ('W', 'F'):
+        width += 2
+      elif not unicodedata.combining(uc):
+        width += 1
+    return width
+  else:
+    return len(line)
+
+
+def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
+               error):
+  """Checks rules from the 'C++ style rules' section of cppguide.html.
+
+  Most of these rules are hard to test (naming, comment style), but we
+  do what we can.  In particular we check for 2-space indents, line lengths,
+  tab usage, spaces inside code, etc.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    file_extension: The extension (without the dot) of the filename.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: The function to call with any errors found.
+  """
+
+  # Don't use "elided" lines here, otherwise we can't check commented lines.
+  # Don't want to use "raw" either, because we don't want to check inside C++11
+  # raw strings,
+  raw_lines = clean_lines.lines_without_raw_strings
+  line = raw_lines[linenum]
+
+  if line.find('\t') != -1:
+    error(filename, linenum, 'whitespace/tab', 1,
+          'Tab found; better to use spaces')
+
+  # One or three blank spaces at the beginning of the line is weird; it's
+  # hard to reconcile that with 2-space indents.
+  # NOTE: here are the conditions rob pike used for his tests.  Mine aren't
+  # as sophisticated, but it may be worth becoming so:  RLENGTH==initial_spaces
+  # if(RLENGTH > 20) complain = 0;
+  # if(match($0, " +(error|private|public|protected):")) complain = 0;
+  # if(match(prev, "&& *$")) complain = 0;
+  # if(match(prev, "\\|\\| *$")) complain = 0;
+  # if(match(prev, "[\",=><] *$")) complain = 0;
+  # if(match($0, " <<")) complain = 0;
+  # if(match(prev, " +for \\(")) complain = 0;
+  # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
+  scope_or_label_pattern = r'\s*\w+\s*:\s*\\?$'
+  classinfo = nesting_state.InnermostClass()
+  initial_spaces = 0
+  cleansed_line = clean_lines.elided[linenum]
+  while initial_spaces < len(line) and line[initial_spaces] == ' ':
+    initial_spaces += 1
+  if line and line[-1].isspace():
+    error(filename, linenum, 'whitespace/end_of_line', 4,
+          'Line ends in whitespace.  Consider deleting these extra spaces.')
+  # There are certain situations we allow one space, notably for
+  # section labels, and also lines containing multi-line raw strings.
+  elif ((initial_spaces == 1 or initial_spaces == 3) and
+        not Match(scope_or_label_pattern, cleansed_line) and
+        not (clean_lines.raw_lines[linenum] != line and
+             Match(r'^\s*""', line))):
+    error(filename, linenum, 'whitespace/indent', 3,
+          'Weird number of spaces at line-start.  '
+          'Are you using a 2-space indent?')
+
+  # Check if the line is a header guard.
+  is_header_guard = False
+  if file_extension == 'h':
+    cppvar = GetHeaderGuardCPPVariable(filename)
+    if (line.startswith('#ifndef %s' % cppvar) or
+        line.startswith('#define %s' % cppvar) or
+        line.startswith('#endif  // %s' % cppvar)):
+      is_header_guard = True
+  # #include lines and header guards can be long, since there's no clean way to
+  # split them.
+  #
+  # URLs can be long too.  It's possible to split these, but it makes them
+  # harder to cut&paste.
+  #
+  # The "$Id:...$" comment may also get very long without it being the
+  # developers fault.
+  if (not line.startswith('#include') and not is_header_guard and
+      not Match(r'^\s*//.*http(s?)://\S*$', line) and
+      not Match(r'^// \$Id:.*#[0-9]+ \$$', line)):
+    line_width = GetLineWidth(line)
+    extended_length = int((_line_length * 1.25))
+    if line_width > extended_length:
+      error(filename, linenum, 'whitespace/line_length', 4,
+            'Lines should very rarely be longer than %i characters' %
+            extended_length)
+    elif line_width > _line_length:
+      error(filename, linenum, 'whitespace/line_length', 2,
+            'Lines should be <= %i characters long' % _line_length)
+
+  if (cleansed_line.count(';') > 1 and
+      # for loops are allowed two ;'s (and may run over two lines).
+      cleansed_line.find('for') == -1 and
+      (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or
+       GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and
+      # It's ok to have many commands in a switch case that fits in 1 line
+      not ((cleansed_line.find('case ') != -1 or
+            cleansed_line.find('default:') != -1) and
+           cleansed_line.find('break;') != -1)):
+    error(filename, linenum, 'whitespace/newline', 0,
+          'More than one command on the same line')
+
+  # Some more style checks
+  CheckBraces(filename, clean_lines, linenum, error)
+  CheckTrailingSemicolon(filename, clean_lines, linenum, error)
+  CheckEmptyBlockBody(filename, clean_lines, linenum, error)
+  CheckAccess(filename, clean_lines, linenum, nesting_state, error)
+  CheckSpacing(filename, clean_lines, linenum, nesting_state, error)
+  CheckOperatorSpacing(filename, clean_lines, linenum, error)
+  CheckParenthesisSpacing(filename, clean_lines, linenum, error)
+  CheckCommaSpacing(filename, clean_lines, linenum, error)
+  CheckBracesSpacing(filename, clean_lines, linenum, error)
+  CheckSpacingForFunctionCall(filename, clean_lines, linenum, error)
+  CheckRValueReference(filename, clean_lines, linenum, nesting_state, error)
+  CheckCheck(filename, clean_lines, linenum, error)
+  CheckAltTokens(filename, clean_lines, linenum, error)
+  classinfo = nesting_state.InnermostClass()
+  if classinfo:
+    CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error)
+
+
+_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
+# Matches the first component of a filename delimited by -s and _s. That is:
+#  _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
+#  _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo'
+#  _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo'
+#  _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo'
+_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
+
+
+def _DropCommonSuffixes(filename):
+  """Drops common suffixes like _test.cc or -inl.h from filename.
+
+  For example:
+    >>> _DropCommonSuffixes('foo/foo-inl.h')
+    'foo/foo'
+    >>> _DropCommonSuffixes('foo/bar/foo.cc')
+    'foo/bar/foo'
+    >>> _DropCommonSuffixes('foo/foo_internal.h')
+    'foo/foo'
+    >>> _DropCommonSuffixes('foo/foo_unusualinternal.h')
+    'foo/foo_unusualinternal'
+
+  Args:
+    filename: The input filename.
+
+  Returns:
+    The filename with the common suffix removed.
+  """
+  for suffix in ('test.cc', 'regtest.cc', 'unittest.cc',
+                 'inl.h', 'impl.h', 'internal.h'):
+    if (filename.endswith(suffix) and len(filename) > len(suffix) and
+        filename[-len(suffix) - 1] in ('-', '_')):
+      return filename[:-len(suffix) - 1]
+  return os.path.splitext(filename)[0]
+
+
+def _IsTestFilename(filename):
+  """Determines if the given filename has a suffix that identifies it as a test.
+
+  Args:
+    filename: The input filename.
+
+  Returns:
+    True if 'filename' looks like a test, False otherwise.
+  """
+  if (filename.endswith('_test.cc') or
+      filename.endswith('_unittest.cc') or
+      filename.endswith('_regtest.cc')):
+    return True
+  else:
+    return False
+
+
+def _ClassifyInclude(fileinfo, include, is_system):
+  """Figures out what kind of header 'include' is.
+
+  Args:
+    fileinfo: The current file cpplint is running over. A FileInfo instance.
+    include: The path to a #included file.
+    is_system: True if the #include used <> rather than "".
+
+  Returns:
+    One of the _XXX_HEADER constants.
+
+  For example:
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True)
+    _C_SYS_HEADER
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True)
+    _CPP_SYS_HEADER
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False)
+    _LIKELY_MY_HEADER
+    >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'),
+    ...                  'bar/foo_other_ext.h', False)
+    _POSSIBLE_MY_HEADER
+    >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False)
+    _OTHER_HEADER
+  """
+  # This is a list of all standard c++ header files, except
+  # those already checked for above.
+  is_cpp_h = include in _CPP_HEADERS
+
+  if is_system:
+    if is_cpp_h:
+      return _CPP_SYS_HEADER
+    else:
+      return _C_SYS_HEADER
+
+  # If the target file and the include we're checking share a
+  # basename when we drop common extensions, and the include
+  # lives in . , then it's likely to be owned by the target file.
+  target_dir, target_base = (
+      os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName())))
+  include_dir, include_base = os.path.split(_DropCommonSuffixes(include))
+  if target_base == include_base and (
+      include_dir == target_dir or
+      include_dir == os.path.normpath(target_dir + '/../public')):
+    return _LIKELY_MY_HEADER
+
+  # If the target and include share some initial basename
+  # component, it's possible the target is implementing the
+  # include, so it's allowed to be first, but we'll never
+  # complain if it's not there.
+  target_first_component = _RE_FIRST_COMPONENT.match(target_base)
+  include_first_component = _RE_FIRST_COMPONENT.match(include_base)
+  if (target_first_component and include_first_component and
+      target_first_component.group(0) ==
+      include_first_component.group(0)):
+    return _POSSIBLE_MY_HEADER
+
+  return _OTHER_HEADER
+
+
+
+def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
+  """Check rules that are applicable to #include lines.
+
+  Strings on #include lines are NOT removed from elided line, to make
+  certain tasks easier. However, to prevent false positives, checks
+  applicable to #include lines in CheckLanguage must be put here.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    include_state: An _IncludeState instance in which the headers are inserted.
+    error: The function to call with any errors found.
+  """
+  fileinfo = FileInfo(filename)
+  line = clean_lines.lines[linenum]
+
+  # "include" should use the new style "foo/bar.h" instead of just "bar.h"
+  # Only do this check if the included header follows google naming
+  # conventions.  If not, assume that it's a 3rd party API that
+  # requires special include conventions.
+  #
+  # We also make an exception for Lua headers, which follow google
+  # naming convention but not the include convention.
+  match = Match(r'#include\s*"([^/]+\.h)"', line)
+  if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)):
+    error(filename, linenum, 'build/include', 4,
+          'Include the directory when naming .h files')
+
+  # we shouldn't include a file more than once. actually, there are a
+  # handful of instances where doing so is okay, but in general it's
+  # not.
+  match = _RE_PATTERN_INCLUDE.search(line)
+  if match:
+    include = match.group(2)
+    is_system = (match.group(1) == '<')
+    duplicate_line = include_state.FindHeader(include)
+    if duplicate_line >= 0:
+      error(filename, linenum, 'build/include', 4,
+            '"%s" already included at %s:%s' %
+            (include, filename, duplicate_line))
+    elif (include.endswith('.cc') and
+          os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)):
+      error(filename, linenum, 'build/include', 4,
+            'Do not include .cc files from other packages')
+    elif not _THIRD_PARTY_HEADERS_PATTERN.match(include):
+      include_state.include_list[-1].append((include, linenum))
+
+      # We want to ensure that headers appear in the right order:
+      # 1) for foo.cc, foo.h  (preferred location)
+      # 2) c system files
+      # 3) cpp system files
+      # 4) for foo.cc, foo.h  (deprecated location)
+      # 5) other google headers
+      #
+      # We classify each include statement as one of those 5 types
+      # using a number of techniques. The include_state object keeps
+      # track of the highest type seen, and complains if we see a
+      # lower type after that.
+      error_message = include_state.CheckNextIncludeOrder(
+          _ClassifyInclude(fileinfo, include, is_system))
+      if error_message:
+        error(filename, linenum, 'build/include_order', 4,
+              '%s. Should be: %s.h, c system, c++ system, other.' %
+              (error_message, fileinfo.BaseName()))
+      canonical_include = include_state.CanonicalizeAlphabeticalOrder(include)
+      if not include_state.IsInAlphabeticalOrder(
+          clean_lines, linenum, canonical_include):
+        error(filename, linenum, 'build/include_alpha', 4,
+              'Include "%s" not in alphabetical order' % include)
+      include_state.SetLastHeader(canonical_include)
+
+
+
+def _GetTextInside(text, start_pattern):
+  r"""Retrieves all the text between matching open and close parentheses.
+
+  Given a string of lines and a regular expression string, retrieve all the text
+  following the expression and between opening punctuation symbols like
+  (, [, or {, and the matching close-punctuation symbol. This properly nested
+  occurrences of the punctuations, so for the text like
+    printf(a(), b(c()));
+  a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'.
+  start_pattern must match string having an open punctuation symbol at the end.
+
+  Args:
+    text: The lines to extract text. Its comments and strings must be elided.
+           It can be single line and can span multiple lines.
+    start_pattern: The regexp string indicating where to start extracting
+                   the text.
+  Returns:
+    The extracted text.
+    None if either the opening string or ending punctuation could not be found.
+  """
+  # TODO(unknown): Audit cpplint.py to see what places could be profitably
+  # rewritten to use _GetTextInside (and use inferior regexp matching today).
+
+  # Give opening punctuations to get the matching close-punctuations.
+  matching_punctuation = {'(': ')', '{': '}', '[': ']'}
+  closing_punctuation = set(matching_punctuation.itervalues())
+
+  # Find the position to start extracting text.
+  match = re.search(start_pattern, text, re.M)
+  if not match:  # start_pattern not found in text.
+    return None
+  start_position = match.end(0)
+
+  assert start_position > 0, (
+      'start_pattern must ends with an opening punctuation.')
+  assert text[start_position - 1] in matching_punctuation, (
+      'start_pattern must ends with an opening punctuation.')
+  # Stack of closing punctuations we expect to have in text after position.
+  punctuation_stack = [matching_punctuation[text[start_position - 1]]]
+  position = start_position
+  while punctuation_stack and position < len(text):
+    if text[position] == punctuation_stack[-1]:
+      punctuation_stack.pop()
+    elif text[position] in closing_punctuation:
+      # A closing punctuation without matching opening punctuations.
+      return None
+    elif text[position] in matching_punctuation:
+      punctuation_stack.append(matching_punctuation[text[position]])
+    position += 1
+  if punctuation_stack:
+    # Opening punctuations left without matching close-punctuations.
+    return None
+  # punctuations match.
+  return text[start_position:position - 1]
+
+
+# Patterns for matching call-by-reference parameters.
+#
+# Supports nested templates up to 2 levels deep using this messy pattern:
+#   < (?: < (?: < [^<>]*
+#               >
+#           |   [^<>] )*
+#         >
+#     |   [^<>] )*
+#   >
+_RE_PATTERN_IDENT = r'[_a-zA-Z]\w*'  # =~ [[:alpha:]][[:alnum:]]*
+_RE_PATTERN_TYPE = (
+    r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?'
+    r'(?:\w|'
+    r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|'
+    r'::)+')
+# A call-by-reference parameter ends with '& identifier'.
+_RE_PATTERN_REF_PARAM = re.compile(
+    r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*'
+    r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]')
+# A call-by-const-reference parameter either ends with 'const& identifier'
+# or looks like 'const type& identifier' when 'type' is atomic.
+_RE_PATTERN_CONST_REF_PARAM = (
+    r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT +
+    r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')')
+
+
+def CheckLanguage(filename, clean_lines, linenum, file_extension,
+                  include_state, nesting_state, error):
+  """Checks rules from the 'C++ language rules' section of cppguide.html.
+
+  Some of these rules are hard to test (function overloading, using
+  uint32 inappropriately), but we do the best we can.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    file_extension: The extension (without the dot) of the filename.
+    include_state: An _IncludeState instance in which the headers are inserted.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: The function to call with any errors found.
+  """
+  # If the line is empty or consists of entirely a comment, no need to
+  # check it.
+  line = clean_lines.elided[linenum]
+  if not line:
+    return
+
+  match = _RE_PATTERN_INCLUDE.search(line)
+  if match:
+    CheckIncludeLine(filename, clean_lines, linenum, include_state, error)
+    return
+
+  # Reset include state across preprocessor directives.  This is meant
+  # to silence warnings for conditional includes.
+  match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line)
+  if match:
+    include_state.ResetSection(match.group(1))
+
+  # Make Windows paths like Unix.
+  fullname = os.path.abspath(filename).replace('\\', '/')
+  
+  # Perform other checks now that we are sure that this is not an include line
+  CheckCasts(filename, clean_lines, linenum, error)
+  CheckGlobalStatic(filename, clean_lines, linenum, error)
+  CheckPrintf(filename, clean_lines, linenum, error)
+
+  if file_extension == 'h':
+    # TODO(unknown): check that 1-arg constructors are explicit.
+    #                How to tell it's a constructor?
+    #                (handled in CheckForNonStandardConstructs for now)
+    # TODO(unknown): check that classes declare or disable copy/assign
+    #                (level 1 error)
+    pass
+
+  # Check if people are using the verboten C basic types.  The only exception
+  # we regularly allow is "unsigned short port" for port.
+  if Search(r'\bshort port\b', line):
+    if not Search(r'\bunsigned short port\b', line):
+      error(filename, linenum, 'runtime/int', 4,
+            'Use "unsigned short" for ports, not "short"')
+  else:
+    match = Search(r'\b(short|long(?! +double)|long long)\b', line)
+    if match:
+      error(filename, linenum, 'runtime/int', 4,
+            'Use int16/int64/etc, rather than the C type %s' % match.group(1))
+
+  # Check if some verboten operator overloading is going on
+  # TODO(unknown): catch out-of-line unary operator&:
+  #   class X {};
+  #   int operator&(const X& x) { return 42; }  // unary operator&
+  # The trick is it's hard to tell apart from binary operator&:
+  #   class Y { int operator&(const Y& x) { return 23; } }; // binary operator&
+  if Search(r'\boperator\s*&\s*\(\s*\)', line):
+    error(filename, linenum, 'runtime/operator', 4,
+          'Unary operator& is dangerous.  Do not use it.')
+
+  # Check for suspicious usage of "if" like
+  # } if (a == b) {
+  if Search(r'\}\s*if\s*\(', line):
+    error(filename, linenum, 'readability/braces', 4,
+          'Did you mean "else if"? If not, start a new line for "if".')
+
+  # Check for potential format string bugs like printf(foo).
+  # We constrain the pattern not to pick things like DocidForPrintf(foo).
+  # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
+  # TODO(unknown): Catch the following case. Need to change the calling
+  # convention of the whole function to process multiple line to handle it.
+  #   printf(
+  #       boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line);
+  printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(')
+  if printf_args:
+    match = Match(r'([\w.\->()]+)$', printf_args)
+    if match and match.group(1) != '__VA_ARGS__':
+      function_name = re.search(r'\b((?:string)?printf)\s*\(',
+                                line, re.I).group(1)
+      error(filename, linenum, 'runtime/printf', 4,
+            'Potential format string bug. Do %s("%%s", %s) instead.'
+            % (function_name, match.group(1)))
+
+  # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
+  match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
+  if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)):
+    error(filename, linenum, 'runtime/memset', 4,
+          'Did you mean "memset(%s, 0, %s)"?'
+          % (match.group(1), match.group(2)))
+
+  if Search(r'\busing namespace\b', line):
+    error(filename, linenum, 'build/namespaces', 5,
+          'Do not use namespace using-directives.  '
+          'Use using-declarations instead.')
+
+  # Detect variable-length arrays.
+  match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
+  if (match and match.group(2) != 'return' and match.group(2) != 'delete' and
+      match.group(3).find(']') == -1):
+    # Split the size using space and arithmetic operators as delimiters.
+    # If any of the resulting tokens are not compile time constants then
+    # report the error.
+    tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3))
+    is_const = True
+    skip_next = False
+    for tok in tokens:
+      if skip_next:
+        skip_next = False
+        continue
+
+      if Search(r'sizeof\(.+\)', tok): continue
+      if Search(r'arraysize\(\w+\)', tok): continue
+
+      tok = tok.lstrip('(')
+      tok = tok.rstrip(')')
+      if not tok: continue
+      if Match(r'\d+', tok): continue
+      if Match(r'0[xX][0-9a-fA-F]+', tok): continue
+      if Match(r'k[A-Z0-9]\w*', tok): continue
+      if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue
+      if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue
+      # A catch all for tricky sizeof cases, including 'sizeof expression',
+      # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
+      # requires skipping the next token because we split on ' ' and '*'.
+      if tok.startswith('sizeof'):
+        skip_next = True
+        continue
+      is_const = False
+      break
+    if not is_const:
+      error(filename, linenum, 'runtime/arrays', 1,
+            'Do not use variable-length arrays.  Use an appropriately named '
+            "('k' followed by CamelCase) compile-time constant for the size.")
+
+  # Check for use of unnamed namespaces in header files.  Registration
+  # macros are typically OK, so we allow use of "namespace {" on lines
+  # that end with backslashes.
+  if (file_extension == 'h'
+      and Search(r'\bnamespace\s*{', line)
+      and line[-1] != '\\'):
+    error(filename, linenum, 'build/namespaces', 4,
+          'Do not use unnamed namespaces in header files.  See '
+          'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+          ' for more information.')
+
+
+def CheckGlobalStatic(filename, clean_lines, linenum, error):
+  """Check for unsafe global or static objects.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Match two lines at a time to support multiline declarations
+  if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line):
+    line += clean_lines.elided[linenum + 1].strip()
+
+  # Check for people declaring static/global STL strings at the top level.
+  # This is dangerous because the C++ language does not guarantee that
+  # globals with constructors are initialized before the first access.
+  match = Match(
+      r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
+      line)
+
+  # Remove false positives:
+  # - String pointers (as opposed to values).
+  #    string *pointer
+  #    const string *pointer
+  #    string const *pointer
+  #    string *const pointer
+  #
+  # - Functions and template specializations.
+  #    string Function<Type>(...
+  #    string Class<Type>::Method(...
+  #
+  # - Operators.  These are matched separately because operator names
+  #   cross non-word boundaries, and trying to match both operators
+  #   and functions at the same time would decrease accuracy of
+  #   matching identifiers.
+  #    string Class::operator*()
+  if (match and
+      not Search(r'\bstring\b(\s+const)?\s*\*\s*(const\s+)?\w', line) and
+      not Search(r'\boperator\W', line) and
+      not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(3))):
+    error(filename, linenum, 'runtime/string', 4,
+          'For a static/global string constant, use a C style string instead: '
+          '"%schar %s[]".' %
+          (match.group(1), match.group(2)))
+
+  if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
+    error(filename, linenum, 'runtime/init', 4,
+          'You seem to be initializing a member variable with itself.')
+
+
+def CheckPrintf(filename, clean_lines, linenum, error):
+  """Check for printf related issues.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # When snprintf is used, the second argument shouldn't be a literal.
+  match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
+  if match and match.group(2) != '0':
+    # If 2nd arg is zero, snprintf is used to calculate size.
+    error(filename, linenum, 'runtime/printf', 3,
+          'If you can, use sizeof(%s) instead of %s as the 2nd arg '
+          'to snprintf.' % (match.group(1), match.group(2)))
+
+  # Check if some verboten C functions are being used.
+  if Search(r'\bsprintf\s*\(', line):
+    error(filename, linenum, 'runtime/printf', 5,
+          'Never use sprintf. Use snprintf instead.')
+  match = Search(r'\b(strcpy|strcat)\s*\(', line)
+  if match:
+    error(filename, linenum, 'runtime/printf', 4,
+          'Almost always, snprintf is better than %s' % match.group(1))
+
+
+def IsDerivedFunction(clean_lines, linenum):
+  """Check if current line contains an inherited function.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+  Returns:
+    True if current line contains a function with "override"
+    virt-specifier.
+  """
+  # Scan back a few lines for start of current function
+  for i in xrange(linenum, max(-1, linenum - 10), -1):
+    match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i])
+    if match:
+      # Look for "override" after the matching closing parenthesis
+      line, _, closing_paren = CloseExpression(
+          clean_lines, i, len(match.group(1)))
+      return (closing_paren >= 0 and
+              Search(r'\boverride\b', line[closing_paren:]))
+  return False
+
+
+def IsOutOfLineMethodDefinition(clean_lines, linenum):
+  """Check if current line contains an out-of-line method definition.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+  Returns:
+    True if current line contains an out-of-line method definition.
+  """
+  # Scan back a few lines for start of current function
+  for i in xrange(linenum, max(-1, linenum - 10), -1):
+    if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]):
+      return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None
+  return False
+
+
+def IsInitializerList(clean_lines, linenum):
+  """Check if current line is inside constructor initializer list.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+  Returns:
+    True if current line appears to be inside constructor initializer
+    list, False otherwise.
+  """
+  for i in xrange(linenum, 1, -1):
+    line = clean_lines.elided[i]
+    if i == linenum:
+      remove_function_body = Match(r'^(.*)\{\s*$', line)
+      if remove_function_body:
+        line = remove_function_body.group(1)
+
+    if Search(r'\s:\s*\w+[({]', line):
+      # A lone colon tend to indicate the start of a constructor
+      # initializer list.  It could also be a ternary operator, which
+      # also tend to appear in constructor initializer lists as
+      # opposed to parameter lists.
+      return True
+    if Search(r'\}\s*,\s*$', line):
+      # A closing brace followed by a comma is probably the end of a
+      # brace-initialized member in constructor initializer list.
+      return True
+    if Search(r'[{};]\s*$', line):
+      # Found one of the following:
+      # - A closing brace or semicolon, probably the end of the previous
+      #   function.
+      # - An opening brace, probably the start of current class or namespace.
+      #
+      # Current line is probably not inside an initializer list since
+      # we saw one of those things without seeing the starting colon.
+      return False
+
+  # Got to the beginning of the file without seeing the start of
+  # constructor initializer list.
+  return False
+
+
+def CheckForNonConstReference(filename, clean_lines, linenum,
+                              nesting_state, error):
+  """Check for non-const references.
+
+  Separate from CheckLanguage since it scans backwards from current
+  line, instead of scanning forward.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: The function to call with any errors found.
+  """
+  # Do nothing if there is no '&' on current line.
+  line = clean_lines.elided[linenum]
+  if '&' not in line:
+    return
+
+  # If a function is inherited, current function doesn't have much of
+  # a choice, so any non-const references should not be blamed on
+  # derived function.
+  if IsDerivedFunction(clean_lines, linenum):
+    return
+
+  # Don't warn on out-of-line method definitions, as we would warn on the
+  # in-line declaration, if it isn't marked with 'override'.
+  if IsOutOfLineMethodDefinition(clean_lines, linenum):
+    return
+
+  # Long type names may be broken across multiple lines, usually in one
+  # of these forms:
+  #   LongType
+  #       ::LongTypeContinued &identifier
+  #   LongType::
+  #       LongTypeContinued &identifier
+  #   LongType<
+  #       ...>::LongTypeContinued &identifier
+  #
+  # If we detected a type split across two lines, join the previous
+  # line to current line so that we can match const references
+  # accordingly.
+  #
+  # Note that this only scans back one line, since scanning back
+  # arbitrary number of lines would be expensive.  If you have a type
+  # that spans more than 2 lines, please use a typedef.
+  if linenum > 1:
+    previous = None
+    if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line):
+      # previous_line\n + ::current_line
+      previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$',
+                        clean_lines.elided[linenum - 1])
+    elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line):
+      # previous_line::\n + current_line
+      previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$',
+                        clean_lines.elided[linenum - 1])
+    if previous:
+      line = previous.group(1) + line.lstrip()
+    else:
+      # Check for templated parameter that is split across multiple lines
+      endpos = line.rfind('>')
+      if endpos > -1:
+        (_, startline, startpos) = ReverseCloseExpression(
+            clean_lines, linenum, endpos)
+        if startpos > -1 and startline < linenum:
+          # Found the matching < on an earlier line, collect all
+          # pieces up to current line.
+          line = ''
+          for i in xrange(startline, linenum + 1):
+            line += clean_lines.elided[i].strip()
+
+  # Check for non-const references in function parameters.  A single '&' may
+  # found in the following places:
+  #   inside expression: binary & for bitwise AND
+  #   inside expression: unary & for taking the address of something
+  #   inside declarators: reference parameter
+  # We will exclude the first two cases by checking that we are not inside a
+  # function body, including one that was just introduced by a trailing '{'.
+  # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare].
+  if (nesting_state.previous_stack_top and
+      not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or
+           isinstance(nesting_state.previous_stack_top, _NamespaceInfo))):
+    # Not at toplevel, not within a class, and not within a namespace
+    return
+
+  # Avoid initializer lists.  We only need to scan back from the
+  # current line for something that starts with ':'.
+  #
+  # We don't need to check the current line, since the '&' would
+  # appear inside the second set of parentheses on the current line as
+  # opposed to the first set.
+  if linenum > 0:
+    for i in xrange(linenum - 1, max(0, linenum - 10), -1):
+      previous_line = clean_lines.elided[i]
+      if not Search(r'[),]\s*$', previous_line):
+        break
+      if Match(r'^\s*:\s+\S', previous_line):
+        return
+
+  # Avoid preprocessors
+  if Search(r'\\\s*$', line):
+    return
+
+  # Avoid constructor initializer lists
+  if IsInitializerList(clean_lines, linenum):
+    return
+
+  # We allow non-const references in a few standard places, like functions
+  # called "swap()" or iostream operators like "<<" or ">>".  Do not check
+  # those function parameters.
+  #
+  # We also accept & in static_assert, which looks like a function but
+  # it's actually a declaration expression.
+  whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|'
+                           r'operator\s*[<>][<>]|'
+                           r'static_assert|COMPILE_ASSERT'
+                           r')\s*\(')
+  if Search(whitelisted_functions, line):
+    return
+  elif not Search(r'\S+\([^)]*$', line):
+    # Don't see a whitelisted function on this line.  Actually we
+    # didn't see any function name on this line, so this is likely a
+    # multi-line parameter list.  Try a bit harder to catch this case.
+    for i in xrange(2):
+      if (linenum > i and
+          Search(whitelisted_functions, clean_lines.elided[linenum - i - 1])):
+        return
+
+  decls = ReplaceAll(r'{[^}]*}', ' ', line)  # exclude function body
+  for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls):
+    if not Match(_RE_PATTERN_CONST_REF_PARAM, parameter):
+      error(filename, linenum, 'runtime/references', 2,
+            'Is this a non-const reference? '
+            'If so, make const or use a pointer: ' +
+            ReplaceAll(' *<', '<', parameter))
+
+
+def CheckCasts(filename, clean_lines, linenum, error):
+  """Various cast related checks.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Check to see if they're using an conversion function cast.
+  # I just try to capture the most common basic types, though there are more.
+  # Parameterless conversion functions, such as bool(), are allowed as they are
+  # probably a member operator declaration or default constructor.
+  match = Search(
+      r'(\bnew\s+|\S<\s*(?:const\s+)?)?\b'
+      r'(int|float|double|bool|char|int32|uint32|int64|uint64)'
+      r'(\([^)].*)', line)
+  expecting_function = ExpectingFunctionArgs(clean_lines, linenum)
+  if match and not expecting_function:
+    matched_type = match.group(2)
+
+    # matched_new_or_template is used to silence two false positives:
+    # - New operators
+    # - Template arguments with function types
+    #
+    # For template arguments, we match on types immediately following
+    # an opening bracket without any spaces.  This is a fast way to
+    # silence the common case where the function type is the first
+    # template argument.  False negative with less-than comparison is
+    # avoided because those operators are usually followed by a space.
+    #
+    #   function<double(double)>   // bracket + no space = false positive
+    #   value < double(42)         // bracket + space = true positive
+    matched_new_or_template = match.group(1)
+
+    # Avoid arrays by looking for brackets that come after the closing
+    # parenthesis.
+    if Match(r'\([^()]+\)\s*\[', match.group(3)):
+      return
+
+    # Other things to ignore:
+    # - Function pointers
+    # - Casts to pointer types
+    # - Placement new
+    # - Alias declarations
+    matched_funcptr = match.group(3)
+    if (matched_new_or_template is None and
+        not (matched_funcptr and
+             (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(',
+                    matched_funcptr) or
+              matched_funcptr.startswith('(*)'))) and
+        not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and
+        not Search(r'new\(\S+\)\s*' + matched_type, line)):
+      error(filename, linenum, 'readability/casting', 4,
+            'Using deprecated casting style.  '
+            'Use static_cast<%s>(...) instead' %
+            matched_type)
+
+  if not expecting_function:
+    CheckCStyleCast(filename, clean_lines, linenum, 'static_cast',
+                    r'\((int|float|double|bool|char|u?int(16|32|64))\)', error)
+
+  # This doesn't catch all cases. Consider (const char * const)"hello".
+  #
+  # (char *) "foo" should always be a const_cast (reinterpret_cast won't
+  # compile).
+  if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast',
+                     r'\((char\s?\*+\s?)\)\s*"', error):
+    pass
+  else:
+    # Check pointer casts for other than string constants
+    CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast',
+                    r'\((\w+\s?\*+\s?)\)', error)
+
+  # In addition, we look for people taking the address of a cast.  This
+  # is dangerous -- casts can assign to temporaries, so the pointer doesn't
+  # point where you think.
+  #
+  # Some non-identifier character is required before the '&' for the
+  # expression to be recognized as a cast.  These are casts:
+  #   expression = &static_cast<int*>(temporary());
+  #   function(&(int*)(temporary()));
+  #
+  # This is not a cast:
+  #   reference_type&(int* function_param);
+  match = Search(
+      r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|'
+      r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line)
+  if match:
+    # Try a better error message when the & is bound to something
+    # dereferenced by the casted pointer, as opposed to the casted
+    # pointer itself.
+    parenthesis_error = False
+    match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line)
+    if match:
+      _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1)))
+      if x1 >= 0 and clean_lines.elided[y1][x1] == '(':
+        _, y2, x2 = CloseExpression(clean_lines, y1, x1)
+        if x2 >= 0:
+          extended_line = clean_lines.elided[y2][x2:]
+          if y2 < clean_lines.NumLines() - 1:
+            extended_line += clean_lines.elided[y2 + 1]
+          if Match(r'\s*(?:->|\[)', extended_line):
+            parenthesis_error = True
+
+    if parenthesis_error:
+      error(filename, linenum, 'readability/casting', 4,
+            ('Are you taking an address of something dereferenced '
+             'from a cast?  Wrapping the dereferenced expression in '
+             'parentheses will make the binding more obvious'))
+    else:
+      error(filename, linenum, 'runtime/casting', 4,
+            ('Are you taking an address of a cast?  '
+             'This is dangerous: could be a temp var.  '
+             'Take the address before doing the cast, rather than after'))
+
+
+def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error):
+  """Checks for a C-style cast by looking for the pattern.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    cast_type: The string for the C++ cast to recommend.  This is either
+      reinterpret_cast, static_cast, or const_cast, depending.
+    pattern: The regular expression used to find C-style casts.
+    error: The function to call with any errors found.
+
+  Returns:
+    True if an error was emitted.
+    False otherwise.
+  """
+  line = clean_lines.elided[linenum]
+  match = Search(pattern, line)
+  if not match:
+    return False
+
+  # Exclude lines with keywords that tend to look like casts
+  context = line[0:match.start(1) - 1]
+  if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context):
+    return False
+
+  # Try expanding current context to see if we one level of
+  # parentheses inside a macro.
+  if linenum > 0:
+    for i in xrange(linenum - 1, max(0, linenum - 5), -1):
+      context = clean_lines.elided[i] + context
+  if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context):
+    return False
+
+  # operator++(int) and operator--(int)
+  if context.endswith(' operator++') or context.endswith(' operator--'):
+    return False
+
+  # A single unnamed argument for a function tends to look like old
+  # style cast.  If we see those, don't issue warnings for deprecated
+  # casts, instead issue warnings for unnamed arguments where
+  # appropriate.
+  #
+  # These are things that we want warnings for, since the style guide
+  # explicitly require all parameters to be named:
+  #   Function(int);
+  #   Function(int) {
+  #   ConstMember(int) const;
+  #   ConstMember(int) const {
+  #   ExceptionMember(int) throw (...);
+  #   ExceptionMember(int) throw (...) {
+  #   PureVirtual(int) = 0;
+  #   [](int) -> bool {
+  #
+  # These are functions of some sort, where the compiler would be fine
+  # if they had named parameters, but people often omit those
+  # identifiers to reduce clutter:
+  #   (FunctionPointer)(int);
+  #   (FunctionPointer)(int) = value;
+  #   Function((function_pointer_arg)(int))
+  #   Function((function_pointer_arg)(int), int param)
+  #   <TemplateArgument(int)>;
+  #   <(FunctionPointerTemplateArgument)(int)>;
+  remainder = line[match.end(0):]
+  if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)',
+           remainder):
+    # Looks like an unnamed parameter.
+
+    # Don't warn on any kind of template arguments.
+    if Match(r'^\s*>', remainder):
+      return False
+
+    # Don't warn on assignments to function pointers, but keep warnings for
+    # unnamed parameters to pure virtual functions.  Note that this pattern
+    # will also pass on assignments of "0" to function pointers, but the
+    # preferred values for those would be "nullptr" or "NULL".
+    matched_zero = Match(r'^\s=\s*(\S+)\s*;', remainder)
+    if matched_zero and matched_zero.group(1) != '0':
+      return False
+
+    # Don't warn on function pointer declarations.  For this we need
+    # to check what came before the "(type)" string.
+    if Match(r'.*\)\s*$', line[0:match.start(0)]):
+      return False
+
+    # Don't warn if the parameter is named with block comments, e.g.:
+    #  Function(int /*unused_param*/);
+    raw_line = clean_lines.raw_lines[linenum]
+    if '/*' in raw_line:
+      return False
+
+    # Passed all filters, issue warning here.
+    error(filename, linenum, 'readability/function', 3,
+          'All parameters should be named in a function')
+    return True
+
+  # At this point, all that should be left is actual casts.
+  error(filename, linenum, 'readability/casting', 4,
+        'Using C-style cast.  Use %s<%s>(...) instead' %
+        (cast_type, match.group(1)))
+
+  return True
+
+
+def ExpectingFunctionArgs(clean_lines, linenum):
+  """Checks whether where function type arguments are expected.
+
+  Args:
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+
+  Returns:
+    True if the line at 'linenum' is inside something that expects arguments
+    of function types.
+  """
+  line = clean_lines.elided[linenum]
+  return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or
+          (linenum >= 2 and
+           (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$',
+                  clean_lines.elided[linenum - 1]) or
+            Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$',
+                  clean_lines.elided[linenum - 2]) or
+            Search(r'\bstd::m?function\s*\<\s*$',
+                   clean_lines.elided[linenum - 1]))))
+
+
+_HEADERS_CONTAINING_TEMPLATES = (
+    ('<deque>', ('deque',)),
+    ('<functional>', ('unary_function', 'binary_function',
+                      'plus', 'minus', 'multiplies', 'divides', 'modulus',
+                      'negate',
+                      'equal_to', 'not_equal_to', 'greater', 'less',
+                      'greater_equal', 'less_equal',
+                      'logical_and', 'logical_or', 'logical_not',
+                      'unary_negate', 'not1', 'binary_negate', 'not2',
+                      'bind1st', 'bind2nd',
+                      'pointer_to_unary_function',
+                      'pointer_to_binary_function',
+                      'ptr_fun',
+                      'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
+                      'mem_fun_ref_t',
+                      'const_mem_fun_t', 'const_mem_fun1_t',
+                      'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
+                      'mem_fun_ref',
+                     )),
+    ('<limits>', ('numeric_limits',)),
+    ('<list>', ('list',)),
+    ('<map>', ('map', 'multimap',)),
+    ('<memory>', ('allocator',)),
+    ('<queue>', ('queue', 'priority_queue',)),
+    ('<set>', ('set', 'multiset',)),
+    ('<stack>', ('stack',)),
+    ('<string>', ('char_traits', 'basic_string',)),
+    ('<tuple>', ('tuple',)),
+    ('<utility>', ('pair',)),
+    ('<vector>', ('vector',)),
+
+    # gcc extensions.
+    # Note: std::hash is their hash, ::hash is our hash
+    ('<hash_map>', ('hash_map', 'hash_multimap',)),
+    ('<hash_set>', ('hash_set', 'hash_multiset',)),
+    ('<slist>', ('slist',)),
+    )
+
+_RE_PATTERN_STRING = re.compile(r'\bstring\b')
+
+_re_pattern_algorithm_header = []
+for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
+                  'transform'):
+  # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
+  # type::max().
+  _re_pattern_algorithm_header.append(
+      (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
+       _template,
+       '<algorithm>'))
+
+_re_pattern_templates = []
+for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
+  for _template in _templates:
+    _re_pattern_templates.append(
+        (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
+         _template + '<>',
+         _header))
+
+
+def FilesBelongToSameModule(filename_cc, filename_h):
+  """Check if these two filenames belong to the same module.
+
+  The concept of a 'module' here is a as follows:
+  foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
+  same 'module' if they are in the same directory.
+  some/path/public/xyzzy and some/path/internal/xyzzy are also considered
+  to belong to the same module here.
+
+  If the filename_cc contains a longer path than the filename_h, for example,
+  '/absolute/path/to/base/sysinfo.cc', and this file would include
+  'base/sysinfo.h', this function also produces the prefix needed to open the
+  header. This is used by the caller of this function to more robustly open the
+  header file. We don't have access to the real include paths in this context,
+  so we need this guesswork here.
+
+  Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
+  according to this implementation. Because of this, this function gives
+  some false positives. This should be sufficiently rare in practice.
+
+  Args:
+    filename_cc: is the path for the .cc file
+    filename_h: is the path for the header path
+
+  Returns:
+    Tuple with a bool and a string:
+    bool: True if filename_cc and filename_h belong to the same module.
+    string: the additional prefix needed to open the header file.
+  """
+
+  if not filename_cc.endswith('.cc'):
+    return (False, '')
+  filename_cc = filename_cc[:-len('.cc')]
+  if filename_cc.endswith('_unittest'):
+    filename_cc = filename_cc[:-len('_unittest')]
+  elif filename_cc.endswith('_test'):
+    filename_cc = filename_cc[:-len('_test')]
+  filename_cc = filename_cc.replace('/public/', '/')
+  filename_cc = filename_cc.replace('/internal/', '/')
+
+  if not filename_h.endswith('.h'):
+    return (False, '')
+  filename_h = filename_h[:-len('.h')]
+  if filename_h.endswith('-inl'):
+    filename_h = filename_h[:-len('-inl')]
+  filename_h = filename_h.replace('/public/', '/')
+  filename_h = filename_h.replace('/internal/', '/')
+
+  files_belong_to_same_module = filename_cc.endswith(filename_h)
+  common_path = ''
+  if files_belong_to_same_module:
+    common_path = filename_cc[:-len(filename_h)]
+  return files_belong_to_same_module, common_path
+
+
+def UpdateIncludeState(filename, include_dict, io=codecs):
+  """Fill up the include_dict with new includes found from the file.
+
+  Args:
+    filename: the name of the header to read.
+    include_dict: a dictionary in which the headers are inserted.
+    io: The io factory to use to read the file. Provided for testability.
+
+  Returns:
+    True if a header was successfully added. False otherwise.
+  """
+  headerfile = None
+  try:
+    headerfile = io.open(filename, 'r', 'utf8', 'replace')
+  except IOError:
+    return False
+  linenum = 0
+  for line in headerfile:
+    linenum += 1
+    clean_line = CleanseComments(line)
+    match = _RE_PATTERN_INCLUDE.search(clean_line)
+    if match:
+      include = match.group(2)
+      include_dict.setdefault(include, linenum)
+  return True
+
+
+def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
+                              io=codecs):
+  """Reports for missing stl includes.
+
+  This function will output warnings to make sure you are including the headers
+  necessary for the stl containers and functions that you use. We only give one
+  reason to include a header. For example, if you use both equal_to<> and
+  less<> in a .h file, only one (the latter in the file) of these will be
+  reported as a reason to include the <functional>.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    include_state: An _IncludeState instance.
+    error: The function to call with any errors found.
+    io: The IO factory to use to read the header file. Provided for unittest
+        injection.
+  """
+  required = {}  # A map of header name to linenumber and the template entity.
+                 # Example of required: { '<functional>': (1219, 'less<>') }
+
+  for linenum in xrange(clean_lines.NumLines()):
+    line = clean_lines.elided[linenum]
+    if not line or line[0] == '#':
+      continue
+
+    # String is special -- it is a non-templatized type in STL.
+    matched = _RE_PATTERN_STRING.search(line)
+    if matched:
+      # Don't warn about strings in non-STL namespaces:
+      # (We check only the first match per line; good enough.)
+      prefix = line[:matched.start()]
+      if prefix.endswith('std::') or not prefix.endswith('::'):
+        required['<string>'] = (linenum, 'string')
+
+    for pattern, template, header in _re_pattern_algorithm_header:
+      if pattern.search(line):
+        required[header] = (linenum, template)
+
+    # The following function is just a speed up, no semantics are changed.
+    if not '<' in line:  # Reduces the cpu time usage by skipping lines.
+      continue
+
+    for pattern, template, header in _re_pattern_templates:
+      if pattern.search(line):
+        required[header] = (linenum, template)
+
+  # The policy is that if you #include something in foo.h you don't need to
+  # include it again in foo.cc. Here, we will look at possible includes.
+  # Let's flatten the include_state include_list and copy it into a dictionary.
+  include_dict = dict([item for sublist in include_state.include_list
+                       for item in sublist])
+
+  # Did we find the header for this file (if any) and successfully load it?
+  header_found = False
+
+  # Use the absolute path so that matching works properly.
+  abs_filename = FileInfo(filename).FullName()
+
+  # For Emacs's flymake.
+  # If cpplint is invoked from Emacs's flymake, a temporary file is generated
+  # by flymake and that file name might end with '_flymake.cc'. In that case,
+  # restore original file name here so that the corresponding header file can be
+  # found.
+  # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
+  # instead of 'foo_flymake.h'
+  abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
+
+  # include_dict is modified during iteration, so we iterate over a copy of
+  # the keys.
+  header_keys = include_dict.keys()
+  for header in header_keys:
+    (same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
+    fullpath = common_path + header
+    if same_module and UpdateIncludeState(fullpath, include_dict, io):
+      header_found = True
+
+  # If we can't find the header file for a .cc, assume it's because we don't
+  # know where to look. In that case we'll give up as we're not sure they
+  # didn't include it in the .h file.
+  # TODO(unknown): Do a better job of finding .h files so we are confident that
+  # not having the .h file means there isn't one.
+  if filename.endswith('.cc') and not header_found:
+    return
+
+  # All the lines have been processed, report the errors found.
+  for required_header_unstripped in required:
+    template = required[required_header_unstripped][1]
+    if required_header_unstripped.strip('<>"') not in include_dict:
+      error(filename, required[required_header_unstripped][0],
+            'build/include_what_you_use', 4,
+            'Add #include ' + required_header_unstripped + ' for ' + template)
+
+
+_RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<')
+
+
+def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error):
+  """Check that make_pair's template arguments are deduced.
+
+  G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are
+  specified explicitly, and such use isn't intended in any case.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+  match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line)
+  if match:
+    error(filename, linenum, 'build/explicit_make_pair',
+          4,  # 4 = high confidence
+          'For C++11-compatibility, omit template arguments from make_pair'
+          ' OR use pair directly OR if appropriate, construct a pair directly')
+
+
+def CheckDefaultLambdaCaptures(filename, clean_lines, linenum, error):
+  """Check that default lambda captures are not used.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # A lambda introducer specifies a default capture if it starts with "[="
+  # or if it starts with "[&" _not_ followed by an identifier.
+  match = Match(r'^(.*)\[\s*(?:=|&[^\w])', line)
+  if match:
+    # Found a potential error, check what comes after the lambda-introducer.
+    # If it's not open parenthesis (for lambda-declarator) or open brace
+    # (for compound-statement), it's not a lambda.
+    line, _, pos = CloseExpression(clean_lines, linenum, len(match.group(1)))
+    if pos >= 0 and Match(r'^\s*[{(]', line[pos:]):
+      error(filename, linenum, 'build/c++11',
+            4,  # 4 = high confidence
+            'Default lambda captures are an unapproved C++ feature.')
+
+
+def CheckRedundantVirtual(filename, clean_lines, linenum, error):
+  """Check if line contains a redundant "virtual" function-specifier.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  # Look for "virtual" on current line.
+  line = clean_lines.elided[linenum]
+  virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line)
+  if not virtual: return
+
+  # Ignore "virtual" keywords that are near access-specifiers.  These
+  # are only used in class base-specifier and do not apply to member
+  # functions.
+  if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or
+      Match(r'^\s+(public|protected|private)\b', virtual.group(3))):
+    return
+
+  # Ignore the "virtual" keyword from virtual base classes.  Usually
+  # there is a column on the same line in these cases (virtual base
+  # classes are rare in google3 because multiple inheritance is rare).
+  if Match(r'^.*[^:]:[^:].*$', line): return
+
+  # Look for the next opening parenthesis.  This is the start of the
+  # parameter list (possibly on the next line shortly after virtual).
+  # TODO(unknown): doesn't work if there are virtual functions with
+  # decltype() or other things that use parentheses, but csearch suggests
+  # that this is rare.
+  end_col = -1
+  end_line = -1
+  start_col = len(virtual.group(2))
+  for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())):
+    line = clean_lines.elided[start_line][start_col:]
+    parameter_list = Match(r'^([^(]*)\(', line)
+    if parameter_list:
+      # Match parentheses to find the end of the parameter list
+      (_, end_line, end_col) = CloseExpression(
+          clean_lines, start_line, start_col + len(parameter_list.group(1)))
+      break
+    start_col = 0
+
+  if end_col < 0:
+    return  # Couldn't find end of parameter list, give up
+
+  # Look for "override" or "final" after the parameter list
+  # (possibly on the next few lines).
+  for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())):
+    line = clean_lines.elided[i][end_col:]
+    match = Search(r'\b(override|final)\b', line)
+    if match:
+      error(filename, linenum, 'readability/inheritance', 4,
+            ('"virtual" is redundant since function is '
+             'already declared as "%s"' % match.group(1)))
+
+    # Set end_col to check whole lines after we are done with the
+    # first line.
+    end_col = 0
+    if Search(r'[^\w]\s*$', line):
+      break
+
+
+def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error):
+  """Check if line contains a redundant "override" or "final" virt-specifier.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  # Look for closing parenthesis nearby.  We need one to confirm where
+  # the declarator ends and where the virt-specifier starts to avoid
+  # false positives.
+  line = clean_lines.elided[linenum]
+  declarator_end = line.rfind(')')
+  if declarator_end >= 0:
+    fragment = line[declarator_end:]
+  else:
+    if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0:
+      fragment = line
+    else:
+      return
+
+  # Check that at most one of "override" or "final" is present, not both
+  if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment):
+    error(filename, linenum, 'readability/inheritance', 4,
+          ('"override" is redundant since function is '
+           'already declared as "final"'))
+
+
+
+
+# Returns true if we are at a new block, and it is directly
+# inside of a namespace.
+def IsBlockInNameSpace(nesting_state, is_forward_declaration):
+  """Checks that the new block is directly in a namespace.
+
+  Args:
+    nesting_state: The _NestingState object that contains info about our state.
+    is_forward_declaration: If the class is a forward declared class.
+  Returns:
+    Whether or not the new block is directly in a namespace.
+  """
+  if is_forward_declaration:
+    if len(nesting_state.stack) >= 1 and (
+        isinstance(nesting_state.stack[-1], _NamespaceInfo)):
+      return True
+    else:
+      return False
+
+  return (len(nesting_state.stack) > 1 and
+          nesting_state.stack[-1].check_namespace_indentation and
+          isinstance(nesting_state.stack[-2], _NamespaceInfo))
+
+
+def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item,
+                                    raw_lines_no_comments, linenum):
+  """This method determines if we should apply our namespace indentation check.
+
+  Args:
+    nesting_state: The current nesting state.
+    is_namespace_indent_item: If we just put a new class on the stack, True.
+      If the top of the stack is not a class, or we did not recently
+      add the class, False.
+    raw_lines_no_comments: The lines without the comments.
+    linenum: The current line number we are processing.
+
+  Returns:
+    True if we should apply our namespace indentation check. Currently, it
+    only works for classes and namespaces inside of a namespace.
+  """
+
+  is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments,
+                                                     linenum)
+
+  if not (is_namespace_indent_item or is_forward_declaration):
+    return False
+
+  # If we are in a macro, we do not want to check the namespace indentation.
+  if IsMacroDefinition(raw_lines_no_comments, linenum):
+    return False
+
+  return IsBlockInNameSpace(nesting_state, is_forward_declaration)
+
+
+# Call this method if the line is directly inside of a namespace.
+# If the line above is blank (excluding comments) or the start of
+# an inner namespace, it cannot be indented.
+def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum,
+                                    error):
+  line = raw_lines_no_comments[linenum]
+  if Match(r'^\s+', line):
+    error(filename, linenum, 'runtime/indentation_namespace', 4,
+          'Do not indent within a namespace')
+
+
+def ProcessLine(filename, file_extension, clean_lines, line,
+                include_state, function_state, nesting_state, error,
+                extra_check_functions=[]):
+  """Processes a single line in the file.
+
+  Args:
+    filename: Filename of the file that is being processed.
+    file_extension: The extension (dot not included) of the file.
+    clean_lines: An array of strings, each representing a line of the file,
+                 with comments stripped.
+    line: Number of line being processed.
+    include_state: An _IncludeState instance in which the headers are inserted.
+    function_state: A _FunctionState instance which counts function lines, etc.
+    nesting_state: A NestingState instance which maintains information about
+                   the current stack of nested blocks being parsed.
+    error: A callable to which errors are reported, which takes 4 arguments:
+           filename, line number, error level, and message
+    extra_check_functions: An array of additional check functions that will be
+                           run on each source line. Each function takes 4
+                           arguments: filename, clean_lines, line, error
+  """
+  raw_lines = clean_lines.raw_lines
+  ParseNolintSuppressions(filename, raw_lines[line], line, error)
+  nesting_state.Update(filename, clean_lines, line, error)
+  CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line,
+                               error)
+  if nesting_state.InAsmBlock(): return
+  CheckForFunctionLengths(filename, clean_lines, line, function_state, error)
+  CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error)
+  CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error)
+  CheckLanguage(filename, clean_lines, line, file_extension, include_state,
+                nesting_state, error)
+  CheckForNonConstReference(filename, clean_lines, line, nesting_state, error)
+  CheckForNonStandardConstructs(filename, clean_lines, line,
+                                nesting_state, error)
+  CheckVlogArguments(filename, clean_lines, line, error)
+  CheckPosixThreading(filename, clean_lines, line, error)
+  CheckInvalidIncrement(filename, clean_lines, line, error)
+  CheckMakePairUsesDeduction(filename, clean_lines, line, error)
+  CheckDefaultLambdaCaptures(filename, clean_lines, line, error)
+  CheckRedundantVirtual(filename, clean_lines, line, error)
+  CheckRedundantOverrideOrFinal(filename, clean_lines, line, error)
+  for check_fn in extra_check_functions:
+    check_fn(filename, clean_lines, line, error)
+
+def FlagCxx11Features(filename, clean_lines, linenum, error):
+  """Flag those c++11 features that we only allow in certain places.
+
+  Args:
+    filename: The name of the current file.
+    clean_lines: A CleansedLines instance containing the file.
+    linenum: The number of the line to check.
+    error: The function to call with any errors found.
+  """
+  line = clean_lines.elided[linenum]
+
+  # Flag unapproved C++11 headers.
+  include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line)
+  if include and include.group(1) in ('cfenv',
+                                      'condition_variable',
+                                      'fenv.h',
+                                      'future',
+                                      'mutex',
+                                      'thread',
+                                      'chrono',
+                                      'ratio',
+                                      'regex',
+                                      'system_error',
+                                     ):
+    error(filename, linenum, 'build/c++11', 5,
+          ('<%s> is an unapproved C++11 header.') % include.group(1))
+
+  # The only place where we need to worry about C++11 keywords and library
+  # features in preprocessor directives is in macro definitions.
+  if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return
+
+  # These are classes and free functions.  The classes are always
+  # mentioned as std::*, but we only catch the free functions if
+  # they're not found by ADL.  They're alphabetical by header.
+  for top_name in (
+      # type_traits
+      'alignment_of',
+      'aligned_union',
+      ):
+    if Search(r'\bstd::%s\b' % top_name, line):
+      error(filename, linenum, 'build/c++11', 5,
+            ('std::%s is an unapproved C++11 class or function.  Send c-style '
+             'an example of where it would make your code more readable, and '
+             'they may let you use it.') % top_name)
+
+
+def ProcessFileData(filename, file_extension, lines, error,
+                    extra_check_functions=[]):
+  """Performs lint checks and reports any errors to the given error function.
+
+  Args:
+    filename: Filename of the file that is being processed.
+    file_extension: The extension (dot not included) of the file.
+    lines: An array of strings, each representing a line of the file, with the
+           last element being empty if the file is terminated with a newline.
+    error: A callable to which errors are reported, which takes 4 arguments:
+           filename, line number, error level, and message
+    extra_check_functions: An array of additional check functions that will be
+                           run on each source line. Each function takes 4
+                           arguments: filename, clean_lines, line, error
+  """
+  lines = (['// marker so line numbers and indices both start at 1'] + lines +
+           ['// marker so line numbers end in a known way'])
+
+  include_state = _IncludeState()
+  function_state = _FunctionState()
+  nesting_state = NestingState()
+
+  ResetNolintSuppressions()
+
+  CheckForCopyright(filename, lines, error)
+
+  RemoveMultiLineComments(filename, lines, error)
+  clean_lines = CleansedLines(lines)
+
+  if file_extension == 'h':
+    CheckForHeaderGuard(filename, clean_lines, error)
+
+  for line in xrange(clean_lines.NumLines()):
+    ProcessLine(filename, file_extension, clean_lines, line,
+                include_state, function_state, nesting_state, error,
+                extra_check_functions)
+    FlagCxx11Features(filename, clean_lines, line, error)
+  nesting_state.CheckCompletedBlocks(filename, error)
+
+  CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error)
+  
+  # Check that the .cc file has included its header if it exists.
+  if file_extension == 'cc':
+    CheckHeaderFileIncluded(filename, include_state, error)
+
+  # We check here rather than inside ProcessLine so that we see raw
+  # lines rather than "cleaned" lines.
+  CheckForBadCharacters(filename, lines, error)
+
+  CheckForNewlineAtEOF(filename, lines, error)
+
+def ProcessConfigOverrides(filename):
+  """ Loads the configuration files and processes the config overrides.
+
+  Args:
+    filename: The name of the file being processed by the linter.
+
+  Returns:
+    False if the current |filename| should not be processed further.
+  """
+
+  abs_filename = os.path.abspath(filename)
+  cfg_filters = []
+  keep_looking = True
+  while keep_looking:
+    abs_path, base_name = os.path.split(abs_filename)
+    if not base_name:
+      break  # Reached the root directory.
+
+    cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
+    abs_filename = abs_path
+    if not os.path.isfile(cfg_file):
+      continue
+
+    try:
+      with open(cfg_file) as file_handle:
+        for line in file_handle:
+          line, _, _ = line.partition('#')  # Remove comments.
+          if not line.strip():
+            continue
+
+          name, _, val = line.partition('=')
+          name = name.strip()
+          val = val.strip()
+          if name == 'set noparent':
+            keep_looking = False
+          elif name == 'filter':
+            cfg_filters.append(val)
+          elif name == 'exclude_files':
+            # When matching exclude_files pattern, use the base_name of
+            # the current file name or the directory name we are processing.
+            # For example, if we are checking for lint errors in /foo/bar/baz.cc
+            # and we found the .cfg file at /foo/CPPLINT.cfg, then the config
+            # file's "exclude_files" filter is meant to be checked against "bar"
+            # and not "baz" nor "bar/baz.cc".
+            if base_name:
+              pattern = re.compile(val)
+              if pattern.match(base_name):
+                sys.stderr.write('Ignoring "%s": file excluded by "%s". '
+                                 'File path component "%s" matches '
+                                 'pattern "%s"\n' %
+                                 (filename, cfg_file, base_name, val))
+                return False
+          elif name == 'linelength':
+            global _line_length
+            try:
+                _line_length = int(val)
+            except ValueError:
+                sys.stderr.write('Line length must be numeric.')
+          else:
+            sys.stderr.write(
+                'Invalid configuration option (%s) in file %s\n' %
+                (name, cfg_file))
+
+    except IOError:
+      sys.stderr.write(
+          "Skipping config file '%s': Can't open for reading\n" % cfg_file)
+      keep_looking = False
+
+  # Apply all the accumulated filters in reverse order (top-level directory
+  # config options having the least priority).
+  for filter in reversed(cfg_filters):
+     _AddFilters(filter)
+
+  return True
+
+
+def ProcessFile(filename, vlevel, extra_check_functions=[]):
+  """Does google-lint on a single file.
+
+  Args:
+    filename: The name of the file to parse.
+
+    vlevel: The level of errors to report.  Every error of confidence
+    >= verbose_level will be reported.  0 is a good default.
+
+    extra_check_functions: An array of additional check functions that will be
+                           run on each source line. Each function takes 4
+                           arguments: filename, clean_lines, line, error
+  """
+
+  _SetVerboseLevel(vlevel)
+  _BackupFilters()
+
+  if not ProcessConfigOverrides(filename):
+    _RestoreFilters()
+    return
+
+  lf_lines = []
+  crlf_lines = []
+  try:
+    # Support the UNIX convention of using "-" for stdin.  Note that
+    # we are not opening the file with universal newline support
+    # (which codecs doesn't support anyway), so the resulting lines do
+    # contain trailing '\r' characters if we are reading a file that
+    # has CRLF endings.
+    # If after the split a trailing '\r' is present, it is removed
+    # below.
+    if filename == '-':
+      lines = codecs.StreamReaderWriter(sys.stdin,
+                                        codecs.getreader('utf8'),
+                                        codecs.getwriter('utf8'),
+                                        'replace').read().split('\n')
+    else:
+      lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
+
+    # Remove trailing '\r'.
+    # The -1 accounts for the extra trailing blank line we get from split()
+    for linenum in range(len(lines) - 1):
+      if lines[linenum].endswith('\r'):
+        lines[linenum] = lines[linenum].rstrip('\r')
+        crlf_lines.append(linenum + 1)
+      else:
+        lf_lines.append(linenum + 1)
+
+  except IOError:
+    sys.stderr.write(
+        "Skipping input '%s': Can't open for reading\n" % filename)
+    _RestoreFilters()
+    return
+
+  # Note, if no dot is found, this will give the entire filename as the ext.
+  file_extension = filename[filename.rfind('.') + 1:]
+
+  # When reading from stdin, the extension is unknown, so no cpplint tests
+  # should rely on the extension.
+  if filename != '-' and file_extension not in _valid_extensions:
+    sys.stderr.write('Ignoring %s; not a valid file name '
+                     '(%s)\n' % (filename, ', '.join(_valid_extensions)))
+  else:
+    ProcessFileData(filename, file_extension, lines, Error,
+                    extra_check_functions)
+
+    # If end-of-line sequences are a mix of LF and CR-LF, issue
+    # warnings on the lines with CR.
+    #
+    # Don't issue any warnings if all lines are uniformly LF or CR-LF,
+    # since critique can handle these just fine, and the style guide
+    # doesn't dictate a particular end of line sequence.
+    #
+    # We can't depend on os.linesep to determine what the desired
+    # end-of-line sequence should be, since that will return the
+    # server-side end-of-line sequence.
+    if lf_lines and crlf_lines:
+      # Warn on every line with CR.  An alternative approach might be to
+      # check whether the file is mostly CRLF or just LF, and warn on the
+      # minority, we bias toward LF here since most tools prefer LF.
+      for linenum in crlf_lines:
+        Error(filename, linenum, 'whitespace/newline', 1,
+              'Unexpected \\r (^M) found; better to use only \\n')
+
+  sys.stderr.write('Done processing %s\n' % filename)
+  _RestoreFilters()
+
+
+def PrintUsage(message):
+  """Prints a brief usage string and exits, optionally with an error message.
+
+  Args:
+    message: The optional error message.
+  """
+  sys.stderr.write(_USAGE)
+  if message:
+    sys.exit('\nFATAL ERROR: ' + message)
+  else:
+    sys.exit(1)
+
+
+def PrintCategories():
+  """Prints a list of all the error-categories used by error messages.
+
+  These are the categories used to filter messages via --filter.
+  """
+  sys.stderr.write(''.join('  %s\n' % cat for cat in _ERROR_CATEGORIES))
+  sys.exit(0)
+
+
+def ParseArguments(args):
+  """Parses the command line arguments.
+
+  This may set the output format and verbosity level as side-effects.
+
+  Args:
+    args: The command line arguments:
+
+  Returns:
+    The list of filenames to lint.
+  """
+  try:
+    (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=',
+                                                 'counting=',
+                                                 'filter=',
+                                                 'root=',
+                                                 'linelength=',
+                                                 'extensions='])
+  except getopt.GetoptError:
+    PrintUsage('Invalid arguments.')
+
+  verbosity = _VerboseLevel()
+  output_format = _OutputFormat()
+  filters = ''
+  counting_style = ''
+
+  for (opt, val) in opts:
+    if opt == '--help':
+      PrintUsage(None)
+    elif opt == '--output':
+      if val not in ('emacs', 'vs7', 'eclipse'):
+        PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.')
+      output_format = val
+    elif opt == '--verbose':
+      verbosity = int(val)
+    elif opt == '--filter':
+      filters = val
+      if not filters:
+        PrintCategories()
+    elif opt == '--counting':
+      if val not in ('total', 'toplevel', 'detailed'):
+        PrintUsage('Valid counting options are total, toplevel, and detailed')
+      counting_style = val
+    elif opt == '--root':
+      global _root
+      _root = val
+    elif opt == '--linelength':
+      global _line_length
+      try:
+          _line_length = int(val)
+      except ValueError:
+          PrintUsage('Line length must be digits.')
+    elif opt == '--extensions':
+      global _valid_extensions
+      try:
+          _valid_extensions = set(val.split(','))
+      except ValueError:
+          PrintUsage('Extensions must be comma seperated list.')
+
+  if not filenames:
+    PrintUsage('No files were specified.')
+
+  _SetOutputFormat(output_format)
+  _SetVerboseLevel(verbosity)
+  _SetFilters(filters)
+  _SetCountingStyle(counting_style)
+
+  return filenames
+
+
+def main():
+  filenames = ParseArguments(sys.argv[1:])
+
+  # Change stderr to write with replacement characters so we don't die
+  # if we try to print something containing non-ASCII characters.
+  sys.stderr = codecs.StreamReaderWriter(sys.stderr,
+                                         codecs.getreader('utf8'),
+                                         codecs.getwriter('utf8'),
+                                         'replace')
+
+  _cpplint_state.ResetErrorCounts()
+  for filename in filenames:
+    ProcessFile(filename, _cpplint_state.verbose_level)
+  _cpplint_state.PrintErrorCounts()
+
+  sys.exit(_cpplint_state.error_count > 0)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/cpplint/python/cpplint_test_header.h b/tools/cpplint/python/cpplint_test_header.h
new file mode 100644
index 0000000..4307e80
--- /dev/null
+++ b/tools/cpplint/python/cpplint_test_header.h
@@ -0,0 +1 @@
+// A test header for cpplint_unittest.py.
diff --git a/tools/cpplint/python/cpplint_unittest.py b/tools/cpplint/python/cpplint_unittest.py
new file mode 100755
index 0000000..aaa3b24
--- /dev/null
+++ b/tools/cpplint/python/cpplint_unittest.py
@@ -0,0 +1,5459 @@
+#!/usr/bin/python
+# -*- coding: utf-8; -*-
+#
+# Copyright (c) 2009 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#    * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#    * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for cpplint.py."""
+
+# TODO(unknown): Add a good test that tests UpdateIncludeState.
+
+import codecs
+import os
+import random
+import re
+import sys
+import unittest
+
+import cpplint
+
+
+# This class works as an error collector and replaces cpplint.Error
+# function for the unit tests.  We also verify each category we see
+# is in cpplint._ERROR_CATEGORIES, to help keep that list up to date.
+class ErrorCollector(object):
+  # These are a global list, covering all categories seen ever.
+  _ERROR_CATEGORIES = cpplint._ERROR_CATEGORIES
+  _SEEN_ERROR_CATEGORIES = {}
+
+  def __init__(self, assert_fn):
+    """assert_fn: a function to call when we notice a problem."""
+    self._assert_fn = assert_fn
+    self._errors = []
+    cpplint.ResetNolintSuppressions()
+
+  def __call__(self, unused_filename, linenum,
+               category, confidence, message):
+    self._assert_fn(category in self._ERROR_CATEGORIES,
+                    'Message "%s" has category "%s",'
+                    ' which is not in _ERROR_CATEGORIES' % (message, category))
+    self._SEEN_ERROR_CATEGORIES[category] = 1
+    if cpplint._ShouldPrintError(category, confidence, linenum):
+      self._errors.append('%s  [%s] [%d]' % (message, category, confidence))
+
+  def Results(self):
+    if len(self._errors) < 2:
+      return ''.join(self._errors)  # Most tests expect to have a string.
+    else:
+      return self._errors  # Let's give a list if there is more than one.
+
+  def ResultList(self):
+    return self._errors
+
+  def VerifyAllCategoriesAreSeen(self):
+    """Fails if there's a category in _ERROR_CATEGORIES~_SEEN_ERROR_CATEGORIES.
+
+    This should only be called after all tests are run, so
+    _SEEN_ERROR_CATEGORIES has had a chance to fully populate.  Since
+    this isn't called from within the normal unittest framework, we
+    can't use the normal unittest assert macros.  Instead we just exit
+    when we see an error.  Good thing this test is always run last!
+    """
+    for category in self._ERROR_CATEGORIES:
+      if category not in self._SEEN_ERROR_CATEGORIES:
+        sys.exit('FATAL ERROR: There are no tests for category "%s"' % category)
+
+  def RemoveIfPresent(self, substr):
+    for (index, error) in enumerate(self._errors):
+      if error.find(substr) != -1:
+        self._errors = self._errors[0:index] + self._errors[(index + 1):]
+        break
+
+
+# This class is a lame mock of codecs. We do not verify filename, mode, or
+# encoding, but for the current use case it is not needed.
+class MockIo(object):
+
+  def __init__(self, mock_file):
+    self.mock_file = mock_file
+
+  def open(self,  # pylint: disable-msg=C6409
+           unused_filename, unused_mode, unused_encoding, _):
+    return self.mock_file
+
+
+class CpplintTestBase(unittest.TestCase):
+  """Provides some useful helper functions for cpplint tests."""
+
+  def setUp(self):
+    # Allow subclasses to cheat os.path.abspath called in FileInfo class.
+    self.os_path_abspath_orig = os.path.abspath
+
+  def tearDown(self):
+    os.path.abspath = self.os_path_abspath_orig
+
+  # Perform lint on single line of input and return the error message.
+  def PerformSingleLineLint(self, code):
+    error_collector = ErrorCollector(self.assert_)
+    lines = code.split('\n')
+    cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
+    clean_lines = cpplint.CleansedLines(lines)
+    include_state = cpplint._IncludeState()
+    function_state = cpplint._FunctionState()
+    nesting_state = cpplint.NestingState()
+    cpplint.ProcessLine('foo.cc', 'cc', clean_lines, 0,
+                        include_state, function_state,
+                        nesting_state, error_collector)
+    # Single-line lint tests are allowed to fail the 'unlintable function'
+    # check.
+    error_collector.RemoveIfPresent(
+        'Lint failed to find start of function body.')
+    return error_collector.Results()
+
+  # Perform lint over multiple lines and return the error message.
+  def PerformMultiLineLint(self, code):
+    error_collector = ErrorCollector(self.assert_)
+    lines = code.split('\n')
+    cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
+    lines = cpplint.CleansedLines(lines)
+    nesting_state = cpplint.NestingState()
+    for i in xrange(lines.NumLines()):
+      nesting_state.Update('foo.h', lines, i, error_collector)
+      cpplint.CheckStyle('foo.h', lines, i, 'h', nesting_state,
+                         error_collector)
+      cpplint.CheckForNonStandardConstructs('foo.h', lines, i,
+                                            nesting_state, error_collector)
+    nesting_state.CheckCompletedBlocks('foo.h', error_collector)
+    return error_collector.Results()
+
+  # Similar to PerformMultiLineLint, but calls CheckLanguage instead of
+  # CheckForNonStandardConstructs
+  def PerformLanguageRulesCheck(self, file_name, code):
+    error_collector = ErrorCollector(self.assert_)
+    include_state = cpplint._IncludeState()
+    nesting_state = cpplint.NestingState()
+    lines = code.split('\n')
+    cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
+    lines = cpplint.CleansedLines(lines)
+    ext = file_name[file_name.rfind('.') + 1:]
+    for i in xrange(lines.NumLines()):
+      cpplint.CheckLanguage(file_name, lines, i, ext, include_state,
+                            nesting_state, error_collector)
+    return error_collector.Results()
+
+  def PerformFunctionLengthsCheck(self, code):
+    """Perform Lint function length check on block of code and return warnings.
+
+    Builds up an array of lines corresponding to the code and strips comments
+    using cpplint functions.
+
+    Establishes an error collector and invokes the function length checking
+    function following cpplint's pattern.
+
+    Args:
+      code: C++ source code expected to generate a warning message.
+
+    Returns:
+      The accumulated errors.
+    """
+    file_name = 'foo.cc'
+    error_collector = ErrorCollector(self.assert_)
+    function_state = cpplint._FunctionState()
+    lines = code.split('\n')
+    cpplint.RemoveMultiLineComments(file_name, lines, error_collector)
+    lines = cpplint.CleansedLines(lines)
+    for i in xrange(lines.NumLines()):
+      cpplint.CheckForFunctionLengths(file_name, lines, i,
+                                      function_state, error_collector)
+    return error_collector.Results()
+
+  def PerformIncludeWhatYouUse(self, code, filename='foo.h', io=codecs):
+    # First, build up the include state.
+    error_collector = ErrorCollector(self.assert_)
+    include_state = cpplint._IncludeState()
+    nesting_state = cpplint.NestingState()
+    lines = code.split('\n')
+    cpplint.RemoveMultiLineComments(filename, lines, error_collector)
+    lines = cpplint.CleansedLines(lines)
+    for i in xrange(lines.NumLines()):
+      cpplint.CheckLanguage(filename, lines, i, '.h', include_state,
+                            nesting_state, error_collector)
+    # We could clear the error_collector here, but this should
+    # also be fine, since our IncludeWhatYouUse unittests do not
+    # have language problems.
+
+    # Second, look for missing includes.
+    cpplint.CheckForIncludeWhatYouUse(filename, lines, include_state,
+                                      error_collector, io)
+    return error_collector.Results()
+
+  # Perform lint and compare the error message with "expected_message".
+  def TestLint(self, code, expected_message):
+    self.assertEquals(expected_message, self.PerformSingleLineLint(code))
+
+  def TestMultiLineLint(self, code, expected_message):
+    self.assertEquals(expected_message, self.PerformMultiLineLint(code))
+
+  def TestMultiLineLintRE(self, code, expected_message_re):
+    message = self.PerformMultiLineLint(code)
+    if not re.search(expected_message_re, message):
+      self.fail('Message was:\n' + message + 'Expected match to "' +
+                expected_message_re + '"')
+
+  def TestLanguageRulesCheck(self, file_name, code, expected_message):
+    self.assertEquals(expected_message,
+                      self.PerformLanguageRulesCheck(file_name, code))
+
+  def TestIncludeWhatYouUse(self, code, expected_message):
+    self.assertEquals(expected_message,
+                      self.PerformIncludeWhatYouUse(code))
+
+  def TestBlankLinesCheck(self, lines, start_errors, end_errors):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc', lines, error_collector)
+    self.assertEquals(
+        start_errors,
+        error_collector.Results().count(
+            'Redundant blank line at the start of a code block '
+            'should be deleted.  [whitespace/blank_line] [2]'))
+    self.assertEquals(
+        end_errors,
+        error_collector.Results().count(
+            'Redundant blank line at the end of a code block '
+            'should be deleted.  [whitespace/blank_line] [3]'))
+
+
+class CpplintTest(CpplintTestBase):
+
+  def GetNamespaceResults(self, lines):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.RemoveMultiLineComments('foo.h', lines, error_collector)
+    lines = cpplint.CleansedLines(lines)
+    nesting_state = cpplint.NestingState()
+    for i in xrange(lines.NumLines()):
+      nesting_state.Update('foo.h', lines, i, error_collector)
+      cpplint.CheckForNamespaceIndentation('foo.h', nesting_state,
+                                           lines, i, error_collector)
+
+    return error_collector.Results()
+
+  def testForwardDeclarationNameSpaceIndentation(self):
+    lines = ['namespace Test {',
+             '  class ForwardDeclaration;',
+             '}  // namespace Test']
+
+    results = self.GetNamespaceResults(lines)
+    self.assertEquals(results, 'Do not indent within a namespace '
+                      ' [runtime/indentation_namespace] [4]')
+
+  def testNameSpaceIndentationForClass(self):
+    lines = ['namespace Test {',
+             'void foo() { }',
+             '  class Test {',
+             '  };',
+             '}  // namespace Test']
+
+    results = self.GetNamespaceResults(lines)
+    self.assertEquals(results, 'Do not indent within a namespace '
+                      ' [runtime/indentation_namespace] [4]')
+
+  def testNameSpaceIndentationNoError(self):
+    lines = ['namespace Test {',
+             'void foo() { }',
+             '}  // namespace Test']
+
+    results = self.GetNamespaceResults(lines)
+    self.assertEquals(results, '')
+
+  def testFalsePositivesNoError(self):
+    lines = ['namespace Test {',
+             'struct OuterClass {',
+             '  struct NoFalsePositivesHere;',
+             '  struct NoFalsePositivesHere member_variable;',
+             '};',
+             '}  // namespace Test']
+
+    results = self.GetNamespaceResults(lines)
+    self.assertEquals(results, '')
+
+
+  # Test get line width.
+  def testGetLineWidth(self):
+    self.assertEquals(0, cpplint.GetLineWidth(''))
+    self.assertEquals(10, cpplint.GetLineWidth(u'x' * 10))
+    self.assertEquals(16, cpplint.GetLineWidth(u'都|道|府|県|支庁'))
+
+  def testGetTextInside(self):
+    self.assertEquals('', cpplint._GetTextInside('fun()', r'fun\('))
+    self.assertEquals('x, y', cpplint._GetTextInside('f(x, y)', r'f\('))
+    self.assertEquals('a(), b(c())', cpplint._GetTextInside(
+        'printf(a(), b(c()))', r'printf\('))
+    self.assertEquals('x, y{}', cpplint._GetTextInside('f[x, y{}]', r'f\['))
+    self.assertEquals(None, cpplint._GetTextInside('f[a, b(}]', r'f\['))
+    self.assertEquals(None, cpplint._GetTextInside('f[x, y]', r'f\('))
+    self.assertEquals('y, h(z, (a + b))', cpplint._GetTextInside(
+        'f(x, g(y, h(z, (a + b))))', r'g\('))
+    self.assertEquals('f(f(x))', cpplint._GetTextInside('f(f(f(x)))', r'f\('))
+    # Supports multiple lines.
+    self.assertEquals('\n  return loop(x);\n',
+                      cpplint._GetTextInside(
+                          'int loop(int x) {\n  return loop(x);\n}\n', r'\{'))
+    # '^' matches the beginning of each line.
+    self.assertEquals('x, y',
+                      cpplint._GetTextInside(
+                          '#include "inl.h"  // skip #define\n'
+                          '#define A2(x, y) a_inl_(x, y, __LINE__)\n'
+                          '#define A(x) a_inl_(x, "", __LINE__)\n',
+                          r'^\s*#define\s*\w+\('))
+
+  def testFindNextMultiLineCommentStart(self):
+    self.assertEquals(1, cpplint.FindNextMultiLineCommentStart([''], 0))
+
+    lines = ['a', 'b', '/* c']
+    self.assertEquals(2, cpplint.FindNextMultiLineCommentStart(lines, 0))
+
+    lines = ['char a[] = "/*";']  # not recognized as comment.
+    self.assertEquals(1, cpplint.FindNextMultiLineCommentStart(lines, 0))
+
+  def testFindNextMultiLineCommentEnd(self):
+    self.assertEquals(1, cpplint.FindNextMultiLineCommentEnd([''], 0))
+    lines = ['a', 'b', ' c */']
+    self.assertEquals(2, cpplint.FindNextMultiLineCommentEnd(lines, 0))
+
+  def testRemoveMultiLineCommentsFromRange(self):
+    lines = ['a', '  /* comment ', ' * still comment', ' comment */   ', 'b']
+    cpplint.RemoveMultiLineCommentsFromRange(lines, 1, 4)
+    self.assertEquals(['a', '/**/', '/**/', '/**/', 'b'], lines)
+
+  def testSpacesAtEndOfLine(self):
+    self.TestLint(
+        '// Hello there ',
+        'Line ends in whitespace.  Consider deleting these extra spaces.'
+        '  [whitespace/end_of_line] [4]')
+
+  # Test line length check.
+  def testLineLengthCheck(self):
+    self.TestLint(
+        '// Hello',
+        '')
+    self.TestLint(
+        '// ' + 'x' * 80,
+        'Lines should be <= 80 characters long'
+        '  [whitespace/line_length] [2]')
+    self.TestLint(
+        '// ' + 'x' * 100,
+        'Lines should very rarely be longer than 100 characters'
+        '  [whitespace/line_length] [4]')
+    self.TestLint(
+        '// http://g' + ('o' * 100) + 'gle.com/',
+        '')
+    self.TestLint(
+        '//   https://g' + ('o' * 100) + 'gle.com/',
+        '')
+    self.TestLint(
+        '//   https://g' + ('o' * 60) + 'gle.com/ and some comments',
+        'Lines should be <= 80 characters long'
+        '  [whitespace/line_length] [2]')
+    self.TestLint(
+        '// Read https://g' + ('o' * 60) + 'gle.com/',
+        '')
+    self.TestLint(
+        '// $Id: g' + ('o' * 80) + 'gle.cc#1 $',
+        '')
+    self.TestLint(
+        '// $Id: g' + ('o' * 80) + 'gle.cc#1',
+        'Lines should be <= 80 characters long'
+        '  [whitespace/line_length] [2]')
+    self.TestMultiLineLint(
+        'static const char kCStr[] = "g' + ('o' * 50) + 'gle";\n',
+        'Lines should be <= 80 characters long'
+        '  [whitespace/line_length] [2]')
+    self.TestMultiLineLint(
+        'static const char kRawStr[] = R"(g' + ('o' * 50) + 'gle)";\n',
+        '')  # no warning because raw string content is elided
+    self.TestMultiLineLint(
+        'static const char kMultiLineRawStr[] = R"(\n'
+        'g' + ('o' * 80) + 'gle\n'
+        ')";',
+        '')
+    self.TestMultiLineLint(
+        'static const char kL' + ('o' * 50) + 'ngIdentifier[] = R"()";\n',
+        'Lines should be <= 80 characters long'
+        '  [whitespace/line_length] [2]')
+
+  # Test error suppression annotations.
+  def testErrorSuppression(self):
+    # Two errors on same line:
+    self.TestLint(
+        'long a = (int64) 65;',
+        ['Using C-style cast.  Use static_cast<int64>(...) instead'
+         '  [readability/casting] [4]',
+         'Use int16/int64/etc, rather than the C type long'
+         '  [runtime/int] [4]',
+        ])
+    # One category of error suppressed:
+    self.TestLint(
+        'long a = (int64) 65;  // NOLINT(runtime/int)',
+        'Using C-style cast.  Use static_cast<int64>(...) instead'
+        '  [readability/casting] [4]')
+    # All categories suppressed: (two aliases)
+    self.TestLint('long a = (int64) 65;  // NOLINT', '')
+    self.TestLint('long a = (int64) 65;  // NOLINT(*)', '')
+    # Malformed NOLINT directive:
+    self.TestLint(
+        'long a = 65;  // NOLINT(foo)',
+        ['Unknown NOLINT error category: foo'
+         '  [readability/nolint] [5]',
+         'Use int16/int64/etc, rather than the C type long  [runtime/int] [4]',
+        ])
+    # Irrelevant NOLINT directive has no effect:
+    self.TestLint(
+        'long a = 65;  // NOLINT(readability/casting)',
+        'Use int16/int64/etc, rather than the C type long'
+        '  [runtime/int] [4]')
+    # NOLINTNEXTLINE silences warning for the next line instead of current line
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('test.cc', 'cc',
+                            ['// Copyright 2014 Your Company.',
+                             '// NOLINTNEXTLINE(whitespace/line_length)',
+                             '//  ./command' + (' -verbose' * 80),
+                             ''],
+                            error_collector)
+    self.assertEquals('', error_collector.Results())
+
+  # Test Variable Declarations.
+  def testVariableDeclarations(self):
+    self.TestLint(
+        'long a = 65;',
+        'Use int16/int64/etc, rather than the C type long'
+        '  [runtime/int] [4]')
+    self.TestLint(
+        'long double b = 65.0;',
+        '')
+    self.TestLint(
+        'long long aa = 6565;',
+        'Use int16/int64/etc, rather than the C type long'
+        '  [runtime/int] [4]')
+
+  # Test C-style cast cases.
+  def testCStyleCast(self):
+    self.TestLint(
+        'int a = (int)1.0;',
+        'Using C-style cast.  Use static_cast<int>(...) instead'
+        '  [readability/casting] [4]')
+    self.TestLint(
+        'int a = (int)-1.0;',
+        'Using C-style cast.  Use static_cast<int>(...) instead'
+        '  [readability/casting] [4]')
+    self.TestLint(
+        'int *a = (int *)NULL;',
+        'Using C-style cast.  Use reinterpret_cast<int *>(...) instead'
+        '  [readability/casting] [4]')
+
+    self.TestLint(
+        'uint16 a = (uint16)1.0;',
+        'Using C-style cast.  Use static_cast<uint16>(...) instead'
+        '  [readability/casting] [4]')
+    self.TestLint(
+        'int32 a = (int32)1.0;',
+        'Using C-style cast.  Use static_cast<int32>(...) instead'
+        '  [readability/casting] [4]')
+    self.TestLint(
+        'uint64 a = (uint64)1.0;',
+        'Using C-style cast.  Use static_cast<uint64>(...) instead'
+        '  [readability/casting] [4]')
+
+    # These shouldn't be recognized casts.
+    self.TestLint('u a = (u)NULL;', '')
+    self.TestLint('uint a = (uint)NULL;', '')
+    self.TestLint('typedef MockCallback<int(int)> CallbackType;', '')
+    self.TestLint('scoped_ptr< MockCallback<int(int)> > callback_value;', '')
+    self.TestLint('std::function<int(bool)>', '')
+    self.TestLint('x = sizeof(int)', '')
+    self.TestLint('x = alignof(int)', '')
+    self.TestLint('alignas(int) char x[42]', '')
+    self.TestLint('alignas(alignof(x)) char y[42]', '')
+    self.TestLint('void F(int (func)(int));', '')
+    self.TestLint('void F(int (func)(int*));', '')
+    self.TestLint('void F(int (Class::member)(int));', '')
+    self.TestLint('void F(int (Class::member)(int*));', '')
+    self.TestLint('void F(int (Class::member)(int), int param);', '')
+    self.TestLint('void F(int (Class::member)(int*), int param);', '')
+
+    # These should not be recognized (lambda functions without arg names).
+    self.TestLint('[](int/*unused*/) -> bool {', '')
+    self.TestLint('[](int /*unused*/) -> bool {', '')
+    self.TestLint('auto f = [](MyStruct* /*unused*/)->int {', '')
+    self.TestLint(
+        '[](int) -> bool {',
+        'All parameters should be named in a function'
+        '  [readability/function] [3]')
+    self.TestLint(
+        'auto f = [](MyStruct*)->int {',
+        'All parameters should be named in a function'
+        '  [readability/function] [3]')
+
+  # Test taking address of casts (runtime/casting)
+  def testRuntimeCasting(self):
+    error_msg = ('Are you taking an address of a cast?  '
+                 'This is dangerous: could be a temp var.  '
+                 'Take the address before doing the cast, rather than after'
+                 '  [runtime/casting] [4]')
+    self.TestLint('int* x = &static_cast<int*>(foo);', error_msg)
+    self.TestLint('int* x = &reinterpret_cast<int *>(foo);', error_msg)
+    self.TestLint('int* x = &(int*)foo;',
+                  ['Using C-style cast.  Use reinterpret_cast<int*>(...) '
+                   'instead  [readability/casting] [4]',
+                   error_msg])
+    self.TestLint('BudgetBuckets&(BudgetWinHistory::*BucketFn)(void) const;',
+                  '')
+    self.TestLint('&(*func_ptr)(arg)', '')
+    self.TestLint('Compute(arg, &(*func_ptr)(i, j));', '')
+
+    # Alternative error message
+    alt_error_msg = ('Are you taking an address of something dereferenced '
+                     'from a cast?  Wrapping the dereferenced expression in '
+                     'parentheses will make the binding more obvious'
+                     '  [readability/casting] [4]')
+    self.TestLint('int* x = &down_cast<Obj*>(obj)->member_;', alt_error_msg)
+    self.TestLint('int* x = &down_cast<Obj*>(obj)[index];', alt_error_msg)
+    self.TestLint('int* x = &(down_cast<Obj*>(obj)->member_);', '')
+    self.TestLint('int* x = &(down_cast<Obj*>(obj)[index]);', '')
+    self.TestLint('int* x = &down_cast<Obj*>(obj)\n->member_;', alt_error_msg)
+    self.TestLint('int* x = &(down_cast<Obj*>(obj)\n->member_);', '')
+
+    # It's OK to cast an address.
+    self.TestLint('int* x = reinterpret_cast<int *>(&foo);', '')
+
+    # Function pointers returning references should not be confused
+    # with taking address of old-style casts.
+    self.TestLint('auto x = implicit_cast<string &(*)(int)>(&foo);', '')
+
+  def testRuntimeSelfinit(self):
+    self.TestLint(
+        'Foo::Foo(Bar r, Bel l) : r_(r_), l_(l_) { }',
+        'You seem to be initializing a member variable with itself.'
+        '  [runtime/init] [4]')
+    self.TestLint(
+        'Foo::Foo(Bar r, Bel l) : r_(r), l_(l) { }',
+        '')
+    self.TestLint(
+        'Foo::Foo(Bar r) : r_(r), l_(r_), ll_(l_) { }',
+        '')
+
+  # Test for unnamed arguments in a method.
+  def testCheckForUnnamedParams(self):
+    message = ('All parameters should be named in a function'
+               '  [readability/function] [3]')
+    self.TestLint('virtual void Func(int*) const;', message)
+    self.TestLint('virtual void Func(int*);', message)
+    self.TestLint('void Method(char*) {', message)
+    self.TestLint('void Method(char*);', message)
+    self.TestLint('static void operator delete[](void*) throw();', message)
+    self.TestLint('int Method(int);', message)
+
+    self.TestLint('virtual void Func(int* p);', '')
+    self.TestLint('void operator delete(void* x) throw();', '')
+    self.TestLint('void Method(char* x) {', '')
+    self.TestLint('void Method(char* /*x*/) {', '')
+    self.TestLint('void Method(char* x);', '')
+    self.TestLint('typedef void (*Method)(int32 x);', '')
+    self.TestLint('static void operator delete[](void* x) throw();', '')
+    self.TestLint('static void operator delete[](void* /*x*/) throw();', '')
+
+    self.TestLint('X operator++(int);', '')
+    self.TestLint('X operator++(int) {', '')
+    self.TestLint('X operator--(int);', '')
+    self.TestLint('X operator--(int /*unused*/) {', '')
+    self.TestLint('MACRO(int);', '')
+    self.TestLint('MACRO(func(int));', '')
+    self.TestLint('MACRO(arg, func(int));', '')
+
+    self.TestLint('void (*func)(void*);', '')
+    self.TestLint('void Func((*func)(void*)) {}', '')
+    self.TestLint('template <void Func(void*)> void func();', '')
+    self.TestLint('virtual void f(int /*unused*/) {', '')
+    self.TestLint('void f(int /*unused*/) override {', '')
+    self.TestLint('void f(int /*unused*/) final {', '')
+
+  # Test deprecated casts such as int(d)
+  def testDeprecatedCast(self):
+    self.TestLint(
+        'int a = int(2.2);',
+        'Using deprecated casting style.  '
+        'Use static_cast<int>(...) instead'
+        '  [readability/casting] [4]')
+
+    self.TestLint(
+        '(char *) "foo"',
+        'Using C-style cast.  '
+        'Use const_cast<char *>(...) instead'
+        '  [readability/casting] [4]')
+
+    self.TestLint(
+        '(int*)foo',
+        'Using C-style cast.  '
+        'Use reinterpret_cast<int*>(...) instead'
+        '  [readability/casting] [4]')
+
+    # Checks for false positives...
+    self.TestLint('int a = int();', '')  # constructor
+    self.TestLint('X::X() : a(int()) {}', '')  # default constructor
+    self.TestLint('operator bool();', '')  # Conversion operator
+    self.TestLint('new int64(123);', '')  # "new" operator on basic type
+    self.TestLint('new   int64(123);', '')  # "new" operator on basic type
+    self.TestLint('using a = bool(int arg);', '')  # C++11 alias-declaration
+    self.TestLint('x = bit_cast<double(*)[3]>(y);', '')  # array of array
+    self.TestLint('void F(const char(&src)[N]);', '')  # array of references
+
+    # Placement new
+    self.TestLint(
+        'new(field_ptr) int(field->default_value_enum()->number());',
+        '')
+
+    # C++11 function wrappers
+    self.TestLint('std::function<int(bool)>', '')
+    self.TestLint('std::function<const int(bool)>', '')
+    self.TestLint('std::function< int(bool) >', '')
+    self.TestLint('mfunction<int(bool)>', '')
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'test.cc', 'cc',
+        ['// Copyright 2014 Your Company. All Rights Reserved.',
+         'typedef std::function<',
+         '    bool(int)> F;',
+         ''],
+        error_collector)
+    self.assertEquals('', error_collector.Results())
+
+    # Return types for function pointers
+    self.TestLint('typedef bool(FunctionPointer)();', '')
+    self.TestLint('typedef bool(FunctionPointer)(int param);', '')
+    self.TestLint('typedef bool(MyClass::*MemberFunctionPointer)();', '')
+    self.TestLint('typedef bool(MyClass::* MemberFunctionPointer)();', '')
+    self.TestLint('typedef bool(MyClass::*MemberFunctionPointer)() const;', '')
+    self.TestLint('void Function(bool(FunctionPointerArg)());', '')
+    self.TestLint('void Function(bool(FunctionPointerArg)()) {}', '')
+    self.TestLint('typedef set<int64, bool(*)(int64, int64)> SortedIdSet', '')
+    self.TestLint(
+        'bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *t)) {}',
+        '')
+
+  # The second parameter to a gMock method definition is a function signature
+  # that often looks like a bad cast but should not picked up by lint.
+  def testMockMethod(self):
+    self.TestLint(
+        'MOCK_METHOD0(method, int());',
+        '')
+    self.TestLint(
+        'MOCK_CONST_METHOD1(method, float(string));',
+        '')
+    self.TestLint(
+        'MOCK_CONST_METHOD2_T(method, double(float, float));',
+        '')
+    self.TestLint(
+        'MOCK_CONST_METHOD1(method, SomeType(int));',
+        '')
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('mock.cc', 'cc',
+                            ['MOCK_METHOD1(method1,',
+                             '             bool(int));',
+                             'MOCK_METHOD1(',
+                             '    method2,',
+                             '    bool(int));',
+                             'MOCK_CONST_METHOD2(',
+                             '    method3, bool(int,',
+                             '                  int));',
+                             'MOCK_METHOD1(method4, int(bool));',
+                             'const int kConstant = int(42);'],  # true positive
+                            error_collector)
+    self.assertEquals(
+        0,
+        error_collector.Results().count(
+            ('Using deprecated casting style.  '
+             'Use static_cast<bool>(...) instead  '
+             '[readability/casting] [4]')))
+    self.assertEquals(
+        1,
+        error_collector.Results().count(
+            ('Using deprecated casting style.  '
+             'Use static_cast<int>(...) instead  '
+             '[readability/casting] [4]')))
+
+  # Like gMock method definitions, MockCallback instantiations look very similar
+  # to bad casts.
+  def testMockCallback(self):
+    self.TestLint(
+        'MockCallback<bool(int)>',
+        '')
+    self.TestLint(
+        'MockCallback<int(float, char)>',
+        '')
+
+  # Test false errors that happened with some include file names
+  def testIncludeFilenameFalseError(self):
+    self.TestLint(
+        '#include "foo/long-foo.h"',
+        '')
+    self.TestLint(
+        '#include "foo/sprintf.h"',
+        '')
+
+  # Test typedef cases.  There was a bug that cpplint misidentified
+  # typedef for pointer to function as C-style cast and produced
+  # false-positive error messages.
+  def testTypedefForPointerToFunction(self):
+    self.TestLint(
+        'typedef void (*Func)(int x);',
+        '')
+    self.TestLint(
+        'typedef void (*Func)(int *x);',
+        '')
+    self.TestLint(
+        'typedef void Func(int x);',
+        '')
+    self.TestLint(
+        'typedef void Func(int *x);',
+        '')
+
+  def testIncludeWhatYouUseNoImplementationFiles(self):
+    code = 'std::vector<int> foo;'
+    self.assertEquals('Add #include <vector> for vector<>'
+                      '  [build/include_what_you_use] [4]',
+                      self.PerformIncludeWhatYouUse(code, 'foo.h'))
+    self.assertEquals('',
+                      self.PerformIncludeWhatYouUse(code, 'foo.cc'))
+
+  def testIncludeWhatYouUse(self):
+    self.TestIncludeWhatYouUse(
+        """#include <vector>
+           std::vector<int> foo;
+        """,
+        '')
+    self.TestIncludeWhatYouUse(
+        """#include <map>
+           std::pair<int,int> foo;
+        """,
+        'Add #include <utility> for pair<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include <multimap>
+           std::pair<int,int> foo;
+        """,
+        'Add #include <utility> for pair<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include <hash_map>
+           std::pair<int,int> foo;
+        """,
+        'Add #include <utility> for pair<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include <utility>
+           std::pair<int,int> foo;
+        """,
+        '')
+    self.TestIncludeWhatYouUse(
+        """#include <vector>
+           DECLARE_string(foobar);
+        """,
+        '')
+    self.TestIncludeWhatYouUse(
+        """#include <vector>
+           DEFINE_string(foobar, "", "");
+        """,
+        '')
+    self.TestIncludeWhatYouUse(
+        """#include <vector>
+           std::pair<int,int> foo;
+        """,
+        'Add #include <utility> for pair<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+           std::vector<int> foo;
+        """,
+        'Add #include <vector> for vector<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include <vector>
+           std::set<int> foo;
+        """,
+        'Add #include <set> for set<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+          hash_map<int, int> foobar;
+        """,
+        'Add #include <hash_map> for hash_map<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+           bool foobar = std::less<int>(0,1);
+        """,
+        'Add #include <functional> for less<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+           bool foobar = min<int>(0,1);
+        """,
+        'Add #include <algorithm> for min  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        'void a(const string &foobar);',
+        'Add #include <string> for string  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        'void a(const std::string &foobar);',
+        'Add #include <string> for string  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        'void a(const my::string &foobar);',
+        '')  # Avoid false positives on strings in other namespaces.
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+           bool foobar = swap(0,1);
+        """,
+        'Add #include <algorithm> for swap  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+           bool foobar = transform(a.begin(), a.end(), b.start(), Foo);
+        """,
+        'Add #include <algorithm> for transform  '
+        '[build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include "base/foobar.h"
+           bool foobar = min_element(a.begin(), a.end());
+        """,
+        'Add #include <algorithm> for min_element  '
+        '[build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """foo->swap(0,1);
+           foo.swap(0,1);
+        """,
+        '')
+    self.TestIncludeWhatYouUse(
+        """#include <string>
+           void a(const std::multimap<int,string> &foobar);
+        """,
+        'Add #include <map> for multimap<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include <queue>
+           void a(const std::priority_queue<int> &foobar);
+        """,
+        '')
+    self.TestIncludeWhatYouUse(
+        """#include <assert.h>
+           #include <string>
+           #include <vector>
+           #include "base/basictypes.h"
+           #include "base/port.h"
+           vector<string> hajoa;""", '')
+    self.TestIncludeWhatYouUse(
+        """#include <string>
+           int i = numeric_limits<int>::max()
+        """,
+        'Add #include <limits> for numeric_limits<>'
+        '  [build/include_what_you_use] [4]')
+    self.TestIncludeWhatYouUse(
+        """#include <limits>
+           int i = numeric_limits<int>::max()
+        """,
+        '')
+
+    # Test the UpdateIncludeState code path.
+    mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"']
+    message = self.PerformIncludeWhatYouUse(
+        '#include "blah/a.h"',
+        filename='blah/a.cc',
+        io=MockIo(mock_header_contents))
+    self.assertEquals(message, '')
+
+    mock_header_contents = ['#include <set>']
+    message = self.PerformIncludeWhatYouUse(
+        """#include "blah/a.h"
+           std::set<int> foo;""",
+        filename='blah/a.cc',
+        io=MockIo(mock_header_contents))
+    self.assertEquals(message, '')
+
+    # Make sure we can find the correct header file if the cc file seems to be
+    # a temporary file generated by Emacs's flymake.
+    mock_header_contents = ['']
+    message = self.PerformIncludeWhatYouUse(
+        """#include "blah/a.h"
+           std::set<int> foo;""",
+        filename='blah/a_flymake.cc',
+        io=MockIo(mock_header_contents))
+    self.assertEquals(message, 'Add #include <set> for set<>  '
+                      '[build/include_what_you_use] [4]')
+
+    # If there's just a cc and the header can't be found then it's ok.
+    message = self.PerformIncludeWhatYouUse(
+        """#include "blah/a.h"
+           std::set<int> foo;""",
+        filename='blah/a.cc')
+    self.assertEquals(message, '')
+
+    # Make sure we find the headers with relative paths.
+    mock_header_contents = ['']
+    message = self.PerformIncludeWhatYouUse(
+        """#include "%s/a.h"
+           std::set<int> foo;""" % os.path.basename(os.getcwd()),
+        filename='a.cc',
+        io=MockIo(mock_header_contents))
+    self.assertEquals(message, 'Add #include <set> for set<>  '
+                      '[build/include_what_you_use] [4]')
+
+  def testFilesBelongToSameModule(self):
+    f = cpplint.FilesBelongToSameModule
+    self.assertEquals((True, ''), f('a.cc', 'a.h'))
+    self.assertEquals((True, ''), f('base/google.cc', 'base/google.h'))
+    self.assertEquals((True, ''), f('base/google_test.cc', 'base/google.h'))
+    self.assertEquals((True, ''),
+                      f('base/google_unittest.cc', 'base/google.h'))
+    self.assertEquals((True, ''),
+                      f('base/internal/google_unittest.cc',
+                        'base/public/google.h'))
+    self.assertEquals((True, 'xxx/yyy/'),
+                      f('xxx/yyy/base/internal/google_unittest.cc',
+                        'base/public/google.h'))
+    self.assertEquals((True, 'xxx/yyy/'),
+                      f('xxx/yyy/base/google_unittest.cc',
+                        'base/public/google.h'))
+    self.assertEquals((True, ''),
+                      f('base/google_unittest.cc', 'base/google-inl.h'))
+    self.assertEquals((True, '/home/build/google3/'),
+                      f('/home/build/google3/base/google.cc', 'base/google.h'))
+
+    self.assertEquals((False, ''),
+                      f('/home/build/google3/base/google.cc', 'basu/google.h'))
+    self.assertEquals((False, ''), f('a.cc', 'b.h'))
+
+  def testCleanseLine(self):
+    self.assertEquals('int foo = 0;',
+                      cpplint.CleanseComments('int foo = 0;  // danger!'))
+    self.assertEquals('int o = 0;',
+                      cpplint.CleanseComments('int /* foo */ o = 0;'))
+    self.assertEquals('foo(int a, int b);',
+                      cpplint.CleanseComments('foo(int a /* abc */, int b);'))
+    self.assertEqual('f(a, b);',
+                     cpplint.CleanseComments('f(a, /* name */ b);'))
+    self.assertEqual('f(a, b);',
+                     cpplint.CleanseComments('f(a /* name */, b);'))
+    self.assertEqual('f(a, b);',
+                     cpplint.CleanseComments('f(a, /* name */b);'))
+    self.assertEqual('f(a, b, c);',
+                     cpplint.CleanseComments('f(a, /**/b, /**/c);'))
+    self.assertEqual('f(a, b, c);',
+                     cpplint.CleanseComments('f(a, /**/b/**/, c);'))
+
+  def testRawStrings(self):
+    self.TestMultiLineLint(
+        """
+        void Func() {
+          static const char kString[] = R"(
+            #endif  <- invalid preprocessor should be ignored
+            */      <- invalid comment should be ignored too
+          )";
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        void Func() {
+          string s = R"TrueDelimiter(
+              )"
+              )FalseDelimiter"
+              )TrueDelimiter";
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        void Func() {
+          char char kString[] = R"(  ";" )";
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        static const char kRawString[] = R"(
+          \tstatic const int kLineWithTab = 1;
+          static const int kLineWithTrailingWhiteSpace = 1;\x20
+
+           void WeirdNumberOfSpacesAtLineStart() {
+            string x;
+            x += StrCat("Use StrAppend instead");
+          }
+
+          void BlankLineAtEndOfBlock() {
+            // TODO incorrectly formatted
+            //Badly formatted comment
+
+          }
+
+        )";""",
+        '')
+    self.TestMultiLineLint(
+        """
+        void Func() {
+          string s = StrCat(R"TrueDelimiter(
+              )"
+              )FalseDelimiter"
+              )TrueDelimiter", R"TrueDelimiter2(
+              )"
+              )FalseDelimiter2"
+              )TrueDelimiter2");
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        static SomeStruct kData = {
+            {0, R"(line1
+                   line2
+                   )"}
+            };""",
+        '')
+
+  def testMultiLineComments(self):
+    # missing explicit is bad
+    self.TestMultiLineLint(
+        r"""int a = 0;
+            /* multi-liner
+            class Foo {
+            Foo(int f);  // should cause a lint warning in code
+            }
+            */ """,
+        '')
+    self.TestMultiLineLint(
+        r"""/* int a = 0; multi-liner
+              static const int b = 0;""",
+        'Could not find end of multi-line comment'
+        '  [readability/multiline_comment] [5]')
+    self.TestMultiLineLint(r"""  /* multi-line comment""",
+                           'Could not find end of multi-line comment'
+                           '  [readability/multiline_comment] [5]')
+    self.TestMultiLineLint(r"""  // /* comment, but not multi-line""", '')
+    self.TestMultiLineLint(r"""/**********
+                                 */""", '')
+    self.TestMultiLineLint(r"""/**
+                                 * Doxygen comment
+                                 */""",
+                           '')
+    self.TestMultiLineLint(r"""/*!
+                                 * Doxygen comment
+                                 */""",
+                           '')
+
+  def testMultilineStrings(self):
+    multiline_string_error_message = (
+        'Multi-line string ("...") found.  This lint script doesn\'t '
+        'do well with such strings, and may give bogus warnings.  '
+        'Use C++11 raw strings or concatenation instead.'
+        '  [readability/multiline_string] [5]')
+
+    file_path = 'mydir/foo.cc'
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'cc',
+                            ['const char* str = "This is a\\',
+                             ' multiline string.";'],
+                            error_collector)
+    self.assertEquals(
+        2,  # One per line.
+        error_collector.ResultList().count(multiline_string_error_message))
+
+  # Test non-explicit single-argument constructors
+  def testExplicitSingleArgumentConstructors(self):
+    old_verbose_level = cpplint._cpplint_state.verbose_level
+    cpplint._cpplint_state.verbose_level = 0
+
+    try:
+      # missing explicit is bad
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # missing explicit is bad, even with whitespace
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo (int f);
+          };""",
+          ['Extra space before ( in function call  [whitespace/parens] [4]',
+           'Single-parameter constructors should be marked explicit.'
+           '  [runtime/explicit] [5]'])
+      # missing explicit, with distracting comment, is still bad
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f);  // simpler than Foo(blargh, blarg)
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # missing explicit, with qualified classname
+      self.TestMultiLineLint(
+          """
+          class Qualifier::AnotherOne::Foo {
+            Foo(int f);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # missing explicit for inline constructors is bad as well
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            inline Foo(int f);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # structs are caught as well.
+      self.TestMultiLineLint(
+          """
+          struct Foo {
+            Foo(int f);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # Templatized classes are caught as well.
+      self.TestMultiLineLint(
+          """
+          template<typename T> class Foo {
+            Foo(int f);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # inline case for templatized classes.
+      self.TestMultiLineLint(
+          """
+          template<typename T> class Foo {
+            inline Foo(int f);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # constructors with a default argument should still be marked explicit
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f = 0);
+          };""",
+          'Constructors callable with one argument should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # multi-argument constructors with all but one default argument should be
+      # marked explicit
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f, int g = 0);
+          };""",
+          'Constructors callable with one argument should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # multi-argument constructors with all default arguments should be marked
+      # explicit
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f = 0, int g = 0);
+          };""",
+          'Constructors callable with one argument should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # explicit no-argument constructors are bad
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            explicit Foo();
+          };""",
+          'Zero-parameter constructors should not be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # void constructors are considered no-argument
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            explicit Foo(void);
+          };""",
+          'Zero-parameter constructors should not be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # Warn explicit multi-argument constructors at lowest severity
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            explicit Foo(int f, int g);
+          };""",
+          'Constructors that require multiple arguments '
+          'should not be marked explicit.  [runtime/explicit] [0]')
+      # but explicit multi-argument constructors with only one non-default
+      # argument are OK
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            explicit Foo(int f, int g = 0);
+          };""",
+          '')
+      # single-argument constructors that take a function that takes multiple
+      # arguments should be explicit
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(void (*f)(int f, int g));
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # single-argument constructors that take a single template argument with
+      # multiple parameters should be explicit
+      self.TestMultiLineLint(
+          """
+          template <typename T, typename S>
+          class Foo {
+            Foo(Bar<T, S> b);
+          };""",
+          'Single-parameter constructors should be marked explicit.'
+          '  [runtime/explicit] [5]')
+      # but copy constructors that take multiple template parameters are OK
+      self.TestMultiLineLint(
+          """
+          template <typename T, S>
+          class Foo {
+            Foo(Foo<T, S>& f);
+          };""",
+          '')
+      # proper style is okay
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            explicit Foo(int f);
+          };""",
+          '')
+      # two argument constructor is okay
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f, int b);
+          };""",
+          '')
+      # two argument constructor, across two lines, is okay
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f,
+                int b);
+          };""",
+          '')
+      # non-constructor (but similar name), is okay
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            aFoo(int f);
+          };""",
+          '')
+      # constructor with void argument is okay
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(void);
+          };""",
+          '')
+      # single argument method is okay
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Bar(int b);
+          };""",
+          '')
+      # comments should be ignored
+      self.TestMultiLineLint(
+          """
+          class Foo {
+          // Foo(int f);
+          };""",
+          '')
+      # single argument function following class definition is okay
+      # (okay, it's not actually valid, but we don't want a false positive)
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(int f, int b);
+          };
+          Foo(int f);""",
+          '')
+      # single argument function is okay
+      self.TestMultiLineLint(
+          """static Foo(int f);""",
+          '')
+      # single argument copy constructor is okay.
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(const Foo&);
+          };""",
+          '')
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(Foo const&);
+          };""",
+          '')
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(Foo&);
+          };""",
+          '')
+      # templatized copy constructor is okay.
+      self.TestMultiLineLint(
+          """
+          template<typename T> class Foo {
+            Foo(const Foo<T>&);
+          };""",
+          '')
+      # Special case for std::initializer_list
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(std::initializer_list<T> &arg) {}
+          };""",
+          '')
+      # Anything goes inside an assembly block
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData('foo.cc', 'cc',
+                              ['void Func() {',
+                               '  __asm__ (',
+                               '    "hlt"',
+                               '  );',
+                               '  asm {',
+                               '    movdqa [edx + 32], xmm2',
+                               '  }',
+                               '}'],
+                              error_collector)
+      self.assertEquals(
+          0,
+          error_collector.ResultList().count(
+              'Extra space before ( in function call  [whitespace/parens] [4]'))
+      self.assertEquals(
+          0,
+          error_collector.ResultList().count(
+              'Closing ) should be moved to the previous line  '
+              '[whitespace/parens] [2]'))
+      self.assertEquals(
+          0,
+          error_collector.ResultList().count(
+              'Extra space before [  [whitespace/braces] [5]'))
+    finally:
+      cpplint._cpplint_state.verbose_level = old_verbose_level
+
+  def testSlashStarCommentOnSingleLine(self):
+    self.TestMultiLineLint(
+        """/* static */ Foo(int f);""",
+        '')
+    self.TestMultiLineLint(
+        """/*/ static */  Foo(int f);""",
+        '')
+    self.TestMultiLineLint(
+        """/*/ static Foo(int f);""",
+        'Could not find end of multi-line comment'
+        '  [readability/multiline_comment] [5]')
+    self.TestMultiLineLint(
+        """  /*/ static Foo(int f);""",
+        'Could not find end of multi-line comment'
+        '  [readability/multiline_comment] [5]')
+    self.TestMultiLineLint(
+        """  /**/ static Foo(int f);""",
+        '')
+
+  # Test suspicious usage of "if" like this:
+  # if (a == b) {
+  #   DoSomething();
+  # } if (a == c) {   // Should be "else if".
+  #   DoSomething();  // This gets called twice if a == b && a == c.
+  # }
+  def testSuspiciousUsageOfIf(self):
+    self.TestLint(
+        '  if (a == b) {',
+        '')
+    self.TestLint(
+        '  } if (a == b) {',
+        'Did you mean "else if"? If not, start a new line for "if".'
+        '  [readability/braces] [4]')
+
+  # Test suspicious usage of memset. Specifically, a 0
+  # as the final argument is almost certainly an error.
+  def testSuspiciousUsageOfMemset(self):
+    # Normal use is okay.
+    self.TestLint(
+        '  memset(buf, 0, sizeof(buf))',
+        '')
+
+    # A 0 as the final argument is almost certainly an error.
+    self.TestLint(
+        '  memset(buf, sizeof(buf), 0)',
+        'Did you mean "memset(buf, 0, sizeof(buf))"?'
+        '  [runtime/memset] [4]')
+    self.TestLint(
+        '  memset(buf, xsize * ysize, 0)',
+        'Did you mean "memset(buf, 0, xsize * ysize)"?'
+        '  [runtime/memset] [4]')
+
+    # There is legitimate test code that uses this form.
+    # This is okay since the second argument is a literal.
+    self.TestLint(
+        "  memset(buf, 'y', 0)",
+        '')
+    self.TestLint(
+        '  memset(buf, 4, 0)',
+        '')
+    self.TestLint(
+        '  memset(buf, -1, 0)',
+        '')
+    self.TestLint(
+        '  memset(buf, 0xF1, 0)',
+        '')
+    self.TestLint(
+        '  memset(buf, 0xcd, 0)',
+        '')
+
+  def testRedundantVirtual(self):
+    self.TestLint('virtual void F()', '')
+    self.TestLint('virtual void F();', '')
+    self.TestLint('virtual void F() {}', '')
+
+    message_template = ('"%s" is redundant since function is already '
+                        'declared as "%s"  [readability/inheritance] [4]')
+    for virt_specifier in ['override', 'final']:
+      error_message = message_template % ('virtual', virt_specifier)
+      self.TestLint('virtual int F() %s' % virt_specifier, error_message)
+      self.TestLint('virtual int F() %s;' % virt_specifier, error_message)
+      self.TestLint('virtual int F() %s {' % virt_specifier, error_message)
+
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(
+          'foo.cc', 'cc',
+          ['// Copyright 2014 Your Company.',
+           'virtual void F(int a,',
+           '               int b) ' + virt_specifier + ';',
+           'virtual void F(int a,',
+           '               int b) LOCKS_EXCLUDED(lock) ' + virt_specifier + ';',
+           'virtual void F(int a,',
+           '               int b)',
+           '    LOCKS_EXCLUDED(lock) ' + virt_specifier + ';',
+           ''],
+          error_collector)
+      self.assertEquals(
+          [error_message, error_message, error_message],
+          error_collector.Results())
+
+    error_message = message_template % ('override', 'final')
+    self.TestLint('int F() override final', error_message)
+    self.TestLint('int F() override final;', error_message)
+    self.TestLint('int F() override final {}', error_message)
+    self.TestLint('int F() final override', error_message)
+    self.TestLint('int F() final override;', error_message)
+    self.TestLint('int F() final override {}', error_message)
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company.',
+         'struct A : virtual B {',
+         '  ~A() override;'
+         '};',
+         'class C',
+         '    : public D,',
+         '      public virtual E {',
+         '  void Func() override;',
+         '}',
+         ''],
+        error_collector)
+    self.assertEquals('', error_collector.Results())
+
+    self.TestLint('void Finalize(AnnotationProto *final) override;', '')
+
+  def testCheckDeprecated(self):
+    self.TestLanguageRulesCheck('foo_test.cc', '#include <iostream>', '')
+    self.TestLanguageRulesCheck('foo_unittest.cc', '#include <iostream>', '')
+
+  def testCheckPosixThreading(self):
+    self.TestLint('var = sctime_r()', '')
+    self.TestLint('var = strtok_r()', '')
+    self.TestLint('var = strtok_r(foo, ba, r)', '')
+    self.TestLint('var = brand()', '')
+    self.TestLint('_rand()', '')
+    self.TestLint('.rand()', '')
+    self.TestLint('->rand()', '')
+    self.TestLint('ACMRandom rand(seed)', '')
+    self.TestLint('ISAACRandom rand()', '')
+    self.TestLint('var = rand()',
+                  'Consider using rand_r(...) instead of rand(...)'
+                  ' for improved thread safety.'
+                  '  [runtime/threadsafe_fn] [2]')
+    self.TestLint('var = strtok(str, delim)',
+                  'Consider using strtok_r(...) '
+                  'instead of strtok(...)'
+                  ' for improved thread safety.'
+                  '  [runtime/threadsafe_fn] [2]')
+
+  def testVlogMisuse(self):
+    self.TestLint('VLOG(1)', '')
+    self.TestLint('VLOG(99)', '')
+    self.TestLint('LOG(ERROR)', '')
+    self.TestLint('LOG(INFO)', '')
+    self.TestLint('LOG(WARNING)', '')
+    self.TestLint('LOG(FATAL)', '')
+    self.TestLint('LOG(DFATAL)', '')
+    self.TestLint('VLOG(SOMETHINGWEIRD)', '')
+    self.TestLint('MYOWNVLOG(ERROR)', '')
+    errmsg = ('VLOG() should be used with numeric verbosity level.  '
+              'Use LOG() if you want symbolic severity levels.'
+              '  [runtime/vlog] [5]')
+    self.TestLint('VLOG(ERROR)', errmsg)
+    self.TestLint('VLOG(INFO)', errmsg)
+    self.TestLint('VLOG(WARNING)', errmsg)
+    self.TestLint('VLOG(FATAL)', errmsg)
+    self.TestLint('VLOG(DFATAL)', errmsg)
+    self.TestLint('  VLOG(ERROR)', errmsg)
+    self.TestLint('  VLOG(INFO)', errmsg)
+    self.TestLint('  VLOG(WARNING)', errmsg)
+    self.TestLint('  VLOG(FATAL)', errmsg)
+    self.TestLint('  VLOG(DFATAL)', errmsg)
+
+
+  # Test potential format string bugs like printf(foo).
+  def testFormatStrings(self):
+    self.TestLint('printf("foo")', '')
+    self.TestLint('printf("foo: %s", foo)', '')
+    self.TestLint('DocidForPrintf(docid)', '')  # Should not trigger.
+    self.TestLint('printf(format, value)', '')  # Should not trigger.
+    self.TestLint('printf(__VA_ARGS__)', '')  # Should not trigger.
+    self.TestLint('printf(format.c_str(), value)', '')  # Should not trigger.
+    self.TestLint('printf(format(index).c_str(), value)', '')
+    self.TestLint(
+        'printf(foo)',
+        'Potential format string bug. Do printf("%s", foo) instead.'
+        '  [runtime/printf] [4]')
+    self.TestLint(
+        'printf(foo.c_str())',
+        'Potential format string bug. '
+        'Do printf("%s", foo.c_str()) instead.'
+        '  [runtime/printf] [4]')
+    self.TestLint(
+        'printf(foo->c_str())',
+        'Potential format string bug. '
+        'Do printf("%s", foo->c_str()) instead.'
+        '  [runtime/printf] [4]')
+    self.TestLint(
+        'StringPrintf(foo)',
+        'Potential format string bug. Do StringPrintf("%s", foo) instead.'
+        ''
+        '  [runtime/printf] [4]')
+
+  # Test disallowed use of operator& and other operators.
+  def testIllegalOperatorOverloading(self):
+    errmsg = ('Unary operator& is dangerous.  Do not use it.'
+              '  [runtime/operator] [4]')
+    self.TestLint('void operator=(const Myclass&)', '')
+    self.TestLint('void operator&(int a, int b)', '')   # binary operator& ok
+    self.TestLint('void operator&() { }', errmsg)
+    self.TestLint('void operator & (  ) { }',
+                  ['Extra space after (  [whitespace/parens] [2]', errmsg])
+
+  # const string reference members are dangerous..
+  def testConstStringReferenceMembers(self):
+    errmsg = ('const string& members are dangerous. It is much better to use '
+              'alternatives, such as pointers or simple constants.'
+              '  [runtime/member_string_references] [2]')
+
+    members_declarations = ['const string& church',
+                            'const string &turing',
+                            'const string & godel']
+    # TODO(unknown): Enable also these tests if and when we ever
+    # decide to check for arbitrary member references.
+    #                         "const Turing & a",
+    #                         "const Church& a",
+    #                         "const vector<int>& a",
+    #                         "const     Kurt::Godel    &    godel",
+    #                         "const Kazimierz::Kuratowski& kk" ]
+
+    # The Good.
+
+    self.TestLint('void f(const string&)', '')
+    self.TestLint('const string& f(const string& a, const string& b)', '')
+    self.TestLint('typedef const string& A;', '')
+
+    for decl in members_declarations:
+      self.TestLint(decl + ' = b;', '')
+      self.TestLint(decl + '      =', '')
+
+    # The Bad.
+
+    for decl in members_declarations:
+      self.TestLint(decl + ';', errmsg)
+
+  # Variable-length arrays are not permitted.
+  def testVariableLengthArrayDetection(self):
+    errmsg = ('Do not use variable-length arrays.  Use an appropriately named '
+              "('k' followed by CamelCase) compile-time constant for the size."
+              '  [runtime/arrays] [1]')
+
+    self.TestLint('int a[any_old_variable];', errmsg)
+    self.TestLint('int doublesize[some_var * 2];', errmsg)
+    self.TestLint('int a[afunction()];', errmsg)
+    self.TestLint('int a[function(kMaxFooBars)];', errmsg)
+    self.TestLint('bool a_list[items_->size()];', errmsg)
+    self.TestLint('namespace::Type buffer[len+1];', errmsg)
+
+    self.TestLint('int a[64];', '')
+    self.TestLint('int a[0xFF];', '')
+    self.TestLint('int first[256], second[256];', '')
+    self.TestLint('int array_name[kCompileTimeConstant];', '')
+    self.TestLint('char buf[somenamespace::kBufSize];', '')
+    self.TestLint('int array_name[ALL_CAPS];', '')
+    self.TestLint('AClass array1[foo::bar::ALL_CAPS];', '')
+    self.TestLint('int a[kMaxStrLen + 1];', '')
+    self.TestLint('int a[sizeof(foo)];', '')
+    self.TestLint('int a[sizeof(*foo)];', '')
+    self.TestLint('int a[sizeof foo];', '')
+    self.TestLint('int a[sizeof(struct Foo)];', '')
+    self.TestLint('int a[128 - sizeof(const bar)];', '')
+    self.TestLint('int a[(sizeof(foo) * 4)];', '')
+    self.TestLint('int a[(arraysize(fixed_size_array)/2) << 1];', '')
+    self.TestLint('delete a[some_var];', '')
+    self.TestLint('return a[some_var];', '')
+
+  # DISALLOW_COPY_AND_ASSIGN and DISALLOW_IMPLICIT_CONSTRUCTORS should be at
+  # end of class if present.
+  def testDisallowMacrosAtEnd(self):
+    for macro_name in (
+        'DISALLOW_COPY_AND_ASSIGN',
+        'DISALLOW_IMPLICIT_CONSTRUCTORS'):
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(
+          'foo.cc', 'cc',
+          ['// Copyright 2014 Your Company.',
+           'class SomeClass {',
+           ' private:',
+           '  %s(SomeClass);' % macro_name,
+           '  int member_;',
+           '};',
+           ''],
+          error_collector)
+      self.assertEquals(
+          ('%s should be the last thing in the class' % macro_name) +
+          '  [readability/constructors] [3]',
+          error_collector.Results())
+
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(
+          'foo.cc', 'cc',
+          ['// Copyright 2014 Your Company.',
+           'class OuterClass {',
+           ' private:',
+           '  struct InnerClass {',
+           '   private:',
+           '    %s(InnerClass);' % macro_name,
+           '    int member;',
+           '  };',
+           '};',
+           ''],
+          error_collector)
+      self.assertEquals(
+          ('%s should be the last thing in the class' % macro_name) +
+          '  [readability/constructors] [3]',
+          error_collector.Results())
+
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(
+          'foo.cc', 'cc',
+          ['// Copyright 2014 Your Company.',
+           'class OuterClass1 {',
+           ' private:',
+           '  struct InnerClass1 {',
+           '   private:',
+           '    %s(InnerClass1);' % macro_name,
+           '  };',
+           '  %s(OuterClass1);' % macro_name,
+           '};',
+           'struct OuterClass2 {',
+           ' private:',
+           '  class InnerClass2 {',
+           '   private:',
+           '    %s(InnerClass2);' % macro_name,
+           '    // comment',
+           '  };',
+           '',
+           '  %s(OuterClass2);' % macro_name,
+           '',
+           '  // comment',
+           '};',
+           'void Func() {',
+           '  struct LocalClass {',
+           '   private:',
+           '    %s(LocalClass);' % macro_name,
+           '  } variable;',
+           '}',
+           ''],
+          error_collector)
+      self.assertEquals('', error_collector.Results())
+
+  # DISALLOW* macros should be in the private: section.
+  def testMisplacedDisallowMacros(self):
+    for macro_name in (
+        'DISALLOW_COPY_AND_ASSIGN',
+        'DISALLOW_IMPLICIT_CONSTRUCTORS'):
+      self.TestMultiLineLint(
+          """
+          class A {'
+           public:
+            %s(A);
+          };""" % macro_name,
+          ('%s must be in the private: section' % macro_name) +
+          '  [readability/constructors] [3]')
+
+      self.TestMultiLineLint(
+          """
+          struct B {'
+            %s(B);
+          };""" % macro_name,
+          ('%s must be in the private: section' % macro_name) +
+          '  [readability/constructors] [3]')
+
+      self.TestMultiLineLint(
+          """
+          class Outer1 {'
+           private:
+            struct Inner1 {
+              %s(Inner1);
+            };
+            %s(Outer1);
+          };""" % (macro_name, macro_name),
+          ('%s must be in the private: section' % macro_name) +
+          '  [readability/constructors] [3]')
+
+      self.TestMultiLineLint(
+          """
+          class Outer2 {'
+           private:
+            class Inner2 {
+              %s(Inner2);
+            };
+            %s(Outer2);
+          };""" % (macro_name, macro_name),
+          '')
+    # Extra checks to make sure that nested classes are handled
+    # correctly.  Use different macros for inner and outer classes so
+    # that we can tell the error messages apart.
+    self.TestMultiLineLint(
+        """
+        class Outer3 {
+          struct Inner3 {
+            DISALLOW_COPY_AND_ASSIGN(Inner3);
+          };
+          DISALLOW_IMPLICIT_CONSTRUCTORS(Outer3);
+        };""",
+        ('DISALLOW_COPY_AND_ASSIGN must be in the private: section'
+         '  [readability/constructors] [3]'))
+    self.TestMultiLineLint(
+        """
+        struct Outer4 {
+          class Inner4 {
+            DISALLOW_COPY_AND_ASSIGN(Inner4);
+          };
+          DISALLOW_IMPLICIT_CONSTRUCTORS(Outer4);
+        };""",
+        ('DISALLOW_IMPLICIT_CONSTRUCTORS must be in the private: section'
+         '  [readability/constructors] [3]'))
+
+  # Brace usage
+  def testBraces(self):
+    # Braces shouldn't be followed by a ; unless they're defining a struct
+    # or initializing an array
+    self.TestLint('int a[3] = { 1, 2, 3 };', '')
+    self.TestLint(
+        """const int foo[] =
+               {1, 2, 3 };""",
+        '')
+    # For single line, unmatched '}' with a ';' is ignored (not enough context)
+    self.TestMultiLineLint(
+        """int a[3] = { 1,
+                        2,
+                        3 };""",
+        '')
+    self.TestMultiLineLint(
+        """int a[2][3] = { { 1, 2 },
+                         { 3, 4 } };""",
+        '')
+    self.TestMultiLineLint(
+        """int a[2][3] =
+               { { 1, 2 },
+                 { 3, 4 } };""",
+        '')
+
+  # CHECK/EXPECT_TRUE/EXPECT_FALSE replacements
+  def testCheckCheck(self):
+    self.TestLint('CHECK(x == 42);',
+                  'Consider using CHECK_EQ instead of CHECK(a == b)'
+                  '  [readability/check] [2]')
+    self.TestLint('CHECK(x != 42);',
+                  'Consider using CHECK_NE instead of CHECK(a != b)'
+                  '  [readability/check] [2]')
+    self.TestLint('CHECK(x >= 42);',
+                  'Consider using CHECK_GE instead of CHECK(a >= b)'
+                  '  [readability/check] [2]')
+    self.TestLint('CHECK(x > 42);',
+                  'Consider using CHECK_GT instead of CHECK(a > b)'
+                  '  [readability/check] [2]')
+    self.TestLint('CHECK(x <= 42);',
+                  'Consider using CHECK_LE instead of CHECK(a <= b)'
+                  '  [readability/check] [2]')
+    self.TestLint('CHECK(x < 42);',
+                  'Consider using CHECK_LT instead of CHECK(a < b)'
+                  '  [readability/check] [2]')
+
+    self.TestLint('DCHECK(x == 42);',
+                  'Consider using DCHECK_EQ instead of DCHECK(a == b)'
+                  '  [readability/check] [2]')
+    self.TestLint('DCHECK(x != 42);',
+                  'Consider using DCHECK_NE instead of DCHECK(a != b)'
+                  '  [readability/check] [2]')
+    self.TestLint('DCHECK(x >= 42);',
+                  'Consider using DCHECK_GE instead of DCHECK(a >= b)'
+                  '  [readability/check] [2]')
+    self.TestLint('DCHECK(x > 42);',
+                  'Consider using DCHECK_GT instead of DCHECK(a > b)'
+                  '  [readability/check] [2]')
+    self.TestLint('DCHECK(x <= 42);',
+                  'Consider using DCHECK_LE instead of DCHECK(a <= b)'
+                  '  [readability/check] [2]')
+    self.TestLint('DCHECK(x < 42);',
+                  'Consider using DCHECK_LT instead of DCHECK(a < b)'
+                  '  [readability/check] [2]')
+
+    self.TestLint(
+        'EXPECT_TRUE("42" == x);',
+        'Consider using EXPECT_EQ instead of EXPECT_TRUE(a == b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_TRUE("42" != x);',
+        'Consider using EXPECT_NE instead of EXPECT_TRUE(a != b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_TRUE(+42 >= x);',
+        'Consider using EXPECT_GE instead of EXPECT_TRUE(a >= b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_TRUE_M(-42 > x);',
+        'Consider using EXPECT_GT_M instead of EXPECT_TRUE_M(a > b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_TRUE_M(42U <= x);',
+        'Consider using EXPECT_LE_M instead of EXPECT_TRUE_M(a <= b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_TRUE_M(42L < x);',
+        'Consider using EXPECT_LT_M instead of EXPECT_TRUE_M(a < b)'
+        '  [readability/check] [2]')
+
+    self.TestLint(
+        'EXPECT_FALSE(x == 42);',
+        'Consider using EXPECT_NE instead of EXPECT_FALSE(a == b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_FALSE(x != 42);',
+        'Consider using EXPECT_EQ instead of EXPECT_FALSE(a != b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_FALSE(x >= 42);',
+        'Consider using EXPECT_LT instead of EXPECT_FALSE(a >= b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'ASSERT_FALSE(x > 42);',
+        'Consider using ASSERT_LE instead of ASSERT_FALSE(a > b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'ASSERT_FALSE(x <= 42);',
+        'Consider using ASSERT_GT instead of ASSERT_FALSE(a <= b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'ASSERT_FALSE_M(x < 42);',
+        'Consider using ASSERT_GE_M instead of ASSERT_FALSE_M(a < b)'
+        '  [readability/check] [2]')
+
+    self.TestLint('CHECK(x<42);',
+                  ['Missing spaces around <'
+                   '  [whitespace/operators] [3]',
+                   'Consider using CHECK_LT instead of CHECK(a < b)'
+                   '  [readability/check] [2]'])
+    self.TestLint('CHECK(x>42);',
+                  ['Missing spaces around >'
+                   '  [whitespace/operators] [3]',
+                   'Consider using CHECK_GT instead of CHECK(a > b)'
+                   '  [readability/check] [2]'])
+
+    self.TestLint('using some::namespace::operator<<;', '')
+    self.TestLint('using some::namespace::operator>>;', '')
+
+    self.TestLint('CHECK(x->y == 42);',
+                  'Consider using CHECK_EQ instead of CHECK(a == b)'
+                  '  [readability/check] [2]')
+
+    self.TestLint(
+        '  EXPECT_TRUE(42 < x);  // Random comment.',
+        'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)'
+        '  [readability/check] [2]')
+    self.TestLint(
+        'EXPECT_TRUE( 42 < x );',
+        ['Extra space after ( in function call'
+         '  [whitespace/parens] [4]',
+         'Extra space before )  [whitespace/parens] [2]',
+         'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)'
+         '  [readability/check] [2]'])
+
+    self.TestLint('CHECK(4\'2 == x);',
+                  'Consider using CHECK_EQ instead of CHECK(a == b)'
+                  '  [readability/check] [2]')
+
+  def testCheckCheckFalsePositives(self):
+    self.TestLint('CHECK(some_iterator == obj.end());', '')
+    self.TestLint('EXPECT_TRUE(some_iterator == obj.end());', '')
+    self.TestLint('EXPECT_FALSE(some_iterator == obj.end());', '')
+    self.TestLint('CHECK(some_pointer != NULL);', '')
+    self.TestLint('EXPECT_TRUE(some_pointer != NULL);', '')
+    self.TestLint('EXPECT_FALSE(some_pointer != NULL);', '')
+
+    self.TestLint('CHECK(CreateTestFile(dir, (1 << 20)));', '')
+    self.TestLint('CHECK(CreateTestFile(dir, (1 >> 20)));', '')
+
+    self.TestLint('CHECK(x ^ (y < 42));', '')
+    self.TestLint('CHECK((x > 42) ^ (x < 54));', '')
+    self.TestLint('CHECK(a && b < 42);', '')
+    self.TestLint('CHECK(42 < a && a < b);', '')
+    self.TestLint('SOFT_CHECK(x > 42);', '')
+
+    self.TestMultiLineLint(
+        """_STLP_DEFINE_BINARY_OP_CHECK(==, _OP_EQUAL);
+        _STLP_DEFINE_BINARY_OP_CHECK(!=, _OP_NOT_EQUAL);
+        _STLP_DEFINE_BINARY_OP_CHECK(<, _OP_LESS_THAN);
+        _STLP_DEFINE_BINARY_OP_CHECK(<=, _OP_LESS_EQUAL);
+        _STLP_DEFINE_BINARY_OP_CHECK(>, _OP_GREATER_THAN);
+        _STLP_DEFINE_BINARY_OP_CHECK(>=, _OP_GREATER_EQUAL);
+        _STLP_DEFINE_BINARY_OP_CHECK(+, _OP_PLUS);
+        _STLP_DEFINE_BINARY_OP_CHECK(*, _OP_TIMES);
+        _STLP_DEFINE_BINARY_OP_CHECK(/, _OP_DIVIDE);
+        _STLP_DEFINE_BINARY_OP_CHECK(-, _OP_SUBTRACT);
+        _STLP_DEFINE_BINARY_OP_CHECK(%, _OP_MOD);""",
+        '')
+
+    self.TestLint('CHECK(x < 42) << "Custom error message";', '')
+
+  # Alternative token to punctuation operator replacements
+  def testCheckAltTokens(self):
+    self.TestLint('true or true',
+                  'Use operator || instead of or'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('true and true',
+                  'Use operator && instead of and'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('if (not true)',
+                  'Use operator ! instead of not'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('1 bitor 1',
+                  'Use operator | instead of bitor'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('1 xor 1',
+                  'Use operator ^ instead of xor'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('1 bitand 1',
+                  'Use operator & instead of bitand'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('x = compl 1',
+                  'Use operator ~ instead of compl'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('x and_eq y',
+                  'Use operator &= instead of and_eq'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('x or_eq y',
+                  'Use operator |= instead of or_eq'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('x xor_eq y',
+                  'Use operator ^= instead of xor_eq'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('x not_eq y',
+                  'Use operator != instead of not_eq'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('line_continuation or',
+                  'Use operator || instead of or'
+                  '  [readability/alt_tokens] [2]')
+    self.TestLint('if(true and(parentheses',
+                  'Use operator && instead of and'
+                  '  [readability/alt_tokens] [2]')
+
+    self.TestLint('#include "base/false-and-false.h"', '')
+    self.TestLint('#error false or false', '')
+    self.TestLint('false nor false', '')
+    self.TestLint('false nand false', '')
+
+  # Passing and returning non-const references
+  def testNonConstReference(self):
+    # Passing a non-const reference as function parameter is forbidden.
+    operand_error_message = ('Is this a non-const reference? '
+                             'If so, make const or use a pointer: %s'
+                             '  [runtime/references] [2]')
+    # Warn of use of a non-const reference in operators and functions
+    self.TestLint('bool operator>(Foo& s, Foo& f);',
+                  [operand_error_message % 'Foo& s',
+                   operand_error_message % 'Foo& f'])
+    self.TestLint('bool operator+(Foo& s, Foo& f);',
+                  [operand_error_message % 'Foo& s',
+                   operand_error_message % 'Foo& f'])
+    self.TestLint('int len(Foo& s);', operand_error_message % 'Foo& s')
+    # Allow use of non-const references in a few specific cases
+    self.TestLint('stream& operator>>(stream& s, Foo& f);', '')
+    self.TestLint('stream& operator<<(stream& s, Foo& f);', '')
+    self.TestLint('void swap(Bar& a, Bar& b);', '')
+    # Returning a non-const reference from a function is OK.
+    self.TestLint('int& g();', '')
+    # Passing a const reference to a struct (using the struct keyword) is OK.
+    self.TestLint('void foo(const struct tm& tm);', '')
+    # Passing a const reference to a typename is OK.
+    self.TestLint('void foo(const typename tm& tm);', '')
+    # Const reference to a pointer type is OK.
+    self.TestLint('void foo(const Bar* const& p) {', '')
+    self.TestLint('void foo(Bar const* const& p) {', '')
+    self.TestLint('void foo(Bar* const& p) {', '')
+    # Const reference to a templated type is OK.
+    self.TestLint('void foo(const std::vector<std::string>& v);', '')
+    # Non-const reference to a pointer type is not OK.
+    self.TestLint('void foo(Bar*& p);',
+                  operand_error_message % 'Bar*& p')
+    self.TestLint('void foo(const Bar*& p);',
+                  operand_error_message % 'const Bar*& p')
+    self.TestLint('void foo(Bar const*& p);',
+                  operand_error_message % 'Bar const*& p')
+    self.TestLint('void foo(struct Bar*& p);',
+                  operand_error_message % 'struct Bar*& p')
+    self.TestLint('void foo(const struct Bar*& p);',
+                  operand_error_message % 'const struct Bar*& p')
+    self.TestLint('void foo(struct Bar const*& p);',
+                  operand_error_message % 'struct Bar const*& p')
+    # Non-const reference to a templated type is not OK.
+    self.TestLint('void foo(std::vector<int>& p);',
+                  operand_error_message % 'std::vector<int>& p')
+    # Returning an address of something is not prohibited.
+    self.TestLint('return &something;', '')
+    self.TestLint('if (condition) {return &something; }', '')
+    self.TestLint('if (condition) return &something;', '')
+    self.TestLint('if (condition) address = &something;', '')
+    self.TestLint('if (condition) result = lhs&rhs;', '')
+    self.TestLint('if (condition) result = lhs & rhs;', '')
+    self.TestLint('a = (b+c) * sizeof &f;', '')
+    self.TestLint('a = MySize(b) * sizeof &f;', '')
+    # We don't get confused by C++11 range-based for loops.
+    self.TestLint('for (const string& s : c)', '')
+    self.TestLint('for (auto& r : c)', '')
+    self.TestLint('for (typename Type& a : b)', '')
+    # We don't get confused by some other uses of '&'.
+    self.TestLint('T& operator=(const T& t);', '')
+    self.TestLint('int g() { return (a & b); }', '')
+    self.TestLint('T& r = (T&)*(vp());', '')
+    self.TestLint('T& r = v', '')
+    self.TestLint('static_assert((kBits & kMask) == 0, "text");', '')
+    self.TestLint('COMPILE_ASSERT((kBits & kMask) == 0, text);', '')
+    # Spaces before template arguments.  This is poor style, but
+    # happens 0.15% of the time.
+    self.TestLint('void Func(const vector <int> &const_x, '
+                  'vector <int> &nonconst_x) {',
+                  operand_error_message % 'vector<int> &nonconst_x')
+
+    # Derived member functions are spared from override check
+    self.TestLint('void Func(X& x);', operand_error_message % 'X& x')
+    self.TestLint('void Func(X& x) {}', operand_error_message % 'X& x')
+    self.TestLint('void Func(X& x) override;', '')
+    self.TestLint('void Func(X& x) override {', '')
+    self.TestLint('void Func(X& x) const override;', '')
+    self.TestLint('void Func(X& x) const override {', '')
+
+    # Don't warn on out-of-line method definitions.
+    self.TestLint('void NS::Func(X& x) {', '')
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company. All Rights Reserved.',
+         'void a::b() {}',
+         'void f(int& q) {}',
+         ''],
+        error_collector)
+    self.assertEquals(
+        operand_error_message % 'int& q',
+        error_collector.Results())
+
+    # Other potential false positives.  These need full parser
+    # state to reproduce as opposed to just TestLint.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company. All Rights Reserved.',
+         'void swap(int &x,',
+         '          int &y) {',
+         '}',
+         'void swap(',
+         '    sparsegroup<T, GROUP_SIZE, Alloc> &x,',
+         '    sparsegroup<T, GROUP_SIZE, Alloc> &y) {',
+         '}',
+         'ostream& operator<<(',
+         '    ostream& out',
+         '    const dense_hash_set<Value, Hash, Equals, Alloc>& seq) {',
+         '}',
+         'class A {',
+         '  void Function(',
+         '      string &x) override {',
+         '  }',
+         '};',
+         'void Derived::Function(',
+         '    string &x) {',
+         '}',
+         '#define UNSUPPORTED_MASK(_mask) \\',
+         '  if (flags & _mask) { \\',
+         '    LOG(FATAL) << "Unsupported flag: " << #_mask; \\',
+         '  }',
+         'Constructor::Constructor()',
+         '    : initializer1_(a1 & b1),',
+         '      initializer2_(a2 & b2) {',
+         '}',
+         'Constructor::Constructor()',
+         '    : initializer1_{a3 & b3},',
+         '      initializer2_(a4 & b4) {',
+         '}',
+         'Constructor::Constructor()',
+         '    : initializer1_{a5 & b5},',
+         '      initializer2_(a6 & b6) {}',
+         ''],
+        error_collector)
+    self.assertEquals('', error_collector.Results())
+
+    # Multi-line references
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company. All Rights Reserved.',
+         'void Func(const Outer::',
+         '              Inner& const_x,',
+         '          const Outer',
+         '              ::Inner& const_y,',
+         '          const Outer<',
+         '              int>::Inner& const_z,',
+         '          Outer::',
+         '              Inner& nonconst_x,',
+         '          Outer',
+         '              ::Inner& nonconst_y,',
+         '          Outer<',
+         '              int>::Inner& nonconst_z) {',
+         '}',
+         ''],
+        error_collector)
+    self.assertEquals(
+        [operand_error_message % 'Outer::Inner& nonconst_x',
+         operand_error_message % 'Outer::Inner& nonconst_y',
+         operand_error_message % 'Outer<int>::Inner& nonconst_z'],
+        error_collector.Results())
+
+    # A peculiar false positive due to bad template argument parsing
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company. All Rights Reserved.',
+         'inline RCULocked<X>::ReadPtr::ReadPtr(const RCULocked* rcu) {',
+         '  DCHECK(!(data & kFlagMask)) << "Error";',
+         '}',
+         '',
+         'RCULocked<X>::WritePtr::WritePtr(RCULocked* rcu)',
+         '    : lock_(&rcu_->mutex_) {',
+         '}',
+         ''],
+        error_collector.Results())
+    self.assertEquals('', error_collector.Results())
+
+  def testBraceAtBeginOfLine(self):
+    self.TestLint('{',
+                  '{ should almost always be at the end of the previous line'
+                  '  [whitespace/braces] [4]')
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['int function()',
+                             '{',  # warning here
+                             '  MutexLock l(&mu);',
+                             '}',
+                             'int variable;'
+                             '{',  # no warning
+                             '  MutexLock l(&mu);',
+                             '}',
+                             'MyType m = {',
+                             '  {value1, value2},',
+                             '  {',  # no warning
+                             '    loooong_value1, looooong_value2',
+                             '  }',
+                             '};',
+                             '#if PREPROCESSOR',
+                             '{',  # no warning
+                             '  MutexLock l(&mu);',
+                             '}',
+                             '#endif'],
+                            error_collector)
+    self.assertEquals(1, error_collector.Results().count(
+        '{ should almost always be at the end of the previous line'
+        '  [whitespace/braces] [4]'))
+
+    self.TestMultiLineLint(
+        """
+        foo(
+          {
+            loooooooooooooooong_value,
+          });""",
+        '')
+
+  def testMismatchingSpacesInParens(self):
+    self.TestLint('if (foo ) {', 'Mismatching spaces inside () in if'
+                  '  [whitespace/parens] [5]')
+    self.TestLint('switch ( foo) {', 'Mismatching spaces inside () in switch'
+                  '  [whitespace/parens] [5]')
+    self.TestLint('for (foo; ba; bar ) {', 'Mismatching spaces inside () in for'
+                  '  [whitespace/parens] [5]')
+    self.TestLint('for (; foo; bar) {', '')
+    self.TestLint('for ( ; foo; bar) {', '')
+    self.TestLint('for ( ; foo; bar ) {', '')
+    self.TestLint('for (foo; bar; ) {', '')
+    self.TestLint('while (  foo  ) {', 'Should have zero or one spaces inside'
+                  ' ( and ) in while  [whitespace/parens] [5]')
+
+  def testSpacingForFncall(self):
+    self.TestLint('if (foo) {', '')
+    self.TestLint('for (foo; bar; baz) {', '')
+    self.TestLint('for (;;) {', '')
+    # Space should be allowed in placement new operators.
+    self.TestLint('Something* p = new (place) Something();', '')
+    # Test that there is no warning when increment statement is empty.
+    self.TestLint('for (foo; baz;) {', '')
+    self.TestLint('for (foo;bar;baz) {', 'Missing space after ;'
+                  '  [whitespace/semicolon] [3]')
+    # we don't warn about this semicolon, at least for now
+    self.TestLint('if (condition) {return &something; }',
+                  '')
+    # seen in some macros
+    self.TestLint('DoSth();\\', '')
+    # Test that there is no warning about semicolon here.
+    self.TestLint('abc;// this is abc',
+                  'At least two spaces is best between code'
+                  ' and comments  [whitespace/comments] [2]')
+    self.TestLint('while (foo) {', '')
+    self.TestLint('switch (foo) {', '')
+    self.TestLint('foo( bar)', 'Extra space after ( in function call'
+                  '  [whitespace/parens] [4]')
+    self.TestLint('foo(  // comment', '')
+    self.TestLint('foo( // comment',
+                  'At least two spaces is best between code'
+                  ' and comments  [whitespace/comments] [2]')
+    self.TestLint('foobar( \\', '')
+    self.TestLint('foobar(     \\', '')
+    self.TestLint('( a + b)', 'Extra space after ('
+                  '  [whitespace/parens] [2]')
+    self.TestLint('((a+b))', '')
+    self.TestLint('foo (foo)', 'Extra space before ( in function call'
+                  '  [whitespace/parens] [4]')
+    self.TestLint('} catch (const Foo& ex) {', '')
+    self.TestLint('case (42):', '')
+    self.TestLint('typedef foo (*foo)(foo)', '')
+    self.TestLint('typedef foo (*foo12bar_)(foo)', '')
+    self.TestLint('typedef foo (Foo::*bar)(foo)', '')
+    self.TestLint('using foo = type (Foo::*bar)(foo)', '')
+    self.TestLint('using foo = type (Foo::*bar)(', '')
+    self.TestLint('using foo = type (Foo::*)(', '')
+    self.TestLint('foo (Foo::*bar)(', '')
+    self.TestLint('foo (x::y::*z)(', '')
+    self.TestLint('foo (Foo::bar)(',
+                  'Extra space before ( in function call'
+                  '  [whitespace/parens] [4]')
+    self.TestLint('foo (*bar)(', '')
+    self.TestLint('typedef foo (Foo::*bar)(', '')
+    self.TestLint('(foo)(bar)', '')
+    self.TestLint('Foo (*foo)(bar)', '')
+    self.TestLint('Foo (*foo)(Bar bar,', '')
+    self.TestLint('char (*p)[sizeof(foo)] = &foo', '')
+    self.TestLint('char (&ref)[sizeof(foo)] = &foo', '')
+    self.TestLint('const char32 (*table[])[6];', '')
+    # The sizeof operator is often written as if it were a function call, with
+    # an opening parenthesis directly following the operator name, but it can
+    # also be written like any other operator, with a space following the
+    # operator name, and the argument optionally in parentheses.
+    self.TestLint('sizeof(foo)', '')
+    self.TestLint('sizeof foo', '')
+    self.TestLint('sizeof (foo)', '')
+
+  def testSpacingBeforeBraces(self):
+    self.TestLint('if (foo){', 'Missing space before {'
+                  '  [whitespace/braces] [5]')
+    self.TestLint('for{', 'Missing space before {'
+                  '  [whitespace/braces] [5]')
+    self.TestLint('for {', '')
+    self.TestLint('EXPECT_DEBUG_DEATH({', '')
+    self.TestLint('std::is_convertible<A, B>{}', '')
+
+  def testSemiColonAfterBraces(self):
+    self.TestLint('if (cond) {};',
+                  'You don\'t need a ; after a }  [readability/braces] [4]')
+    self.TestLint('void Func() {};',
+                  'You don\'t need a ; after a }  [readability/braces] [4]')
+    self.TestLint('void Func() const {};',
+                  'You don\'t need a ; after a }  [readability/braces] [4]')
+    self.TestLint('class X {};', '')
+    for keyword in ['struct', 'union']:
+      for align in ['', ' alignas(16)']:
+        for typename in ['', ' X']:
+          for identifier in ['', ' x']:
+            self.TestLint(keyword + align + typename + ' {}' + identifier + ';',
+                          '')
+
+    self.TestLint('class X : public Y {};', '')
+    self.TestLint('class X : public MACRO() {};', '')
+    self.TestLint('DEFINE_FACADE(PCQueue::Watcher, PCQueue) {};', '')
+    self.TestLint('VCLASS(XfaTest, XfaContextTest) {};', '')
+    self.TestLint('TEST(TestCase, TestName) {};',
+                  'You don\'t need a ; after a }  [readability/braces] [4]')
+    self.TestLint('TEST_F(TestCase, TestName) {};',
+                  'You don\'t need a ; after a }  [readability/braces] [4]')
+
+    self.TestLint('file_tocs_[i] = (FileToc) {a, b, c};', '')
+    self.TestMultiLineLint('class X : public Y,\npublic Z {};', '')
+
+  def testLambda(self):
+    self.TestLint('auto x = []() {};', '')
+    self.TestLint('return []() {};', '')
+    self.TestMultiLineLint('auto x = []() {\n};\n', '')
+    self.TestLint('int operator[](int x) {};',
+                  'You don\'t need a ; after a }  [readability/braces] [4]')
+
+    self.TestMultiLineLint('auto x = [&a,\nb]() {};', '')
+    self.TestMultiLineLint('auto x = [&a,\nb]\n() {};', '')
+    self.TestMultiLineLint('auto x = [&a,\n'
+                           '          b](\n'
+                           '    int a,\n'
+                           '    int b) {\n'
+                           '  return a +\n'
+                           '         b;\n'
+                           '};\n',
+                           '')
+
+    for lambda_with_default_capture in ('void f() { [=]{}; }',
+                                        'void f() { [=](int i) {}; }',
+                                        'void f() { [=, &x]{}; }',
+                                        'void f() { [&]{}; }',
+                                        'void f() { [ & ]{}; }',
+                                        'void f() { [&, y]{}; }'):
+      self.TestLint(lambda_with_default_capture,
+                    'Default lambda captures are an unapproved C++ feature.  '
+                    '[build/c++11] [4]')
+
+    # "[&...]" isn't necessarily a default capture, though "[=...]" always is.
+    self.TestLint('void f() { [&variable]{}; }', '')
+
+    # Avoid false positives with operator[]
+    self.TestLint('table_to_children[&*table].push_back(dependent);', '')
+
+  def testBraceInitializerList(self):
+    self.TestLint('MyStruct p = {1, 2};', '')
+    self.TestLint('MyStruct p{1, 2};', '')
+    self.TestLint('vector<int> p = {1, 2};', '')
+    self.TestLint('vector<int> p{1, 2};', '')
+    self.TestLint('x = vector<int>{1, 2};', '')
+    self.TestLint('x = (struct in_addr){ 0 };', '')
+    self.TestLint('Func(vector<int>{1, 2})', '')
+    self.TestLint('Func((struct in_addr){ 0 })', '')
+    self.TestLint('Func(vector<int>{1, 2}, 3)', '')
+    self.TestLint('Func((struct in_addr){ 0 }, 3)', '')
+    self.TestLint('LOG(INFO) << char{7};', '')
+    self.TestLint('LOG(INFO) << char{7} << "!";', '')
+    self.TestLint('int p[2] = {1, 2};', '')
+    self.TestLint('return {1, 2};', '')
+    self.TestLint('std::unique_ptr<Foo> foo{new Foo{}};', '')
+    self.TestLint('auto foo = std::unique_ptr<Foo>{new Foo{}};', '')
+    self.TestLint('static_assert(Max7String{}.IsValid(), "");', '')
+    self.TestLint('map_of_pairs[{1, 2}] = 3;', '')
+    self.TestLint('ItemView{has_offer() ? new Offer{offer()} : nullptr', '')
+    self.TestLint('template <class T, EnableIf<::std::is_const<T>{}> = 0>', '')
+
+    self.TestMultiLineLint('std::unique_ptr<Foo> foo{\n'
+                           '  new Foo{}\n'
+                           '};\n', '')
+    self.TestMultiLineLint('std::unique_ptr<Foo> foo{\n'
+                           '  new Foo{\n'
+                           '    new Bar{}\n'
+                           '  }\n'
+                           '};\n', '')
+    self.TestMultiLineLint('if (true) {\n'
+                           '  if (false){}\n'
+                           '}\n',
+                           'Missing space before {  [whitespace/braces] [5]')
+    self.TestMultiLineLint('MyClass::MyClass()\n'
+                           '    : initializer_{\n'
+                           '          Func()} {\n'
+                           '}\n', '')
+
+  def testSpacingAroundElse(self):
+    self.TestLint('}else {', 'Missing space before else'
+                  '  [whitespace/braces] [5]')
+    self.TestLint('} else{', 'Missing space before {'
+                  '  [whitespace/braces] [5]')
+    self.TestLint('} else {', '')
+    self.TestLint('} else if (foo) {', '')
+
+  def testSpacingWithInitializerLists(self):
+    self.TestLint('int v[1][3] = {{1, 2, 3}};', '')
+    self.TestLint('int v[1][1] = {{0}};', '')
+
+  def testSpacingForBinaryOps(self):
+    self.TestLint('if (foo||bar) {', 'Missing spaces around ||'
+                  '  [whitespace/operators] [3]')
+    self.TestLint('if (foo<=bar) {', 'Missing spaces around <='
+                  '  [whitespace/operators] [3]')
+    self.TestLint('if (foo<bar) {', 'Missing spaces around <'
+                  '  [whitespace/operators] [3]')
+    self.TestLint('if (foo>bar) {', 'Missing spaces around >'
+                  '  [whitespace/operators] [3]')
+    self.TestLint('if (foo<bar->baz) {', 'Missing spaces around <'
+                  '  [whitespace/operators] [3]')
+    self.TestLint('if (foo<bar->bar) {', 'Missing spaces around <'
+                  '  [whitespace/operators] [3]')
+    self.TestLint('template<typename T = double>', '')
+    self.TestLint('std::unique_ptr<No<Spaces>>', '')
+    self.TestLint('typedef hash_map<Foo, Bar>', '')
+    self.TestLint('10<<20', '')
+    self.TestLint('10<<a',
+                  'Missing spaces around <<  [whitespace/operators] [3]')
+    self.TestLint('a<<20',
+                  'Missing spaces around <<  [whitespace/operators] [3]')
+    self.TestLint('a<<b',
+                  'Missing spaces around <<  [whitespace/operators] [3]')
+    self.TestLint('10ULL<<20', '')
+    self.TestLint('a>>b',
+                  'Missing spaces around >>  [whitespace/operators] [3]')
+    self.TestLint('10>>b',
+                  'Missing spaces around >>  [whitespace/operators] [3]')
+    self.TestLint('LOG(ERROR)<<*foo',
+                  'Missing spaces around <<  [whitespace/operators] [3]')
+    self.TestLint('LOG(ERROR)<<&foo',
+                  'Missing spaces around <<  [whitespace/operators] [3]')
+    self.TestLint('StringCoder<vector<string>>::ToString()', '')
+    self.TestLint('map<pair<int, int>, map<int, int>>::iterator', '')
+    self.TestLint('func<int, pair<int, pair<int, int>>>()', '')
+    self.TestLint('MACRO1(list<list<int>>)', '')
+    self.TestLint('MACRO2(list<list<int>>, 42)', '')
+    self.TestLint('void DoFoo(const set<vector<string>>& arg1);', '')
+    self.TestLint('void SetFoo(set<vector<string>>* arg1);', '')
+    self.TestLint('foo = new set<vector<string>>;', '')
+    self.TestLint('reinterpret_cast<set<vector<string>>*>(a);', '')
+    self.TestLint('MACRO(<<)', '')
+    self.TestLint('MACRO(<<, arg)', '')
+    self.TestLint('MACRO(<<=)', '')
+    self.TestLint('MACRO(<<=, arg)', '')
+
+    self.TestLint('using Vector3<T>::operator==;', '')
+    self.TestLint('using Vector3<T>::operator!=;', '')
+
+  def testRvalueReference(self):
+    space_error = 'Missing spaces around &&  [whitespace/operators] [3]'
+    rvalue_error = ('RValue references are an unapproved C++ feature.'
+                    '  [build/c++11] [3]')
+
+    # Places where lack of space are allowed
+    self.TestLint('DEFINE_BINARY_OPERATOR(&&)', '')
+    self.TestLint('bool operator&&(A b) {}', '')
+    self.TestLint('bool operator&&(A b) {', '')
+    self.TestLint('bool operator&&(A b);', '')
+
+    # Assignment expressions
+    self.TestLint('a = b && c;', '')
+    self.TestLint('a = b&& c;', space_error)
+    self.TestLint('a = b &&c;', space_error)
+    self.TestLint('a = (b&& c);', space_error)
+    self.TestLint('a = (b &&c);', space_error)
+    self.TestLint('a&& b = c;', rvalue_error)
+    self.TestLint('a<b>&& c = d;', rvalue_error)
+    self.TestLint('auto&& a = b;', rvalue_error)
+    self.TestLint('const a&& b = c;', rvalue_error)
+    self.TestLint('struct a&& b = c;', rvalue_error)
+    self.TestLint('decltype(a)&& b = c;', rvalue_error)
+
+    # Cast expressions
+    self.TestLint('a = const_cast<b&&>(c);', rvalue_error)
+    self.TestLint('a = const_cast<const b&&>(c);', rvalue_error)
+    self.TestLint('a = static_cast<b&&>(c);', rvalue_error)
+    self.TestLint('a = static_cast<const b&&>(c);', rvalue_error)
+    self.TestLint('a = dynamic_cast<b&&>(c);', rvalue_error)
+    self.TestLint('a = dynamic_cast<const b&&>(c);', rvalue_error)
+    self.TestLint('a = reinterpret_cast<b&&>(c);', rvalue_error)
+    self.TestLint('a = reinterpret_cast<const b&&>(c);', rvalue_error)
+    self.TestLint('a = cast < b&& c;', space_error)
+
+    # Function parameters
+    for indent in ['', '  ']:
+      for head in ['void Func', 'vector<int> Func', 'vector<int>\nFunc',
+                   'inline void Func',
+                   'Constructor', 'Constructor::Constructor',
+                   'operator=', 'operator =', 'operator = ']:
+        for body in [' {}', ' {', ';']:
+          self.TestMultiLineLint(indent + head + '(A&& b)' + body, rvalue_error)
+          self.TestMultiLineLint(indent + head + '(A &&b)' + body, rvalue_error)
+          self.TestMultiLineLint(indent + head + '(A&&... b)' + body,
+                                 rvalue_error)
+          self.TestMultiLineLint(indent + head + '(A<B>&& c)' + body,
+                                 rvalue_error)
+          self.TestMultiLineLint(indent + head + '(A<B> &&c)' + body,
+                                 rvalue_error)
+
+    # Function templates
+    self.TestLint('std::conditional<A, B&, C&&>::type', rvalue_error)
+    self.TestLint('std::conditional<A, B&&, C&>::type', rvalue_error)
+
+    # Template functions
+    self.TestLint('template <typename T> R&& F()', rvalue_error)
+    self.TestLint('template <typename T> R&& F() {', rvalue_error)
+    self.TestMultiLineLint('template <typename T>\nR&& F()', rvalue_error)
+    self.TestMultiLineLint('template <typename T>\nR&& F() {', rvalue_error)
+    self.TestLint('template <typename T> void F(T a, R&& b)', rvalue_error)
+    self.TestLint('template <typename T> void F(T a, R &&b)', rvalue_error)
+    self.TestLint('template <typename T> void F(T a, R&& b) {', rvalue_error)
+
+    # For loops
+    self.TestLint('for (a&& b;;)', rvalue_error)
+    self.TestLint('for (a&& b;;) {', rvalue_error)
+    self.TestLint('for (; a&& b;)', space_error)
+    self.TestLint('for (; a&& b;) {', space_error)
+
+    # Constructors
+    self.TestLint('A(a&& b)', rvalue_error)
+    self.TestLint('explicit A(a&& b)', rvalue_error)
+    self.TestLint('A(a b) : c(d&& e)', space_error)
+    self.TestLint('A(a b) : c(), d(e&& f)', space_error)
+
+  def testAllowedRvalueReference(self):
+    # Verify that RValue reference warnings for a line range can be silenced
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['// Copyright 2014 Your Company.',
+                             'GOOGLE_ALLOW_RVALUE_REFERENCES_PUSH',
+                             'void F(A&& b);',
+                             'GOOGLE_ALLOW_RVALUE_REFERENCES_POP',
+                             ''],
+                            error_collector)
+    self.assertEquals(error_collector.Results(), '')
+
+    # RValue references for constructors and operator=
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company.',
+         'class X {',
+         '  X(X&& param) = delete;  // NOLINT(runtime/explicit)',
+         '  X(X &&param) = default;  // NOLINT(runtime/explicit)',
+         '  inline X(X&& param) = default;  // NOLINT(runtime/explicit)',
+         '',
+         '  X& operator=(X&& param) = delete;',
+         '  X& operator=(X&& param) = default;',
+         '};',
+         'A::A(A&&) = default;',
+         'Outer::Inner::Inner(Inner&&) = default;',
+         ''],
+        error_collector)
+    self.assertEquals(error_collector.Results(), '')
+
+    # Assume templated function parameters are forwarded, and are allowed
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company.',
+         'template <typename Allowed1>',
+         'void Function1(Allowed1&& a);',
+         '',
+         'template <typename Allowed2, typename Allowed3>',
+         'void Function2(Allowed2&& a, Allowed3 &&b) {',
+         '}',
+         '',
+         'template <class Allowed4>',
+         'void Function3(Ignored1 *a, Allowed4&& b) {',
+         '}',
+         '',
+         'template <typename... Allowed5>',
+         'void Function4(Allowed5&&... a) {',
+         '}',
+         '',
+         'template <class... Allowed6>',
+         'void Function5(',
+         '    Allowed6 &&...a) {',
+         '}',
+         ''],
+        error_collector)
+    self.assertEquals(error_collector.Results(), '')
+
+  def testSpacingBeforeLastSemicolon(self):
+    self.TestLint('call_function() ;',
+                  'Extra space before last semicolon. If this should be an '
+                  'empty statement, use {} instead.'
+                  '  [whitespace/semicolon] [5]')
+    self.TestLint('while (true) ;',
+                  'Extra space before last semicolon. If this should be an '
+                  'empty statement, use {} instead.'
+                  '  [whitespace/semicolon] [5]')
+    self.TestLint('default:;',
+                  'Semicolon defining empty statement. Use {} instead.'
+                  '  [whitespace/semicolon] [5]')
+    self.TestLint('      ;',
+                  'Line contains only semicolon. If this should be an empty '
+                  'statement, use {} instead.'
+                  '  [whitespace/semicolon] [5]')
+    self.TestLint('for (int i = 0; ;', '')
+
+  def testEmptyBlockBody(self):
+    self.TestLint('while (true);',
+                  'Empty loop bodies should use {} or continue'
+                  '  [whitespace/empty_loop_body] [5]')
+    self.TestLint('if (true);',
+                  'Empty conditional bodies should use {}'
+                  '  [whitespace/empty_conditional_body] [5]')
+    self.TestLint('while (true)', '')
+    self.TestLint('while (true) continue;', '')
+    self.TestLint('for (;;);',
+                  'Empty loop bodies should use {} or continue'
+                  '  [whitespace/empty_loop_body] [5]')
+    self.TestLint('for (;;)', '')
+    self.TestLint('for (;;) continue;', '')
+    self.TestLint('for (;;) func();', '')
+    self.TestMultiLineLint("""while (true &&
+                                     false);""",
+                           'Empty loop bodies should use {} or continue'
+                           '  [whitespace/empty_loop_body] [5]')
+    self.TestMultiLineLint("""do {
+                           } while (false);""",
+                           '')
+    self.TestMultiLineLint("""#define MACRO \\
+                           do { \\
+                           } while (false);""",
+                           '')
+    self.TestMultiLineLint("""do {
+                           } while (false);  // next line gets a warning
+                           while (false);""",
+                           'Empty loop bodies should use {} or continue'
+                           '  [whitespace/empty_loop_body] [5]')
+
+  def testSpacingForRangeBasedFor(self):
+    # Basic correctly formatted case:
+    self.TestLint('for (int i : numbers) {', '')
+
+    # Missing space before colon:
+    self.TestLint('for (int i: numbers) {',
+                  'Missing space around colon in range-based for loop'
+                  '  [whitespace/forcolon] [2]')
+    # Missing space after colon:
+    self.TestLint('for (int i :numbers) {',
+                  'Missing space around colon in range-based for loop'
+                  '  [whitespace/forcolon] [2]')
+    # Missing spaces both before and after the colon.
+    self.TestLint('for (int i:numbers) {',
+                  'Missing space around colon in range-based for loop'
+                  '  [whitespace/forcolon] [2]')
+
+    # The scope operator '::' shouldn't cause warnings...
+    self.TestLint('for (std::size_t i : sizes) {}', '')
+    # ...but it shouldn't suppress them either.
+    self.TestLint('for (std::size_t i: sizes) {}',
+                  'Missing space around colon in range-based for loop'
+                  '  [whitespace/forcolon] [2]')
+
+
+  # Static or global STL strings.
+  def testStaticOrGlobalSTLStrings(self):
+    error_msg = ('For a static/global string constant, use a C style '
+                 'string instead: "%s[]".  [runtime/string] [4]')
+
+    self.TestLint('string foo;',
+                  error_msg % 'char foo')
+    self.TestLint('string kFoo = "hello";  // English',
+                  error_msg % 'char kFoo')
+    self.TestLint('static string foo;',
+                  error_msg % 'static char foo')
+    self.TestLint('static const string foo;',
+                  error_msg % 'static const char foo')
+    self.TestLint('string Foo::bar;',
+                  error_msg % 'char Foo::bar')
+    self.TestLint('string* pointer', '')
+    self.TestLint('string *pointer', '')
+    self.TestLint('string* pointer = Func();', '')
+    self.TestLint('string *pointer = Func();', '')
+    self.TestLint('const string* pointer', '')
+    self.TestLint('const string *pointer', '')
+    self.TestLint('const string* pointer = Func();', '')
+    self.TestLint('const string *pointer = Func();', '')
+    self.TestLint('string const* pointer', '')
+    self.TestLint('string const *pointer', '')
+    self.TestLint('string const* pointer = Func();', '')
+    self.TestLint('string const *pointer = Func();', '')
+    self.TestLint('string* const pointer', '')
+    self.TestLint('string *const pointer', '')
+    self.TestLint('string* const pointer = Func();', '')
+    self.TestLint('string *const pointer = Func();', '')
+    self.TestLint('string Foo::bar() {}', '')
+    self.TestLint('string Foo::operator*() {}', '')
+    # Rare case.
+    self.TestLint('string foo("foobar");', error_msg % 'char foo')
+    # Should not catch local or member variables.
+    self.TestLint('  string foo', '')
+    # Should not catch functions.
+    self.TestLint('string EmptyString() { return ""; }', '')
+    self.TestLint('string EmptyString () { return ""; }', '')
+    self.TestLint('string VeryLongNameFunctionSometimesEndsWith(\n'
+                  '    VeryLongNameType very_long_name_variable) {}', '')
+    self.TestLint('template<>\n'
+                  'string FunctionTemplateSpecialization<SomeType>(\n'
+                  '      int x) { return ""; }', '')
+    self.TestLint('template<>\n'
+                  'string FunctionTemplateSpecialization<vector<A::B>* >(\n'
+                  '      int x) { return ""; }', '')
+
+    # should not catch methods of template classes.
+    self.TestLint('string Class<Type>::Method() const {\n'
+                  '  return "";\n'
+                  '}\n', '')
+    self.TestLint('string Class<Type>::Method(\n'
+                  '   int arg) const {\n'
+                  '  return "";\n'
+                  '}\n', '')
+
+    # Check multiline cases.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['// Copyright 2014 Your Company.',
+                             'string Class',
+                             '::MemberFunction1();',
+                             'string Class::',
+                             'MemberFunction2();',
+                             'string Class::',
+                             'NestedClass::MemberFunction3();',
+                             'string TemplateClass<T>::',
+                             'NestedClass::MemberFunction4();',
+                             'string Class',
+                             '::static_member_variable1;',
+                             'string Class::',
+                             'static_member_variable2;',
+                             'string Class',
+                             '::static_member_variable3 = "initial value";',
+                             'string Class::',
+                             'static_member_variable4 = "initial value";',
+                             ''],
+                            error_collector)
+    self.assertEquals(error_collector.Results(),
+                      [error_msg % 'char Class::static_member_variable1',
+                       error_msg % 'char Class::static_member_variable2',
+                       error_msg % 'char Class::static_member_variable3',
+                       error_msg % 'char Class::static_member_variable4'])
+
+  def testNoSpacesInFunctionCalls(self):
+    self.TestLint('TellStory(1, 3);',
+                  '')
+    self.TestLint('TellStory(1, 3 );',
+                  'Extra space before )'
+                  '  [whitespace/parens] [2]')
+    self.TestLint('TellStory(1 /* wolf */, 3 /* pigs */);',
+                  '')
+    self.TestMultiLineLint("""TellStory(1, 3
+                                        );""",
+                           'Closing ) should be moved to the previous line'
+                           '  [whitespace/parens] [2]')
+    self.TestMultiLineLint("""TellStory(Wolves(1),
+                                        Pigs(3
+                                        ));""",
+                           'Closing ) should be moved to the previous line'
+                           '  [whitespace/parens] [2]')
+    self.TestMultiLineLint("""TellStory(1,
+                                        3 );""",
+                           'Extra space before )'
+                           '  [whitespace/parens] [2]')
+
+  def testToDoComments(self):
+    start_space = ('Too many spaces before TODO'
+                   '  [whitespace/todo] [2]')
+    missing_username = ('Missing username in TODO; it should look like '
+                        '"// TODO(my_username): Stuff."'
+                        '  [readability/todo] [2]')
+    end_space = ('TODO(my_username) should be followed by a space'
+                 '  [whitespace/todo] [2]')
+
+    self.TestLint('//   TODOfix this',
+                  [start_space, missing_username, end_space])
+    self.TestLint('//   TODO(ljenkins)fix this',
+                  [start_space, end_space])
+    self.TestLint('//   TODO fix this',
+                  [start_space, missing_username])
+    self.TestLint('// TODO fix this', missing_username)
+    self.TestLint('// TODO: fix this', missing_username)
+    self.TestLint('//TODO(ljenkins): Fix this',
+                  'Should have a space between // and comment'
+                  '  [whitespace/comments] [4]')
+    self.TestLint('// TODO(ljenkins):Fix this', end_space)
+    self.TestLint('// TODO(ljenkins):', '')
+    self.TestLint('// TODO(ljenkins): fix this', '')
+    self.TestLint('// TODO(ljenkins): Fix this', '')
+    self.TestLint('#if 1  // TEST_URLTODOCID_WHICH_HAS_THAT_WORD_IN_IT_H_', '')
+    self.TestLint('// See also similar TODO above', '')
+
+  def testTwoSpacesBetweenCodeAndComments(self):
+    self.TestLint('} // namespace foo',
+                  'At least two spaces is best between code and comments'
+                  '  [whitespace/comments] [2]')
+    self.TestLint('}// namespace foo',
+                  'At least two spaces is best between code and comments'
+                  '  [whitespace/comments] [2]')
+    self.TestLint('printf("foo"); // Outside quotes.',
+                  'At least two spaces is best between code and comments'
+                  '  [whitespace/comments] [2]')
+    self.TestLint('int i = 0;  // Having two spaces is fine.', '')
+    self.TestLint('int i = 0;   // Having three spaces is OK.', '')
+    self.TestLint('// Top level comment', '')
+    self.TestLint('  // Line starts with two spaces.', '')
+    self.TestMultiLineLint('void foo() {\n'
+                           '  { // A scope is opening.\n'
+                           '    int a;', '')
+    self.TestMultiLineLint('void foo() {\n'
+                           '  { // A scope is opening.\n'
+                           '#define A a',
+                           'At least two spaces is best between code and '
+                           'comments  [whitespace/comments] [2]')
+    self.TestMultiLineLint('  foo();\n'
+                           '  { // An indented scope is opening.\n'
+                           '    int a;', '')
+    self.TestMultiLineLint('vector<int> my_elements = {// first\n'
+                           '                           1,', '')
+    self.TestMultiLineLint('vector<int> my_elements = {// my_elements is ..\n'
+                           '    1,',
+                           'At least two spaces is best between code and '
+                           'comments  [whitespace/comments] [2]')
+    self.TestLint('if (foo) { // not a pure scope; comment is too close!',
+                  'At least two spaces is best between code and comments'
+                  '  [whitespace/comments] [2]')
+    self.TestLint('printf("// In quotes.")', '')
+    self.TestLint('printf("\\"%s // In quotes.")', '')
+    self.TestLint('printf("%s", "// In quotes.")', '')
+
+  def testSpaceAfterCommentMarker(self):
+    self.TestLint('//', '')
+    self.TestLint('//x', 'Should have a space between // and comment'
+                  '  [whitespace/comments] [4]')
+    self.TestLint('// x', '')
+    self.TestLint('///', '')
+    self.TestLint('/// x', '')
+    self.TestLint('//!', '')
+    self.TestLint('//----', '')
+    self.TestLint('//====', '')
+    self.TestLint('//////', '')
+    self.TestLint('////// x', '')
+    self.TestLint('///< x', '') # After-member Doxygen comment
+    self.TestLint('//!< x', '') # After-member Doxygen comment
+    self.TestLint('////x', 'Should have a space between // and comment'
+                  '  [whitespace/comments] [4]')
+    self.TestLint('//}', '')
+    self.TestLint('//}x', 'Should have a space between // and comment'
+                  '  [whitespace/comments] [4]')
+    self.TestLint('//!<x', 'Should have a space between // and comment'
+                  '  [whitespace/comments] [4]')
+    self.TestLint('///<x', 'Should have a space between // and comment'
+                  '  [whitespace/comments] [4]')
+
+  # Test a line preceded by empty or comment lines.  There was a bug
+  # that caused it to print the same warning N times if the erroneous
+  # line was preceded by N lines of empty or comment lines.  To be
+  # precise, the '// marker so line numbers and indices both start at
+  # 1' line was also causing the issue.
+  def testLinePrecededByEmptyOrCommentLines(self):
+    def DoTest(self, lines):
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData('foo.cc', 'cc', lines, error_collector)
+      # The warning appears only once.
+      self.assertEquals(
+          1,
+          error_collector.Results().count(
+              'Do not use namespace using-directives.  '
+              'Use using-declarations instead.'
+              '  [build/namespaces] [5]'))
+    DoTest(self, ['using namespace foo;'])
+    DoTest(self, ['', '', '', 'using namespace foo;'])
+    DoTest(self, ['// hello', 'using namespace foo;'])
+
+  def testNewlineAtEOF(self):
+    def DoTest(self, data, is_missing_eof):
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData('foo.cc', 'cc', data.split('\n'),
+                              error_collector)
+      # The warning appears only once.
+      self.assertEquals(
+          int(is_missing_eof),
+          error_collector.Results().count(
+              'Could not find a newline character at the end of the file.'
+              '  [whitespace/ending_newline] [5]'))
+
+    DoTest(self, '// Newline\n// at EOF\n', False)
+    DoTest(self, '// No newline\n// at EOF', True)
+
+  def testInvalidUtf8(self):
+    def DoTest(self, raw_bytes, has_invalid_utf8):
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(
+          'foo.cc', 'cc',
+          unicode(raw_bytes, 'utf8', 'replace').split('\n'),
+          error_collector)
+      # The warning appears only once.
+      self.assertEquals(
+          int(has_invalid_utf8),
+          error_collector.Results().count(
+              'Line contains invalid UTF-8'
+              ' (or Unicode replacement character).'
+              '  [readability/utf8] [5]'))
+
+    DoTest(self, 'Hello world\n', False)
+    DoTest(self, '\xe9\x8e\xbd\n', False)
+    DoTest(self, '\xe9x\x8e\xbd\n', True)
+    # This is the encoding of the replacement character itself (which
+    # you can see by evaluating codecs.getencoder('utf8')(u'\ufffd')).
+    DoTest(self, '\xef\xbf\xbd\n', True)
+
+  def testBadCharacters(self):
+    # Test for NUL bytes only
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('nul.cc', 'cc',
+                            ['// Copyright 2014 Your Company.',
+                             '\0', ''], error_collector)
+    self.assertEquals(
+        error_collector.Results(),
+        'Line contains NUL byte.  [readability/nul] [5]')
+
+    # Make sure both NUL bytes and UTF-8 are caught if they appear on
+    # the same line.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'nul_utf8.cc', 'cc',
+        ['// Copyright 2014 Your Company.',
+         unicode('\xe9x\0', 'utf8', 'replace'), ''],
+        error_collector)
+    self.assertEquals(
+        error_collector.Results(),
+        ['Line contains invalid UTF-8 (or Unicode replacement character).'
+         '  [readability/utf8] [5]',
+         'Line contains NUL byte.  [readability/nul] [5]'])
+
+  def testIsBlankLine(self):
+    self.assert_(cpplint.IsBlankLine(''))
+    self.assert_(cpplint.IsBlankLine(' '))
+    self.assert_(cpplint.IsBlankLine(' \t\r\n'))
+    self.assert_(not cpplint.IsBlankLine('int a;'))
+    self.assert_(not cpplint.IsBlankLine('{'))
+
+  def testBlankLinesCheck(self):
+    self.TestBlankLinesCheck(['{\n', '\n', '\n', '}\n'], 1, 1)
+    self.TestBlankLinesCheck(['  if (foo) {\n', '\n', '  }\n'], 1, 1)
+    self.TestBlankLinesCheck(
+        ['\n', '// {\n', '\n', '\n', '// Comment\n', '{\n', '}\n'], 0, 0)
+    self.TestBlankLinesCheck(['\n', 'run("{");\n', '\n'], 0, 0)
+    self.TestBlankLinesCheck(['\n', '  if (foo) { return 0; }\n', '\n'], 0, 0)
+    self.TestBlankLinesCheck(
+        ['int x(\n', '    int a) {\n', '\n', 'return 0;\n', '}'], 0, 0)
+    self.TestBlankLinesCheck(
+        ['int x(\n', '    int a) const {\n', '\n', 'return 0;\n', '}'], 0, 0)
+    self.TestBlankLinesCheck(
+        ['int x(\n', '     int a) {\n', '\n', 'return 0;\n', '}'], 1, 0)
+    self.TestBlankLinesCheck(
+        ['int x(\n', '   int a) {\n', '\n', 'return 0;\n', '}'], 1, 0)
+
+  def testAllowBlankLineBeforeClosingNamespace(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['namespace {',
+                             '',
+                             '}  // namespace',
+                             'namespace another_namespace {',
+                             '',
+                             '}',
+                             'namespace {',
+                             '',
+                             'template<class T, ',
+                             '         class A = hoge<T>, ',
+                             '         class B = piyo<T>, ',
+                             '         class C = fuga<T> >',
+                             'class D {',
+                             ' public:',
+                             '};',
+                             '', '', '', '',
+                             '}'],
+                            error_collector)
+    self.assertEquals(0, error_collector.Results().count(
+        'Redundant blank line at the end of a code block should be deleted.'
+        '  [whitespace/blank_line] [3]'))
+
+  def testAllowBlankLineBeforeIfElseChain(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['if (hoge) {',
+                             '',  # No warning
+                             '} else if (piyo) {',
+                             '',  # No warning
+                             '} else if (piyopiyo) {',
+                             '  hoge = true;',  # No warning
+                             '} else {',
+                             '',  # Warning on this line
+                             '}'],
+                            error_collector)
+    self.assertEquals(1, error_collector.Results().count(
+        'Redundant blank line at the end of a code block should be deleted.'
+        '  [whitespace/blank_line] [3]'))
+
+  def testAllowBlankLineAfterExtern(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['extern "C" {',
+                             '',
+                             'EXPORTAPI void APICALL Some_function() {}',
+                             '',
+                             '}'],
+                            error_collector)
+    self.assertEquals(0, error_collector.Results().count(
+        'Redundant blank line at the start of a code block should be deleted.'
+        '  [whitespace/blank_line] [2]'))
+    self.assertEquals(0, error_collector.Results().count(
+        'Redundant blank line at the end of a code block should be deleted.'
+        '  [whitespace/blank_line] [3]'))
+
+  def testBlankLineBeforeSectionKeyword(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['class A {',
+                             ' public:',
+                             ' protected:',   # warning 1
+                             ' private:',     # warning 2
+                             '  struct B {',
+                             '   public:',
+                             '   private:'] +  # warning 3
+                            ([''] * 100) +  # Make A and B longer than 100 lines
+                            ['  };',
+                             '  struct C {',
+                             '   protected:',
+                             '   private:',  # C is too short for warnings
+                             '  };',
+                             '};',
+                             'class D',
+                             '    : public {',
+                             ' public:',  # no warning
+                             '};',
+                             'class E {\\',
+                             ' public:\\'] +
+                            (['\\'] * 100) +  # Makes E > 100 lines
+                            ['  int non_empty_line;\\',
+                             ' private:\\',   # no warning
+                             '  int a;\\',
+                             '};'],
+                            error_collector)
+    self.assertEquals(2, error_collector.Results().count(
+        '"private:" should be preceded by a blank line'
+        '  [whitespace/blank_line] [3]'))
+    self.assertEquals(1, error_collector.Results().count(
+        '"protected:" should be preceded by a blank line'
+        '  [whitespace/blank_line] [3]'))
+
+  def testNoBlankLineAfterSectionKeyword(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['class A {',
+                             ' public:',
+                             '',  # warning 1
+                             ' private:',
+                             '',  # warning 2
+                             '  struct B {',
+                             '   protected:',
+                             '',  # warning 3
+                             '  };',
+                             '};'],
+                            error_collector)
+    self.assertEquals(1, error_collector.Results().count(
+        'Do not leave a blank line after "public:"'
+        '  [whitespace/blank_line] [3]'))
+    self.assertEquals(1, error_collector.Results().count(
+        'Do not leave a blank line after "protected:"'
+        '  [whitespace/blank_line] [3]'))
+    self.assertEquals(1, error_collector.Results().count(
+        'Do not leave a blank line after "private:"'
+        '  [whitespace/blank_line] [3]'))
+
+  def testAllowBlankLinesInRawStrings(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['// Copyright 2014 Your Company.',
+                             'static const char *kData[] = {R"(',
+                             '',
+                             ')", R"(',
+                             '',
+                             ')"};',
+                             ''],
+                            error_collector)
+    self.assertEquals('', error_collector.Results())
+
+  def testElseOnSameLineAsClosingBraces(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['if (hoge) {',
+                             '}',
+                             'else if (piyo) {',  # Warning on this line
+                             '}',
+                             ' else {'  # Warning on this line
+                             '',
+                             '}'],
+                            error_collector)
+    self.assertEquals(2, error_collector.Results().count(
+        'An else should appear on the same line as the preceding }'
+        '  [whitespace/newline] [4]'))
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['if (hoge) {',
+                             '',
+                             '}',
+                             'else',  # Warning on this line
+                             '{',
+                             '',
+                             '}'],
+                            error_collector)
+    self.assertEquals(1, error_collector.Results().count(
+        'An else should appear on the same line as the preceding }'
+        '  [whitespace/newline] [4]'))
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['if (hoge) {',
+                             '',
+                             '}',
+                             'else_function();'],
+                            error_collector)
+    self.assertEquals(0, error_collector.Results().count(
+        'An else should appear on the same line as the preceding }'
+        '  [whitespace/newline] [4]'))
+
+  def testMultipleStatementsOnSameLine(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['for (int i = 0; i < 1; i++) {}',
+                             'switch (x) {',
+                             '  case 0: func(); break; ',
+                             '}',
+                             'sum += MathUtil::SafeIntRound(x); x += 0.1;'],
+                            error_collector)
+    self.assertEquals(0, error_collector.Results().count(
+        'More than one command on the same line  [whitespace/newline] [0]'))
+
+    old_verbose_level = cpplint._cpplint_state.verbose_level
+    cpplint._cpplint_state.verbose_level = 0
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['sum += MathUtil::SafeIntRound(x); x += 0.1;'],
+                            error_collector)
+    cpplint._cpplint_state.verbose_level = old_verbose_level
+
+  def testEndOfNamespaceComments(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('foo.cc', 'cc',
+                            ['namespace {',
+                             '',
+                             '}',  # No warning (too short)
+                             'namespace expected {',
+                             '}  // namespace mismatched',  # Warning here
+                             'namespace {',
+                             '}  // namespace mismatched',  # Warning here
+                             'namespace outer { namespace nested {'] +
+                            ([''] * 10) +
+                            ['}',  # Warning here
+                             '}',  # Warning here
+                             'namespace {'] +
+                            ([''] * 10) +
+                            ['}',  # Warning here
+                             'namespace {'] +
+                            ([''] * 10) +
+                            ['}  // namespace some description',  # Anon warning
+                             'namespace {'] +
+                            ([''] * 10) +
+                            ['}  // namespace anonymous',  # Variant warning
+                             'namespace {'] +
+                            ([''] * 10) +
+                            ['}  // anonymous namespace (utils)',  # Variant
+                             'namespace {'] +
+                            ([''] * 10) +
+                            ['}  // anonymous namespace',  # No warning
+                             'namespace missing_comment {'] +
+                            ([''] * 10) +
+                            ['}',  # Warning here
+                             'namespace no_warning {'] +
+                            ([''] * 10) +
+                            ['}  // namespace no_warning',
+                             'namespace no_warning {'] +
+                            ([''] * 10) +
+                            ['};  // end namespace no_warning',
+                             '#define MACRO \\',
+                             'namespace c_style { \\'] +
+                            (['\\'] * 10) +
+                            ['}  /* namespace c_style. */ \\',
+                             ';'],
+                            error_collector)
+    self.assertEquals(1, error_collector.Results().count(
+        'Namespace should be terminated with "// namespace expected"'
+        '  [readability/namespace] [5]'))
+    self.assertEquals(1, error_collector.Results().count(
+        'Namespace should be terminated with "// namespace outer"'
+        '  [readability/namespace] [5]'))
+    self.assertEquals(1, error_collector.Results().count(
+        'Namespace should be terminated with "// namespace nested"'
+        '  [readability/namespace] [5]'))
+    self.assertEquals(3, error_collector.Results().count(
+        'Anonymous namespace should be terminated with "// namespace"'
+        '  [readability/namespace] [5]'))
+    self.assertEquals(2, error_collector.Results().count(
+        'Anonymous namespace should be terminated with "// namespace" or'
+        ' "// anonymous namespace"'
+        '  [readability/namespace] [5]'))
+    self.assertEquals(1, error_collector.Results().count(
+        'Namespace should be terminated with "// namespace missing_comment"'
+        '  [readability/namespace] [5]'))
+    self.assertEquals(0, error_collector.Results().count(
+        'Namespace should be terminated with "// namespace no_warning"'
+        '  [readability/namespace] [5]'))
+
+  def testElseClauseNotOnSameLineAsElse(self):
+    self.TestLint('  else DoSomethingElse();',
+                  'Else clause should never be on same line as else '
+                  '(use 2 lines)  [whitespace/newline] [4]')
+    self.TestLint('  else ifDoSomethingElse();',
+                  'Else clause should never be on same line as else '
+                  '(use 2 lines)  [whitespace/newline] [4]')
+    self.TestLint('  } else if (blah) {', '')
+    self.TestLint('  variable_ends_in_else = true;', '')
+
+  def testComma(self):
+    self.TestLint('a = f(1,2);',
+                  'Missing space after ,  [whitespace/comma] [3]')
+    self.TestLint('int tmp=a,a=b,b=tmp;',
+                  ['Missing spaces around =  [whitespace/operators] [4]',
+                   'Missing space after ,  [whitespace/comma] [3]'])
+    self.TestLint('f(a, /* name */ b);', '')
+    self.TestLint('f(a, /* name */b);', '')
+    self.TestLint('f(a, /* name */-1);', '')
+    self.TestLint('f(a, /* name */"1");', '')
+    self.TestLint('f(1, /* empty macro arg */, 2)', '')
+    self.TestLint('f(1,, 2)', '')
+    self.TestLint('operator,()', '')
+    self.TestLint('operator,(a,b)',
+                  'Missing space after ,  [whitespace/comma] [3]')
+
+  def testEqualsOperatorSpacing(self):
+    self.TestLint('int tmp= a;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int tmp =a;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int tmp=a;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int tmp= 7;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int tmp =7;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int tmp=7;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int* tmp=*p;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('int* tmp= *p;',
+                  'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestMultiLineLint(
+        TrimExtraIndent('''
+            lookahead_services_=
+              ::strings::Split(FLAGS_ls, ",", ::strings::SkipEmpty());'''),
+        'Missing spaces around =  [whitespace/operators] [4]')
+    self.TestLint('bool result = a>=42;',
+                  'Missing spaces around >=  [whitespace/operators] [3]')
+    self.TestLint('bool result = a<=42;',
+                  'Missing spaces around <=  [whitespace/operators] [3]')
+    self.TestLint('bool result = a==42;',
+                  'Missing spaces around ==  [whitespace/operators] [3]')
+    self.TestLint('auto result = a!=42;',
+                  'Missing spaces around !=  [whitespace/operators] [3]')
+    self.TestLint('int a = b!=c;',
+                  'Missing spaces around !=  [whitespace/operators] [3]')
+    self.TestLint('a&=42;', '')
+    self.TestLint('a|=42;', '')
+    self.TestLint('a^=42;', '')
+    self.TestLint('a+=42;', '')
+    self.TestLint('a*=42;', '')
+    self.TestLint('a/=42;', '')
+    self.TestLint('a%=42;', '')
+    self.TestLint('a>>=5;', '')
+    self.TestLint('a<<=5;', '')
+
+  def testShiftOperatorSpacing(self):
+    self.TestLint('a<<b',
+                  'Missing spaces around <<  [whitespace/operators] [3]')
+    self.TestLint('a>>b',
+                  'Missing spaces around >>  [whitespace/operators] [3]')
+    self.TestLint('1<<20', '')
+    self.TestLint('1024>>10', '')
+    self.TestLint('Kernel<<<1, 2>>>()', '')
+
+  def testIndent(self):
+    self.TestLint('static int noindent;', '')
+    self.TestLint('  int two_space_indent;', '')
+    self.TestLint('    int four_space_indent;', '')
+    self.TestLint(' int one_space_indent;',
+                  'Weird number of spaces at line-start.  '
+                  'Are you using a 2-space indent?  [whitespace/indent] [3]')
+    self.TestLint('   int three_space_indent;',
+                  'Weird number of spaces at line-start.  '
+                  'Are you using a 2-space indent?  [whitespace/indent] [3]')
+    self.TestLint(' char* one_space_indent = "public:";',
+                  'Weird number of spaces at line-start.  '
+                  'Are you using a 2-space indent?  [whitespace/indent] [3]')
+    self.TestLint(' public:', '')
+    self.TestLint('  protected:', '')
+    self.TestLint('   private:', '')
+    self.TestLint(' protected: \\', '')
+    self.TestLint('  public:      \\', '')
+    self.TestLint('   private:   \\', '')
+    self.TestMultiLineLint(
+        TrimExtraIndent("""
+            class foo {
+             public slots:
+              void bar();
+            };"""),
+        'Weird number of spaces at line-start.  '
+        'Are you using a 2-space indent?  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        TrimExtraIndent('''
+            static const char kRawString[] = R"("
+             ")";'''),
+        '')
+    self.TestMultiLineLint(
+        TrimExtraIndent('''
+            static const char kNotRawString[] = "("
+             ")";'''),
+        'Weird number of spaces at line-start.  '
+        'Are you using a 2-space indent?  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        ' static const char kSingleLineRawString[] = R"(...)";',
+        'Weird number of spaces at line-start.  '
+        'Are you using a 2-space indent?  [whitespace/indent] [3]')
+
+  def testSectionIndent(self):
+    self.TestMultiLineLint(
+        """
+        class A {
+         public:  // no warning
+          private:  // warning here
+        };""",
+        'private: should be indented +1 space inside class A'
+        '  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        """
+        class B {
+         public:  // no warning
+          template<> struct C {
+            public:    // warning here
+           protected:  // no warning
+          };
+        };""",
+        'public: should be indented +1 space inside struct C'
+        '  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        """
+        struct D {
+         };""",
+        'Closing brace should be aligned with beginning of struct D'
+        '  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        """
+         template<typename E> class F {
+        };""",
+        'Closing brace should be aligned with beginning of class F'
+        '  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        """
+        class G {
+          Q_OBJECT
+        public slots:
+        signals:
+        };""",
+        ['public slots: should be indented +1 space inside class G'
+         '  [whitespace/indent] [3]',
+         'signals: should be indented +1 space inside class G'
+         '  [whitespace/indent] [3]'])
+    self.TestMultiLineLint(
+        """
+        class H {
+          /* comments */ class I {
+           public:  // no warning
+            private:  // warning here
+          };
+        };""",
+        'private: should be indented +1 space inside class I'
+        '  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        """
+        class J
+            : public ::K {
+         public:  // no warning
+          protected:  // warning here
+        };""",
+        'protected: should be indented +1 space inside class J'
+        '  [whitespace/indent] [3]')
+    self.TestMultiLineLint(
+        """
+        class L
+            : public M,
+              public ::N {
+        };""",
+        '')
+    self.TestMultiLineLint(
+        """
+        template <class O,
+                  class P,
+                  class Q,
+                  typename R>
+        static void Func() {
+        }""",
+        '')
+
+  def testConditionals(self):
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          goto fail;
+          goto fail;""",
+        'If/else bodies with multiple statements require braces'
+        '  [readability/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          goto fail; goto fail;""",
+        'If/else bodies with multiple statements require braces'
+        '  [readability/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          foo;
+        else
+          goto fail;
+          goto fail;""",
+        'If/else bodies with multiple statements require braces'
+        '  [readability/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo) goto fail;
+          goto fail;""",
+        'If/else bodies with multiple statements require braces'
+        '  [readability/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          if (bar)
+            baz;
+          else
+            qux;""",
+        'Else clause should be indented at the same level as if. Ambiguous'
+        ' nested if/else chains require braces.  [readability/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          if (bar)
+            baz;
+        else
+          qux;""",
+        'Else clause should be indented at the same level as if. Ambiguous'
+        ' nested if/else chains require braces.  [readability/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo) {
+          bar;
+          baz;
+        } else
+          qux;""",
+        'If an else has a brace on one side, it should have it on both'
+        '  [readability/braces] [5]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          bar;
+        else {
+          baz;
+        }""",
+        'If an else has a brace on one side, it should have it on both'
+        '  [readability/braces] [5]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          bar;
+        else if (baz) {
+          qux;
+        }""",
+        'If an else has a brace on one side, it should have it on both'
+        '  [readability/braces] [5]')
+    self.TestMultiLineLint(
+        """
+        if (foo) {
+          bar;
+        } else if (baz)
+          qux;""",
+        'If an else has a brace on one side, it should have it on both'
+        '  [readability/braces] [5]')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          goto fail;
+        bar;""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo
+            && bar) {
+          baz;
+          qux;
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          goto
+            fail;""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          bar;
+        else
+          baz;
+        qux;""",
+        '')
+    self.TestMultiLineLint(
+        """
+        for (;;) {
+          if (foo)
+            bar;
+          else
+            baz;
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          bar;
+        else if (baz)
+          baz;""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo)
+          bar;
+        else
+          baz;""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo) {
+          bar;
+        } else {
+          baz;
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        if (foo) {
+          bar;
+        } else if (baz) {
+          qux;
+        }""",
+        '')
+    # Note: this is an error for a different reason, but should not trigger the
+    # single-line if error.
+    self.TestMultiLineLint(
+        """
+        if (foo)
+        {
+          bar;
+          baz;
+        }""",
+        '{ should almost always be at the end of the previous line'
+        '  [whitespace/braces] [4]')
+    self.TestMultiLineLint(
+        """
+        if (foo) { \\
+          bar; \\
+          baz; \\
+        }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        void foo() { if (bar) baz; }""",
+        '')
+    self.TestMultiLineLint(
+        """
+        #if foo
+          bar;
+        #else
+          baz;
+          qux;
+        #endif""",
+        '')
+    self.TestMultiLineLint(
+        """void F() {
+          variable = [] { if (true); };
+          variable =
+              [] { if (true); };
+          Call(
+              [] { if (true); },
+              [] { if (true); });
+        }""",
+        '')
+
+  def testTab(self):
+    self.TestLint('\tint a;',
+                  'Tab found; better to use spaces  [whitespace/tab] [1]')
+    self.TestLint('int a = 5;\t\t// set a to 5',
+                  'Tab found; better to use spaces  [whitespace/tab] [1]')
+
+  def testParseArguments(self):
+    old_usage = cpplint._USAGE
+    old_error_categories = cpplint._ERROR_CATEGORIES
+    old_output_format = cpplint._cpplint_state.output_format
+    old_verbose_level = cpplint._cpplint_state.verbose_level
+    old_filters = cpplint._cpplint_state.filters
+    old_line_length = cpplint._line_length
+    old_valid_extensions = cpplint._valid_extensions
+    try:
+      # Don't print usage during the tests, or filter categories
+      cpplint._USAGE = ''
+      cpplint._ERROR_CATEGORIES = ''
+
+      self.assertRaises(SystemExit, cpplint.ParseArguments, [])
+      self.assertRaises(SystemExit, cpplint.ParseArguments, ['--badopt'])
+      self.assertRaises(SystemExit, cpplint.ParseArguments, ['--help'])
+      self.assertRaises(SystemExit, cpplint.ParseArguments, ['--v=0'])
+      self.assertRaises(SystemExit, cpplint.ParseArguments, ['--filter='])
+      # This is illegal because all filters must start with + or -
+      self.assertRaises(SystemExit, cpplint.ParseArguments, ['--filter=foo'])
+      self.assertRaises(SystemExit, cpplint.ParseArguments,
+                        ['--filter=+a,b,-c'])
+
+      self.assertEquals(['foo.cc'], cpplint.ParseArguments(['foo.cc']))
+      self.assertEquals(old_output_format, cpplint._cpplint_state.output_format)
+      self.assertEquals(old_verbose_level, cpplint._cpplint_state.verbose_level)
+
+      self.assertEquals(['foo.cc'],
+                        cpplint.ParseArguments(['--v=1', 'foo.cc']))
+      self.assertEquals(1, cpplint._cpplint_state.verbose_level)
+      self.assertEquals(['foo.h'],
+                        cpplint.ParseArguments(['--v=3', 'foo.h']))
+      self.assertEquals(3, cpplint._cpplint_state.verbose_level)
+      self.assertEquals(['foo.cpp'],
+                        cpplint.ParseArguments(['--verbose=5', 'foo.cpp']))
+      self.assertEquals(5, cpplint._cpplint_state.verbose_level)
+      self.assertRaises(ValueError,
+                        cpplint.ParseArguments, ['--v=f', 'foo.cc'])
+
+      self.assertEquals(['foo.cc'],
+                        cpplint.ParseArguments(['--output=emacs', 'foo.cc']))
+      self.assertEquals('emacs', cpplint._cpplint_state.output_format)
+      self.assertEquals(['foo.h'],
+                        cpplint.ParseArguments(['--output=vs7', 'foo.h']))
+      self.assertEquals('vs7', cpplint._cpplint_state.output_format)
+      self.assertRaises(SystemExit,
+                        cpplint.ParseArguments, ['--output=blah', 'foo.cc'])
+
+      filt = '-,+whitespace,-whitespace/indent'
+      self.assertEquals(['foo.h'],
+                        cpplint.ParseArguments(['--filter='+filt, 'foo.h']))
+      self.assertEquals(['-', '+whitespace', '-whitespace/indent'],
+                        cpplint._cpplint_state.filters)
+
+      self.assertEquals(['foo.cc', 'foo.h'],
+                        cpplint.ParseArguments(['foo.cc', 'foo.h']))
+
+      self.assertEqual(['foo.h'],
+                       cpplint.ParseArguments(['--linelength=120', 'foo.h']))
+      self.assertEqual(120, cpplint._line_length)
+
+      self.assertEqual(['foo.h'],
+                       cpplint.ParseArguments(['--extensions=hpp,cpp,cpp', 'foo.h']))
+      self.assertEqual(set(['hpp', 'cpp']), cpplint._valid_extensions)
+    finally:
+      cpplint._USAGE = old_usage
+      cpplint._ERROR_CATEGORIES = old_error_categories
+      cpplint._cpplint_state.output_format = old_output_format
+      cpplint._cpplint_state.verbose_level = old_verbose_level
+      cpplint._cpplint_state.filters = old_filters
+      cpplint._line_length = old_line_length
+      cpplint._valid_extensions = old_valid_extensions
+
+  def testLineLength(self):
+    old_line_length = cpplint._line_length
+    try:
+      cpplint._line_length = 80
+      self.TestLint(
+          '// %s' % ('H' * 77),
+          '')
+      self.TestLint(
+          '// %s' % ('H' * 78),
+          'Lines should be <= 80 characters long'
+          '  [whitespace/line_length] [2]')
+      cpplint._line_length = 120
+      self.TestLint(
+          '// %s' % ('H' * 117),
+          '')
+      self.TestLint(
+          '// %s' % ('H' * 118),
+          'Lines should be <= 120 characters long'
+          '  [whitespace/line_length] [2]')
+    finally:
+      cpplint._line_length = old_line_length
+
+  def testFilter(self):
+    old_filters = cpplint._cpplint_state.filters
+    try:
+      cpplint._cpplint_state.SetFilters('-,+whitespace,-whitespace/indent')
+      self.TestLint(
+          '// Hello there ',
+          'Line ends in whitespace.  Consider deleting these extra spaces.'
+          '  [whitespace/end_of_line] [4]')
+      self.TestLint('int a = (int)1.0;', '')
+      self.TestLint(' weird opening space', '')
+    finally:
+      cpplint._cpplint_state.filters = old_filters
+
+  def testDefaultFilter(self):
+    default_filters = cpplint._DEFAULT_FILTERS
+    old_filters = cpplint._cpplint_state.filters
+    cpplint._DEFAULT_FILTERS = ['-whitespace']
+    try:
+      # Reset filters
+      cpplint._cpplint_state.SetFilters('')
+      self.TestLint('// Hello there ', '')
+      cpplint._cpplint_state.SetFilters('+whitespace/end_of_line')
+      self.TestLint(
+          '// Hello there ',
+          'Line ends in whitespace.  Consider deleting these extra spaces.'
+          '  [whitespace/end_of_line] [4]')
+      self.TestLint(' weird opening space', '')
+    finally:
+      cpplint._cpplint_state.filters = old_filters
+      cpplint._DEFAULT_FILTERS = default_filters
+
+  def testDuplicateHeader(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData('path/self.cc', 'cc',
+                            ['// Copyright 2014 Your Company. All Rights Reserved.',
+                             '#include "path/self.h"',
+                             '#include "path/duplicate.h"',
+                             '#include "path/duplicate.h"',
+                             '#ifdef MACRO',
+                             '#include "path/unique.h"',
+                             '#else',
+                             '#include "path/unique.h"',
+                             '#endif',
+                             ''],
+                            error_collector)
+    self.assertEquals(
+        ['"path/duplicate.h" already included at path/self.cc:3  '
+         '[build/include] [4]'],
+        error_collector.ResultList())
+
+  def testUnnamedNamespacesInHeaders(self):
+    self.TestLanguageRulesCheck(
+        'foo.h', 'namespace {',
+        'Do not use unnamed namespaces in header files.  See'
+        ' http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+        ' for more information.  [build/namespaces] [4]')
+    # namespace registration macros are OK.
+    self.TestLanguageRulesCheck('foo.h', 'namespace {  \\', '')
+    # named namespaces are OK.
+    self.TestLanguageRulesCheck('foo.h', 'namespace foo {', '')
+    self.TestLanguageRulesCheck('foo.h', 'namespace foonamespace {', '')
+    self.TestLanguageRulesCheck('foo.cc', 'namespace {', '')
+    self.TestLanguageRulesCheck('foo.cc', 'namespace foo {', '')
+
+  def testBuildClass(self):
+    # Test that the linter can parse to the end of class definitions,
+    # and that it will report when it can't.
+    # Use multi-line linter because it performs the ClassState check.
+    self.TestMultiLineLint(
+        'class Foo {',
+        'Failed to find complete declaration of class Foo'
+        '  [build/class] [5]')
+    # Do the same for namespaces
+    self.TestMultiLineLint(
+        'namespace Foo {',
+        'Failed to find complete declaration of namespace Foo'
+        '  [build/namespaces] [5]')
+    # Don't warn on forward declarations of various types.
+    self.TestMultiLineLint(
+        'class Foo;',
+        '')
+    self.TestMultiLineLint(
+        """struct Foo*
+             foo = NewFoo();""",
+        '')
+    # Test preprocessor.
+    self.TestMultiLineLint(
+        """#ifdef DERIVE_FROM_GOO
+          struct Foo : public Goo {
+        #else
+          struct Foo : public Hoo {
+        #endif
+          };""",
+        '')
+    self.TestMultiLineLint(
+        """
+        class Foo
+        #ifdef DERIVE_FROM_GOO
+          : public Goo {
+        #else
+          : public Hoo {
+        #endif
+        };""",
+        '')
+    # Test incomplete class
+    self.TestMultiLineLint(
+        'class Foo {',
+        'Failed to find complete declaration of class Foo'
+        '  [build/class] [5]')
+
+  def testBuildEndComment(self):
+    # The crosstool compiler we currently use will fail to compile the
+    # code in this test, so we might consider removing the lint check.
+    self.TestMultiLineLint(
+        """#if 0
+        #endif Not a comment""",
+        'Uncommented text after #endif is non-standard.  Use a comment.'
+        '  [build/endif_comment] [5]')
+
+  def testBuildForwardDecl(self):
+    # The crosstool compiler we currently use will fail to compile the
+    # code in this test, so we might consider removing the lint check.
+    self.TestLint('class Foo::Goo;',
+                  'Inner-style forward declarations are invalid.'
+                  '  Remove this line.'
+                  '  [build/forward_decl] [5]')
+
+  def GetBuildHeaderGuardPreprocessorSymbol(self, file_path):
+    # Figure out the expected header guard by processing an empty file.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h', [], error_collector)
+    for error in error_collector.ResultList():
+      matched = re.search(
+          'No #ifndef header guard found, suggested CPP variable is: ([A-Z_]+)',
+          error)
+      if matched is not None:
+        return matched.group(1)
+
+  def testBuildHeaderGuard(self):
+    file_path = 'mydir/foo.h'
+    expected_guard = self.GetBuildHeaderGuardPreprocessorSymbol(file_path)
+    self.assertTrue(re.search('MYDIR_FOO_H_$', expected_guard))
+
+    # No guard at all: expect one error.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h', [], error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            'No #ifndef header guard found, suggested CPP variable is: %s'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # No header guard, but the error is suppressed.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['// Copyright 2014 Your Company.',
+                             '// NOLINT(build/header_guard)', ''],
+                            error_collector)
+    self.assertEquals([], error_collector.ResultList())
+
+    # Wrong guard
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef FOO_H', '#define FOO_H'], error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            '#ifndef header guard has wrong style, please use: %s'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # No define
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s' % expected_guard], error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            'No #ifndef header guard found, suggested CPP variable is: %s'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # Mismatched define
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s' % expected_guard,
+                             '#define FOO_H'],
+                            error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            'No #ifndef header guard found, suggested CPP variable is: %s'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # No endif
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s' % expected_guard,
+                             '#define %s' % expected_guard,
+                             ''],
+                            error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            '#endif line should be "#endif  // %s"'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # Commentless endif
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s' % expected_guard,
+                             '#define %s' % expected_guard,
+                             '#endif'],
+                            error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            '#endif line should be "#endif  // %s"'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # Commentless endif for old-style guard
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s_' % expected_guard,
+                             '#define %s_' % expected_guard,
+                             '#endif'],
+                            error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            '#endif line should be "#endif  // %s"'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # No header guard errors
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s' % expected_guard,
+                             '#define %s' % expected_guard,
+                             '#endif  // %s' % expected_guard],
+                            error_collector)
+    for line in error_collector.ResultList():
+      if line.find('build/header_guard') != -1:
+        self.fail('Unexpected error: %s' % line)
+
+    # No header guard errors for old-style guard
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef %s_' % expected_guard,
+                             '#define %s_' % expected_guard,
+                             '#endif  // %s_' % expected_guard],
+                            error_collector)
+    for line in error_collector.ResultList():
+      if line.find('build/header_guard') != -1:
+        self.fail('Unexpected error: %s' % line)
+
+    old_verbose_level = cpplint._cpplint_state.verbose_level
+    try:
+      cpplint._cpplint_state.verbose_level = 0
+      # Warn on old-style guard if verbosity is 0.
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(file_path, 'h',
+                              ['#ifndef %s_' % expected_guard,
+                               '#define %s_' % expected_guard,
+                               '#endif  // %s_' % expected_guard],
+                              error_collector)
+      self.assertEquals(
+          1,
+          error_collector.ResultList().count(
+              '#ifndef header guard has wrong style, please use: %s'
+              '  [build/header_guard] [0]' % expected_guard),
+          error_collector.ResultList())
+    finally:
+      cpplint._cpplint_state.verbose_level = old_verbose_level
+
+    # Completely incorrect header guard
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef FOO',
+                             '#define FOO',
+                             '#endif  // FOO'],
+                            error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            '#ifndef header guard has wrong style, please use: %s'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(
+            '#endif line should be "#endif  // %s"'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # incorrect header guard with nolint
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'h',
+                            ['#ifndef FOO  // NOLINT',
+                             '#define FOO',
+                             '#endif  // FOO NOLINT'],
+                            error_collector)
+    self.assertEquals(
+        0,
+        error_collector.ResultList().count(
+            '#ifndef header guard has wrong style, please use: %s'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+    self.assertEquals(
+        0,
+        error_collector.ResultList().count(
+            '#endif line should be "#endif  // %s"'
+            '  [build/header_guard] [5]' % expected_guard),
+        error_collector.ResultList())
+
+    # Special case for flymake
+    for test_file in ['mydir/foo_flymake.h', 'mydir/.flymake/foo.h']:
+      error_collector = ErrorCollector(self.assert_)
+      cpplint.ProcessFileData(test_file, 'h',
+                              ['// Copyright 2014 Your Company.', ''],
+                              error_collector)
+      self.assertEquals(
+          1,
+          error_collector.ResultList().count(
+              'No #ifndef header guard found, suggested CPP variable is: %s'
+              '  [build/header_guard] [5]' % expected_guard),
+          error_collector.ResultList())
+
+  def testBuildHeaderGuardWithRoot(self):
+    file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
+                             'cpplint_test_header.h')
+    file_info = cpplint.FileInfo(file_path)
+    if file_info.FullName() == file_info.RepositoryName():
+      # When FileInfo cannot deduce the root directory of the repository,
+      # FileInfo.RepositoryName returns the same value as FileInfo.FullName.
+      # This can happen when this source file was obtained without .svn or
+      # .git directory. (e.g. using 'svn export' or 'git archive').
+      # Skip this test in such a case because --root flag makes sense only
+      # when the root directory of the repository is properly deduced.
+      return
+
+    self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_',
+                      cpplint.GetHeaderGuardCPPVariable(file_path))
+    cpplint._root = 'cpplint'
+    self.assertEquals('CPPLINT_TEST_HEADER_H_',
+                      cpplint.GetHeaderGuardCPPVariable(file_path))
+    # --root flag is ignored if an non-existent directory is specified.
+    cpplint._root = 'NON_EXISTENT_DIR'
+    self.assertEquals('CPPLINT_CPPLINT_TEST_HEADER_H_',
+                      cpplint.GetHeaderGuardCPPVariable(file_path))
+
+  def testBuildInclude(self):
+    # Test that include statements have slashes in them.
+    self.TestLint('#include "foo.h"',
+                  'Include the directory when naming .h files'
+                  '  [build/include] [4]')
+    self.TestLint('#include "Python.h"', '')
+    self.TestLint('#include "lua.h"', '')
+
+  def testBuildPrintfFormat(self):
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        [r'printf("\%%d", value);',
+         r'snprintf(buffer, sizeof(buffer), "\[%d", value);',
+         r'fprintf(file, "\(%d", value);',
+         r'vsnprintf(buffer, sizeof(buffer), "\\\{%d", ap);'],
+        error_collector)
+    self.assertEquals(
+        4,
+        error_collector.Results().count(
+            '%, [, (, and { are undefined character escapes.  Unescape them.'
+            '  [build/printf_format] [3]'))
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        'foo.cc', 'cc',
+        ['// Copyright 2014 Your Company.',
+         r'printf("\\%%%d", value);',
+         r'printf(R"(\[)");',
+         r'printf(R"(\[%s)", R"(\])");',
+         ''],
+        error_collector)
+    self.assertEquals('', error_collector.Results())
+
+  def testRuntimePrintfFormat(self):
+    self.TestLint(
+        r'fprintf(file, "%q", value);',
+        '%q in format strings is deprecated.  Use %ll instead.'
+        '  [runtime/printf_format] [3]')
+
+    self.TestLint(
+        r'aprintf(file, "The number is %12q", value);',
+        '%q in format strings is deprecated.  Use %ll instead.'
+        '  [runtime/printf_format] [3]')
+
+    self.TestLint(
+        r'printf(file, "The number is" "%-12q", value);',
+        '%q in format strings is deprecated.  Use %ll instead.'
+        '  [runtime/printf_format] [3]')
+
+    self.TestLint(
+        r'printf(file, "The number is" "%+12q", value);',
+        '%q in format strings is deprecated.  Use %ll instead.'
+        '  [runtime/printf_format] [3]')
+
+    self.TestLint(
+        r'printf(file, "The number is" "% 12q", value);',
+        '%q in format strings is deprecated.  Use %ll instead.'
+        '  [runtime/printf_format] [3]')
+
+    self.TestLint(
+        r'snprintf(file, "Never mix %d and %1$d parameters!", value);',
+        '%N$ formats are unconventional.  Try rewriting to avoid them.'
+        '  [runtime/printf_format] [2]')
+
+  def TestLintLogCodeOnError(self, code, expected_message):
+    # Special TestLint which logs the input code on error.
+    result = self.PerformSingleLineLint(code)
+    if result != expected_message:
+      self.fail('For code: "%s"\nGot: "%s"\nExpected: "%s"'
+                % (code, result, expected_message))
+
+  def testBuildStorageClass(self):
+    qualifiers = [None, 'const', 'volatile']
+    signs = [None, 'signed', 'unsigned']
+    types = ['void', 'char', 'int', 'float', 'double',
+             'schar', 'int8', 'uint8', 'int16', 'uint16',
+             'int32', 'uint32', 'int64', 'uint64']
+    storage_classes = ['extern', 'register', 'static', 'typedef']
+
+    build_storage_class_error_message = (
+        'Storage class (static, extern, typedef, etc) should be first.'
+        '  [build/storage_class] [5]')
+
+    # Some explicit cases. Legal in C++, deprecated in C99.
+    self.TestLint('const int static foo = 5;',
+                  build_storage_class_error_message)
+
+    self.TestLint('char static foo;',
+                  build_storage_class_error_message)
+
+    self.TestLint('double const static foo = 2.0;',
+                  build_storage_class_error_message)
+
+    self.TestLint('uint64 typedef unsigned_long_long;',
+                  build_storage_class_error_message)
+
+    self.TestLint('int register foo = 0;',
+                  build_storage_class_error_message)
+
+    # Since there are a very large number of possibilities, randomly
+    # construct declarations.
+    # Make sure that the declaration is logged if there's an error.
+    # Seed generator with an integer for absolute reproducibility.
+    random.seed(25)
+    for unused_i in range(10):
+      # Build up random list of non-storage-class declaration specs.
+      other_decl_specs = [random.choice(qualifiers), random.choice(signs),
+                          random.choice(types)]
+      # remove None
+      other_decl_specs = [x for x in other_decl_specs if x is not None]
+
+      # shuffle
+      random.shuffle(other_decl_specs)
+
+      # insert storage class after the first
+      storage_class = random.choice(storage_classes)
+      insertion_point = random.randint(1, len(other_decl_specs))
+      decl_specs = (other_decl_specs[0:insertion_point]
+                    + [storage_class]
+                    + other_decl_specs[insertion_point:])
+
+      self.TestLintLogCodeOnError(
+          ' '.join(decl_specs) + ';',
+          build_storage_class_error_message)
+
+      # but no error if storage class is first
+      self.TestLintLogCodeOnError(
+          storage_class + ' ' + ' '.join(other_decl_specs),
+          '')
+
+  def testLegalCopyright(self):
+    legal_copyright_message = (
+        'No copyright message found.  '
+        'You should have a line: "Copyright [year] <Copyright Owner>"'
+        '  [legal/copyright] [5]')
+
+    copyright_line = '// Copyright 2014 Google Inc. All Rights Reserved.'
+
+    file_path = 'mydir/googleclient/foo.cc'
+
+    # There should be a copyright message in the first 10 lines
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'cc', [], error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(legal_copyright_message))
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        file_path, 'cc',
+        ['' for unused_i in range(10)] + [copyright_line],
+        error_collector)
+    self.assertEquals(
+        1,
+        error_collector.ResultList().count(legal_copyright_message))
+
+    # Test that warning isn't issued if Copyright line appears early enough.
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(file_path, 'cc', [copyright_line], error_collector)
+    for message in error_collector.ResultList():
+      if message.find('legal/copyright') != -1:
+        self.fail('Unexpected error: %s' % message)
+
+    error_collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(
+        file_path, 'cc',
+        ['' for unused_i in range(9)] + [copyright_line],
+        error_collector)
+    for message in error_collector.ResultList():
+      if message.find('legal/copyright') != -1:
+        self.fail('Unexpected error: %s' % message)
+
+  def testInvalidIncrement(self):
+    self.TestLint('*count++;',
+                  'Changing pointer instead of value (or unused value of '
+                  'operator*).  [runtime/invalid_increment] [5]')
+
+  def testSnprintfSize(self):
+    self.TestLint('vsnprintf(NULL, 0, format)', '')
+    self.TestLint('snprintf(fisk, 1, format)',
+                  'If you can, use sizeof(fisk) instead of 1 as the 2nd arg '
+                  'to snprintf.  [runtime/printf] [3]')
+class Cxx11Test(CpplintTestBase):
+
+  def Helper(self, package, extension, lines, count):
+    filename = package + '/foo.' + extension
+    lines = lines[:]
+
+    # Header files need to have an ifdef guard wrapped around their code.
+    if extension == 'h':
+      guard = filename.upper().replace('/', '_').replace('.', '_') + '_'
+      lines.insert(0, '#ifndef ' + guard)
+      lines.insert(1, '#define ' + guard)
+      lines.append('#endif  // ' + guard)
+
+    # All files need a final blank line.
+    lines.append('')
+
+    # Process the file and check resulting error count.
+    collector = ErrorCollector(self.assert_)
+    cpplint.ProcessFileData(filename, extension, lines, collector)
+    error_list = collector.ResultList()
+    self.assertEquals(count, len(error_list), error_list)
+
+  def TestCxx11Feature(self, code, expected_error):
+    lines = code.split('\n')
+    collector = ErrorCollector(self.assert_)
+    cpplint.RemoveMultiLineComments('foo.h', lines, collector)
+    clean_lines = cpplint.CleansedLines(lines)
+    cpplint.FlagCxx11Features('foo.cc', clean_lines, 0, collector)
+    self.assertEquals(expected_error, collector.Results())
+
+  def testBlockedHeaders(self):
+    self.TestCxx11Feature('#include <mutex>',
+                          '<mutex> is an unapproved C++11 header.'
+                          '  [build/c++11] [5]')
+
+  def testBlockedClasses(self):
+    self.TestCxx11Feature('std::alignment_of<T>',
+                          'std::alignment_of is an unapproved '
+                          'C++11 class or function.  Send c-style an example '
+                          'of where it would make your code more readable, '
+                          'and they may let you use it.'
+                          '  [build/c++11] [5]')
+    self.TestCxx11Feature('std::alignment_offer', '')
+    self.TestCxx11Feature('mystd::alignment_of', '')
+    self.TestCxx11Feature('std::binomial_distribution', '')
+
+  def testBlockedFunctions(self):
+    self.TestCxx11Feature('std::alignment_of<int>',
+                          'std::alignment_of is an unapproved '
+                          'C++11 class or function.  Send c-style an example '
+                          'of where it would make your code more readable, '
+                          'and they may let you use it.'
+                          '  [build/c++11] [5]')
+    # Missed because of the lack of "std::".  Compiles because ADL
+    # looks in the namespace of my_shared_ptr, which (presumably) is
+    # std::.  But there will be a lint error somewhere in this file
+    # since my_shared_ptr had to be defined.
+    self.TestCxx11Feature('static_pointer_cast<Base>(my_shared_ptr)', '')
+    self.TestCxx11Feature('std::declval<T>()', '')
+
+  def testExplicitMakePair(self):
+    self.TestLint('make_pair', '')
+    self.TestLint('make_pair(42, 42)', '')
+    self.TestLint('make_pair<',
+                  'For C++11-compatibility, omit template arguments from'
+                  ' make_pair OR use pair directly OR if appropriate,'
+                  ' construct a pair directly'
+                  '  [build/explicit_make_pair] [4]')
+    self.TestLint('make_pair <',
+                  'For C++11-compatibility, omit template arguments from'
+                  ' make_pair OR use pair directly OR if appropriate,'
+                  ' construct a pair directly'
+                  '  [build/explicit_make_pair] [4]')
+    self.TestLint('my_make_pair<int, int>', '')
+
+class CleansedLinesTest(unittest.TestCase):
+
+  def testInit(self):
+    lines = ['Line 1',
+             'Line 2',
+             'Line 3 // Comment test',
+             'Line 4 /* Comment test */',
+             'Line 5 "foo"']
+
+    clean_lines = cpplint.CleansedLines(lines)
+    self.assertEquals(lines, clean_lines.raw_lines)
+    self.assertEquals(5, clean_lines.NumLines())
+
+    self.assertEquals(['Line 1',
+                       'Line 2',
+                       'Line 3',
+                       'Line 4',
+                       'Line 5 "foo"'],
+                      clean_lines.lines)
+
+    self.assertEquals(['Line 1',
+                       'Line 2',
+                       'Line 3',
+                       'Line 4',
+                       'Line 5 ""'],
+                      clean_lines.elided)
+
+  def testInitEmpty(self):
+    clean_lines = cpplint.CleansedLines([])
+    self.assertEquals([], clean_lines.raw_lines)
+    self.assertEquals(0, clean_lines.NumLines())
+
+  def testCollapseStrings(self):
+    collapse = cpplint.CleansedLines._CollapseStrings
+    self.assertEquals('""', collapse('""'))             # ""     (empty)
+    self.assertEquals('"""', collapse('"""'))           # """    (bad)
+    self.assertEquals('""', collapse('"xyz"'))          # "xyz"  (string)
+    self.assertEquals('""', collapse('"\\\""'))         # "\""   (string)
+    self.assertEquals('""', collapse('"\'"'))           # "'"    (string)
+    self.assertEquals('"\"', collapse('"\"'))           # "\"    (bad)
+    self.assertEquals('""', collapse('"\\\\"'))         # "\\"   (string)
+    self.assertEquals('"', collapse('"\\\\\\"'))        # "\\\"  (bad)
+    self.assertEquals('""', collapse('"\\\\\\\\"'))     # "\\\\" (string)
+
+    self.assertEquals('\'\'', collapse('\'\''))         # ''     (empty)
+    self.assertEquals('\'\'', collapse('\'a\''))        # 'a'    (char)
+    self.assertEquals('\'\'', collapse('\'\\\'\''))     # '\''   (char)
+    self.assertEquals('\'', collapse('\'\\\''))         # '\'    (bad)
+    self.assertEquals('', collapse('\\012'))            # '\012' (char)
+    self.assertEquals('', collapse('\\xfF0'))           # '\xfF0' (char)
+    self.assertEquals('', collapse('\\n'))              # '\n' (char)
+    self.assertEquals(r'\#', collapse('\\#'))           # '\#' (bad)
+
+    self.assertEquals('"" + ""', collapse('"\'" + "\'"'))
+    self.assertEquals("'', ''", collapse("'\"', '\"'"))
+    self.assertEquals('""[0b10]', collapse('"a\'b"[0b1\'0]'))
+
+    self.assertEquals('42', collapse("4'2"))
+    self.assertEquals('0b0101', collapse("0b0'1'0'1"))
+    self.assertEquals('1048576', collapse("1'048'576"))
+    self.assertEquals('0X100000', collapse("0X10'0000"))
+    self.assertEquals('0004000000', collapse("0'004'000'000"))
+    self.assertEquals('1.602176565e-19', collapse("1.602'176'565e-19"))
+    self.assertEquals('\'\' + 0xffff', collapse("'i' + 0xf'f'f'f"))
+    self.assertEquals('sizeof\'\' == 1', collapse("sizeof'x' == 1"))
+    self.assertEquals('0x.03p100', collapse('0x.0\'3p1\'0\'0'))
+    self.assertEquals('123.45', collapse('1\'23.4\'5'))
+
+    self.assertEquals('StringReplace(body, "", "");',
+                      collapse('StringReplace(body, "\\\\", "\\\\\\\\");'))
+    self.assertEquals('\'\' ""',
+                      collapse('\'"\' "foo"'))
+
+
+class OrderOfIncludesTest(CpplintTestBase):
+
+  def setUp(self):
+    CpplintTestBase.setUp(self)
+    self.include_state = cpplint._IncludeState()
+    os.path.abspath = lambda value: value
+
+  def testCheckNextIncludeOrder_OtherThenCpp(self):
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._OTHER_HEADER))
+    self.assertEqual('Found C++ system header after other header',
+                     self.include_state.CheckNextIncludeOrder(
+                         cpplint._CPP_SYS_HEADER))
+
+  def testCheckNextIncludeOrder_CppThenC(self):
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._CPP_SYS_HEADER))
+    self.assertEqual('Found C system header after C++ system header',
+                     self.include_state.CheckNextIncludeOrder(
+                         cpplint._C_SYS_HEADER))
+
+  def testCheckNextIncludeOrder_LikelyThenCpp(self):
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._LIKELY_MY_HEADER))
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._CPP_SYS_HEADER))
+
+  def testCheckNextIncludeOrder_PossibleThenCpp(self):
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._POSSIBLE_MY_HEADER))
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._CPP_SYS_HEADER))
+
+  def testCheckNextIncludeOrder_CppThenLikely(self):
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._CPP_SYS_HEADER))
+    # This will eventually fail.
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._LIKELY_MY_HEADER))
+
+  def testCheckNextIncludeOrder_CppThenPossible(self):
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._CPP_SYS_HEADER))
+    self.assertEqual('', self.include_state.CheckNextIncludeOrder(
+        cpplint._POSSIBLE_MY_HEADER))
+
+  def testClassifyInclude(self):
+    file_info = cpplint.FileInfo
+    classify_include = cpplint._ClassifyInclude
+    self.assertEqual(cpplint._C_SYS_HEADER,
+                     classify_include(file_info('foo/foo.cc'),
+                                      'stdio.h',
+                                      True))
+    self.assertEqual(cpplint._CPP_SYS_HEADER,
+                     classify_include(file_info('foo/foo.cc'),
+                                      'string',
+                                      True))
+    self.assertEqual(cpplint._CPP_SYS_HEADER,
+                     classify_include(file_info('foo/foo.cc'),
+                                      'typeinfo',
+                                      True))
+    self.assertEqual(cpplint._OTHER_HEADER,
+                     classify_include(file_info('foo/foo.cc'),
+                                      'string',
+                                      False))
+
+    self.assertEqual(cpplint._LIKELY_MY_HEADER,
+                     classify_include(file_info('foo/foo.cc'),
+                                      'foo/foo-inl.h',
+                                      False))
+    self.assertEqual(cpplint._LIKELY_MY_HEADER,
+                     classify_include(file_info('foo/internal/foo.cc'),
+                                      'foo/public/foo.h',
+                                      False))
+    self.assertEqual(cpplint._POSSIBLE_MY_HEADER,
+                     classify_include(file_info('foo/internal/foo.cc'),
+                                      'foo/other/public/foo.h',
+                                      False))
+    self.assertEqual(cpplint._OTHER_HEADER,
+                     classify_include(file_info('foo/internal/foo.cc'),
+                                      'foo/other/public/foop.h',
+                                      False))
+
+  def testTryDropCommonSuffixes(self):
+    self.assertEqual('foo/foo', cpplint._DropCommonSuffixes('foo/foo-inl.h'))
+    self.assertEqual('foo/bar/foo',
+                     cpplint._DropCommonSuffixes('foo/bar/foo_inl.h'))
+    self.assertEqual('foo/foo', cpplint._DropCommonSuffixes('foo/foo.cc'))
+    self.assertEqual('foo/foo_unusualinternal',
+                     cpplint._DropCommonSuffixes('foo/foo_unusualinternal.h'))
+    self.assertEqual('',
+                     cpplint._DropCommonSuffixes('_test.cc'))
+    self.assertEqual('test',
+                     cpplint._DropCommonSuffixes('test.cc'))
+
+  def testRegression(self):
+    def Format(includes):
+      include_list = []
+      for item in includes:
+        if item.startswith('"') or item.startswith('<'):
+          include_list.append('#include %s\n' % item)
+        else:
+          include_list.append(item + '\n')
+      return ''.join(include_list)
+
+    # Test singleton cases first.
+    self.TestLanguageRulesCheck('foo/foo.cc', Format(['"foo/foo.h"']), '')
+    self.TestLanguageRulesCheck('foo/foo.cc', Format(['<stdio.h>']), '')
+    self.TestLanguageRulesCheck('foo/foo.cc', Format(['<string>']), '')
+    self.TestLanguageRulesCheck('foo/foo.cc', Format(['"foo/foo-inl.h"']), '')
+    self.TestLanguageRulesCheck('foo/foo.cc', Format(['"bar/bar-inl.h"']), '')
+    self.TestLanguageRulesCheck('foo/foo.cc', Format(['"bar/bar.h"']), '')
+
+    # Test everything in a good and new order.
+    self.TestLanguageRulesCheck('foo/foo.cc',
+                                Format(['"foo/foo.h"',
+                                        '"foo/foo-inl.h"',
+                                        '<stdio.h>',
+                                        '<string>',
+                                        '<unordered_map>',
+                                        '"bar/bar-inl.h"',
+                                        '"bar/bar.h"']),
+                                '')
+
+    # Test bad orders.
+    self.TestLanguageRulesCheck(
+        'foo/foo.cc',
+        Format(['<string>', '<stdio.h>']),
+        'Found C system header after C++ system header.'
+        ' Should be: foo.h, c system, c++ system, other.'
+        '  [build/include_order] [4]')
+    self.TestLanguageRulesCheck(
+        'foo/foo.cc',
+        Format(['"foo/bar-inl.h"',
+                '"foo/foo-inl.h"']),
+        '')
+    self.TestLanguageRulesCheck(
+        'foo/foo.cc',
+        Format(['"foo/e.h"',
+                '"foo/b.h"',  # warning here (e>b)
+                '"foo/c.h"',
+                '"foo/d.h"',
+                '"foo/a.h"']),  # warning here (d>a)
+        ['Include "foo/b.h" not in alphabetical order'
+         '  [build/include_alpha] [4]',
+         'Include "foo/a.h" not in alphabetical order'
+         '  [build/include_alpha] [4]'])
+    # -inl.h headers are no longer special.
+    self.TestLanguageRulesCheck('foo/foo.cc',
+                                Format(['"foo/foo-inl.h"', '<string>']),
+                                '')
+    self.TestLanguageRulesCheck('foo/foo.cc',
+                                Format(['"foo/bar.h"', '"foo/bar-inl.h"']),
+                                '')
+    # Test componentized header.  OK to have my header in ../public dir.
+    self.TestLanguageRulesCheck('foo/internal/foo.cc',
+                                Format(['"foo/public/foo.h"', '<string>']),
+                                '')
+    # OK to have my header in other dir (not stylistically, but
+    # cpplint isn't as good as a human).
+    self.TestLanguageRulesCheck('foo/internal/foo.cc',
+                                Format(['"foo/other/public/foo.h"',
+                                        '<string>']),
+                                '')
+    self.TestLanguageRulesCheck('foo/foo.cc',
+                                Format(['"foo/foo.h"',
+                                        '<string>',
+                                        '"base/google.h"',
+                                        '"base/flags.h"']),
+                                'Include "base/flags.h" not in alphabetical '
+                                'order  [build/include_alpha] [4]')
+    # According to the style, -inl.h should come before .h, but we don't
+    # complain about that.
+    self.TestLanguageRulesCheck('foo/foo.cc',
+                                Format(['"foo/foo-inl.h"',
+                                        '"foo/foo.h"',
+                                        '"base/google.h"',
+                                        '"base/google-inl.h"']),
+                                '')
+    # Allow project includes to be separated by blank lines
+    self.TestLanguageRulesCheck('a/a.cc',
+                                Format(['"a/a.h"',
+                                        '<string>',
+                                        '"base/google.h"',
+                                        '',
+                                        '"b/c.h"',
+                                        '',
+                                        'MACRO',
+                                        '"a/b.h"']),
+                                '')
+    self.TestLanguageRulesCheck('a/a.cc',
+                                Format(['"a/a.h"',
+                                        '<string>',
+                                        '"base/google.h"',
+                                        '"a/b.h"']),
+                                'Include "a/b.h" not in alphabetical '
+                                'order  [build/include_alpha] [4]')
+
+    # Test conditional includes
+    self.TestLanguageRulesCheck(
+        'a/a.cc',
+        ''.join(['#include <string.h>\n',
+                 '#include "base/port.h"\n',
+                 '#include <initializer_list>\n']),
+        ('Found C++ system header after other header. '
+         'Should be: a.h, c system, c++ system, other.  '
+         '[build/include_order] [4]'))
+    self.TestLanguageRulesCheck(
+        'a/a.cc',
+        ''.join(['#include <string.h>\n',
+                 '#include "base/port.h"\n',
+                 '#ifdef LANG_CXX11\n',
+                 '#include <initializer_list>\n',
+                 '#endif  // LANG_CXX11\n']),
+        '')
+    self.TestLanguageRulesCheck(
+        'a/a.cc',
+        ''.join(['#include <string.h>\n',
+                 '#ifdef LANG_CXX11\n',
+                 '#include "base/port.h"\n',
+                 '#include <initializer_list>\n',
+                 '#endif  // LANG_CXX11\n']),
+        ('Found C++ system header after other header. '
+         'Should be: a.h, c system, c++ system, other.  '
+         '[build/include_order] [4]'))
+
+    # Third party headers are exempt from order checks
+    self.TestLanguageRulesCheck('foo/foo.cc',
+                                Format(['<string>', '"Python.h"', '<vector>']),
+                                '')
+
+
+class CheckForFunctionLengthsTest(CpplintTestBase):
+
+  def setUp(self):
+    # Reducing these thresholds for the tests speeds up tests significantly.
+    self.old_normal_trigger = cpplint._FunctionState._NORMAL_TRIGGER
+    self.old_test_trigger = cpplint._FunctionState._TEST_TRIGGER
+
+    cpplint._FunctionState._NORMAL_TRIGGER = 10
+    cpplint._FunctionState._TEST_TRIGGER = 25
+
+  def tearDown(self):
+    cpplint._FunctionState._NORMAL_TRIGGER = self.old_normal_trigger
+    cpplint._FunctionState._TEST_TRIGGER = self.old_test_trigger
+
+  def TestFunctionLengthsCheck(self, code, expected_message):
+    """Check warnings for long function bodies are as expected.
+
+    Args:
+      code: C++ source code expected to generate a warning message.
+      expected_message: Message expected to be generated by the C++ code.
+    """
+    self.assertEquals(expected_message,
+                      self.PerformFunctionLengthsCheck(code))
+
+  def TriggerLines(self, error_level):
+    """Return number of lines needed to trigger a function length warning.
+
+    Args:
+      error_level: --v setting for cpplint.
+
+    Returns:
+      Number of lines needed to trigger a function length warning.
+    """
+    return cpplint._FunctionState._NORMAL_TRIGGER * 2**error_level
+
+  def TestLines(self, error_level):
+    """Return number of lines needed to trigger a test function length warning.
+
+    Args:
+      error_level: --v setting for cpplint.
+
+    Returns:
+      Number of lines needed to trigger a test function length warning.
+    """
+    return cpplint._FunctionState._TEST_TRIGGER * 2**error_level
+
+  def TestFunctionLengthCheckDefinition(self, lines, error_level):
+    """Generate long function definition and check warnings are as expected.
+
+    Args:
+      lines: Number of lines to generate.
+      error_level:  --v setting for cpplint.
+    """
+    trigger_level = self.TriggerLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        'void test(int x)' + self.FunctionBody(lines),
+        ('Small and focused functions are preferred: '
+         'test() has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]'
+         % (lines, trigger_level, error_level)))
+
+  def TestFunctionLengthCheckDefinitionOK(self, lines):
+    """Generate shorter function definition and check no warning is produced.
+
+    Args:
+      lines: Number of lines to generate.
+    """
+    self.TestFunctionLengthsCheck(
+        'void test(int x)' + self.FunctionBody(lines),
+        '')
+
+  def TestFunctionLengthCheckAtErrorLevel(self, error_level):
+    """Generate and check function at the trigger level for --v setting.
+
+    Args:
+      error_level: --v setting for cpplint.
+    """
+    self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level),
+                                           error_level)
+
+  def TestFunctionLengthCheckBelowErrorLevel(self, error_level):
+    """Generate and check function just below the trigger level for --v setting.
+
+    Args:
+      error_level: --v setting for cpplint.
+    """
+    self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level)-1,
+                                           error_level-1)
+
+  def TestFunctionLengthCheckAboveErrorLevel(self, error_level):
+    """Generate and check function just above the trigger level for --v setting.
+
+    Args:
+      error_level: --v setting for cpplint.
+    """
+    self.TestFunctionLengthCheckDefinition(self.TriggerLines(error_level)+1,
+                                           error_level)
+
+  def FunctionBody(self, number_of_lines):
+    return ' {\n' + '    this_is_just_a_test();\n'*number_of_lines + '}'
+
+  def FunctionBodyWithBlankLines(self, number_of_lines):
+    return ' {\n' + '    this_is_just_a_test();\n\n'*number_of_lines + '}'
+
+  def FunctionBodyWithNoLints(self, number_of_lines):
+    return (' {\n' +
+            '    this_is_just_a_test();  // NOLINT\n'*number_of_lines + '}')
+
+  # Test line length checks.
+  def testFunctionLengthCheckDeclaration(self):
+    self.TestFunctionLengthsCheck(
+        'void test();',  # Not a function definition
+        '')
+
+  def testFunctionLengthCheckDeclarationWithBlockFollowing(self):
+    self.TestFunctionLengthsCheck(
+        ('void test();\n'
+         + self.FunctionBody(66)),  # Not a function definition
+        '')
+
+  def testFunctionLengthCheckClassDefinition(self):
+    self.TestFunctionLengthsCheck(  # Not a function definition
+        'class Test' + self.FunctionBody(66) + ';',
+        '')
+
+  def testFunctionLengthCheckTrivial(self):
+    self.TestFunctionLengthsCheck(
+        'void test() {}',  # Not counted
+        '')
+
+  def testFunctionLengthCheckEmpty(self):
+    self.TestFunctionLengthsCheck(
+        'void test() {\n}',
+        '')
+
+  def testFunctionLengthCheckDefinitionBelowSeverity0(self):
+    old_verbosity = cpplint._SetVerboseLevel(0)
+    self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(0)-1)
+    cpplint._SetVerboseLevel(old_verbosity)
+
+  def testFunctionLengthCheckDefinitionAtSeverity0(self):
+    old_verbosity = cpplint._SetVerboseLevel(0)
+    self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(0))
+    cpplint._SetVerboseLevel(old_verbosity)
+
+  def testFunctionLengthCheckDefinitionAboveSeverity0(self):
+    old_verbosity = cpplint._SetVerboseLevel(0)
+    self.TestFunctionLengthCheckAboveErrorLevel(0)
+    cpplint._SetVerboseLevel(old_verbosity)
+
+  def testFunctionLengthCheckDefinitionBelowSeverity1v0(self):
+    old_verbosity = cpplint._SetVerboseLevel(0)
+    self.TestFunctionLengthCheckBelowErrorLevel(1)
+    cpplint._SetVerboseLevel(old_verbosity)
+
+  def testFunctionLengthCheckDefinitionAtSeverity1v0(self):
+    old_verbosity = cpplint._SetVerboseLevel(0)
+    self.TestFunctionLengthCheckAtErrorLevel(1)
+    cpplint._SetVerboseLevel(old_verbosity)
+
+  def testFunctionLengthCheckDefinitionBelowSeverity1(self):
+    self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(1)-1)
+
+  def testFunctionLengthCheckDefinitionAtSeverity1(self):
+    self.TestFunctionLengthCheckDefinitionOK(self.TriggerLines(1))
+
+  def testFunctionLengthCheckDefinitionAboveSeverity1(self):
+    self.TestFunctionLengthCheckAboveErrorLevel(1)
+
+  def testFunctionLengthCheckDefinitionSeverity1PlusBlanks(self):
+    error_level = 1
+    error_lines = self.TriggerLines(error_level) + 1
+    trigger_level = self.TriggerLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        'void test_blanks(int x)' + self.FunctionBody(error_lines),
+        ('Small and focused functions are preferred: '
+         'test_blanks() has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]')
+        % (error_lines, trigger_level, error_level))
+
+  def testFunctionLengthCheckComplexDefinitionSeverity1(self):
+    error_level = 1
+    error_lines = self.TriggerLines(error_level) + 1
+    trigger_level = self.TriggerLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        ('my_namespace::my_other_namespace::MyVeryLongTypeName*\n'
+         'my_namespace::my_other_namespace::MyFunction(int arg1, char* arg2)'
+         + self.FunctionBody(error_lines)),
+        ('Small and focused functions are preferred: '
+         'my_namespace::my_other_namespace::MyFunction()'
+         ' has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]')
+        % (error_lines, trigger_level, error_level))
+
+  def testFunctionLengthCheckDefinitionSeverity1ForTest(self):
+    error_level = 1
+    error_lines = self.TestLines(error_level) + 1
+    trigger_level = self.TestLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        'TEST_F(Test, Mutator)' + self.FunctionBody(error_lines),
+        ('Small and focused functions are preferred: '
+         'TEST_F(Test, Mutator) has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]')
+        % (error_lines, trigger_level, error_level))
+
+  def testFunctionLengthCheckDefinitionSeverity1ForSplitLineTest(self):
+    error_level = 1
+    error_lines = self.TestLines(error_level) + 1
+    trigger_level = self.TestLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        ('TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,\n'
+         '    FixGoogleUpdate_AllValues_MachineApp)'  # note: 4 spaces
+         + self.FunctionBody(error_lines)),
+        ('Small and focused functions are preferred: '
+         'TEST_F(GoogleUpdateRecoveryRegistryProtectedTest, '  # 1 space
+         'FixGoogleUpdate_AllValues_MachineApp) has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]')
+        % (error_lines+1, trigger_level, error_level))
+
+  def testFunctionLengthCheckDefinitionSeverity1ForBadTestDoesntBreak(self):
+    error_level = 1
+    error_lines = self.TestLines(error_level) + 1
+    trigger_level = self.TestLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        ('TEST_F('
+         + self.FunctionBody(error_lines)),
+        ('Small and focused functions are preferred: '
+         'TEST_F has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]')
+        % (error_lines, trigger_level, error_level))
+
+  def testFunctionLengthCheckDefinitionSeverity1WithEmbeddedNoLints(self):
+    error_level = 1
+    error_lines = self.TriggerLines(error_level)+1
+    trigger_level = self.TriggerLines(cpplint._VerboseLevel())
+    self.TestFunctionLengthsCheck(
+        'void test(int x)' + self.FunctionBodyWithNoLints(error_lines),
+        ('Small and focused functions are preferred: '
+         'test() has %d non-comment lines '
+         '(error triggered by exceeding %d lines).'
+         '  [readability/fn_size] [%d]')
+        % (error_lines, trigger_level, error_level))
+
+  def testFunctionLengthCheckDefinitionSeverity1WithNoLint(self):
+    self.TestFunctionLengthsCheck(
+        ('void test(int x)' + self.FunctionBody(self.TriggerLines(1))
+         + '  // NOLINT -- long function'),
+        '')
+
+  def testFunctionLengthCheckDefinitionBelowSeverity2(self):
+    self.TestFunctionLengthCheckBelowErrorLevel(2)
+
+  def testFunctionLengthCheckDefinitionSeverity2(self):
+    self.TestFunctionLengthCheckAtErrorLevel(2)
+
+  def testFunctionLengthCheckDefinitionAboveSeverity2(self):
+    self.TestFunctionLengthCheckAboveErrorLevel(2)
+
+  def testFunctionLengthCheckDefinitionBelowSeverity3(self):
+    self.TestFunctionLengthCheckBelowErrorLevel(3)
+
+  def testFunctionLengthCheckDefinitionSeverity3(self):
+    self.TestFunctionLengthCheckAtErrorLevel(3)
+
+  def testFunctionLengthCheckDefinitionAboveSeverity3(self):
+    self.TestFunctionLengthCheckAboveErrorLevel(3)
+
+  def testFunctionLengthCheckDefinitionBelowSeverity4(self):
+    self.TestFunctionLengthCheckBelowErrorLevel(4)
+
+  def testFunctionLengthCheckDefinitionSeverity4(self):
+    self.TestFunctionLengthCheckAtErrorLevel(4)
+
+  def testFunctionLengthCheckDefinitionAboveSeverity4(self):
+    self.TestFunctionLengthCheckAboveErrorLevel(4)
+
+  def testFunctionLengthCheckDefinitionBelowSeverity5(self):
+    self.TestFunctionLengthCheckBelowErrorLevel(5)
+
+  def testFunctionLengthCheckDefinitionAtSeverity5(self):
+    self.TestFunctionLengthCheckAtErrorLevel(5)
+
+  def testFunctionLengthCheckDefinitionAboveSeverity5(self):
+    self.TestFunctionLengthCheckAboveErrorLevel(5)
+
+  def testFunctionLengthCheckDefinitionHugeLines(self):
+    # 5 is the limit
+    self.TestFunctionLengthCheckDefinition(self.TriggerLines(10), 5)
+
+  def testFunctionLengthNotDeterminable(self):
+    # Macro invocation without terminating semicolon.
+    self.TestFunctionLengthsCheck(
+        'MACRO(arg)',
+        '')
+
+    # Macro with underscores
+    self.TestFunctionLengthsCheck(
+        'MACRO_WITH_UNDERSCORES(arg1, arg2, arg3)',
+        '')
+
+    self.TestFunctionLengthsCheck(
+        'NonMacro(arg)',
+        'Lint failed to find start of function body.'
+        '  [readability/fn_size] [5]')
+
+
+def TrimExtraIndent(text_block):
+  """Trim a uniform amount of whitespace off of each line in a string.
+
+  Compute the minimum indent on all non blank lines and trim that from each, so
+  that the block of text has no extra indentation.
+
+  Args:
+    text_block: a multiline string
+
+  Returns:
+    text_block with the common whitespace indent of each line removed.
+  """
+
+  def CountLeadingWhitespace(s):
+    count = 0
+    for c in s:
+      if not c.isspace():
+        break
+      count += 1
+    return count
+  # find the minimum indent (except for blank lines)
+  min_indent = min([CountLeadingWhitespace(line)
+                    for line in text_block.split('\n') if line])
+  return '\n'.join([line[min_indent:] for line in text_block.split('\n')])
+
+
+class CloseExpressionTest(unittest.TestCase):
+
+  def setUp(self):
+    self.lines = cpplint.CleansedLines(
+        #           1         2         3         4         5
+        # 0123456789012345678901234567890123456789012345678901234567890
+        ['// Line 0',
+         'inline RCULocked<X>::ReadPtr::ReadPtr(const RCULocked* rcu) {',
+         '  DCHECK(!(data & kFlagMask)) << "Error";',
+         '}',
+         '// Line 4',
+         'RCULocked<X>::WritePtr::WritePtr(RCULocked* rcu)',
+         '    : lock_(&rcu_->mutex_) {',
+         '}',
+         '// Line 8',
+         'template <typename T, typename... A>',
+         'typename std::enable_if<',
+         '    std::is_array<T>::value && (std::extent<T>::value > 0)>::type',
+         'MakeUnique(A&&... a) = delete;',
+         '// Line 13',
+         'auto x = []() {};',
+         '// Line 15',
+         'template <typename U>',
+         'friend bool operator==(const reffed_ptr& a,',
+         '                       const reffed_ptr<U>& b) {',
+         '  return a.get() == b.get();',
+         '}',
+         '// Line 21'])
+
+  def testCloseExpression(self):
+    # List of positions to test:
+    # (start line, start position, end line, end position + 1)
+    positions = [(1, 16, 1, 19),
+                 (1, 37, 1, 59),
+                 (1, 60, 3, 1),
+                 (2, 8, 2, 29),
+                 (2, 30, 22, -1),  # Left shift operator
+                 (9, 9, 9, 36),
+                 (10, 23, 11, 59),
+                 (11, 54, 22, -1),  # Greater than operator
+                 (14, 9, 14, 11),
+                 (14, 11, 14, 13),
+                 (14, 14, 14, 16),
+                 (17, 22, 18, 46),
+                 (18, 47, 20, 1)]
+    for p in positions:
+      (_, line, column) = cpplint.CloseExpression(self.lines, p[0], p[1])
+      self.assertEquals((p[2], p[3]), (line, column))
+
+  def testReverseCloseExpression(self):
+    # List of positions to test:
+    # (end line, end position, start line, start position)
+    positions = [(1, 18, 1, 16),
+                 (1, 58, 1, 37),
+                 (2, 27, 2, 10),
+                 (2, 28, 2, 8),
+                 (6, 18, 0, -1),  # -> operator
+                 (9, 35, 9, 9),
+                 (11, 54, 0, -1),  # Greater than operator
+                 (11, 57, 11, 31),
+                 (14, 10, 14, 9),
+                 (14, 12, 14, 11),
+                 (14, 15, 14, 14),
+                 (18, 45, 17, 22),
+                 (20, 0, 18, 47)]
+    for p in positions:
+      (_, line, column) = cpplint.ReverseCloseExpression(self.lines, p[0], p[1])
+      self.assertEquals((p[2], p[3]), (line, column))
+
+
+class NestingStateTest(unittest.TestCase):
+
+  def setUp(self):
+    self.nesting_state = cpplint.NestingState()
+    self.error_collector = ErrorCollector(self.assert_)
+
+  def UpdateWithLines(self, lines):
+    clean_lines = cpplint.CleansedLines(lines)
+    for line in xrange(clean_lines.NumLines()):
+      self.nesting_state.Update('test.cc',
+                                clean_lines, line, self.error_collector)
+
+  def testEmpty(self):
+    self.UpdateWithLines([])
+    self.assertEquals(self.nesting_state.stack, [])
+
+  def testNamespace(self):
+    self.UpdateWithLines(['namespace {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0],
+                               cpplint._NamespaceInfo))
+    self.assertTrue(self.nesting_state.stack[0].seen_open_brace)
+    self.assertEquals(self.nesting_state.stack[0].name, '')
+
+    self.UpdateWithLines(['namespace outer { namespace inner'])
+    self.assertEquals(len(self.nesting_state.stack), 3)
+    self.assertTrue(self.nesting_state.stack[0].seen_open_brace)
+    self.assertTrue(self.nesting_state.stack[1].seen_open_brace)
+    self.assertFalse(self.nesting_state.stack[2].seen_open_brace)
+    self.assertEquals(self.nesting_state.stack[0].name, '')
+    self.assertEquals(self.nesting_state.stack[1].name, 'outer')
+    self.assertEquals(self.nesting_state.stack[2].name, 'inner')
+
+    self.UpdateWithLines(['{'])
+    self.assertTrue(self.nesting_state.stack[2].seen_open_brace)
+
+    self.UpdateWithLines(['}', '}}'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+  def testClass(self):
+    self.UpdateWithLines(['class A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'A')
+    self.assertFalse(self.nesting_state.stack[0].is_derived)
+    self.assertEquals(self.nesting_state.stack[0].class_indent, 0)
+
+    self.UpdateWithLines(['};',
+                          'struct B : public A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'B')
+    self.assertTrue(self.nesting_state.stack[0].is_derived)
+
+    self.UpdateWithLines(['};',
+                          'class C',
+                          ': public A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'C')
+    self.assertTrue(self.nesting_state.stack[0].is_derived)
+
+    self.UpdateWithLines(['};',
+                          'template<T>'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+    self.UpdateWithLines(['class D {', '  class E {'])
+    self.assertEquals(len(self.nesting_state.stack), 2)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'D')
+    self.assertFalse(self.nesting_state.stack[0].is_derived)
+    self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[1].name, 'E')
+    self.assertFalse(self.nesting_state.stack[1].is_derived)
+    self.assertEquals(self.nesting_state.stack[1].class_indent, 2)
+    self.assertEquals(self.nesting_state.InnermostClass().name, 'E')
+
+    self.UpdateWithLines(['}', '}'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+  def testClassAccess(self):
+    self.UpdateWithLines(['class A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].access, 'private')
+
+    self.UpdateWithLines([' public:'])
+    self.assertEquals(self.nesting_state.stack[0].access, 'public')
+    self.UpdateWithLines([' protracted:'])
+    self.assertEquals(self.nesting_state.stack[0].access, 'public')
+    self.UpdateWithLines([' protected:'])
+    self.assertEquals(self.nesting_state.stack[0].access, 'protected')
+    self.UpdateWithLines([' private:'])
+    self.assertEquals(self.nesting_state.stack[0].access, 'private')
+
+    self.UpdateWithLines(['  struct B {'])
+    self.assertEquals(len(self.nesting_state.stack), 2)
+    self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[1].access, 'public')
+    self.assertEquals(self.nesting_state.stack[0].access, 'private')
+
+    self.UpdateWithLines(['   protected  :'])
+    self.assertEquals(self.nesting_state.stack[1].access, 'protected')
+    self.assertEquals(self.nesting_state.stack[0].access, 'private')
+
+    self.UpdateWithLines(['  }', '}'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+  def testStruct(self):
+    self.UpdateWithLines(['struct A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'A')
+    self.assertFalse(self.nesting_state.stack[0].is_derived)
+
+    self.UpdateWithLines(['}',
+                          'void Func(struct B arg) {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertFalse(isinstance(self.nesting_state.stack[0],
+                                cpplint._ClassInfo))
+
+    self.UpdateWithLines(['}'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+  def testPreprocessor(self):
+    self.assertEquals(len(self.nesting_state.pp_stack), 0)
+    self.UpdateWithLines(['#if MACRO1'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 1)
+    self.UpdateWithLines(['#endif'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 0)
+
+    self.UpdateWithLines(['#ifdef MACRO2'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 1)
+    self.UpdateWithLines(['#else'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 1)
+    self.UpdateWithLines(['#ifdef MACRO3'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 2)
+    self.UpdateWithLines(['#elif MACRO4'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 2)
+    self.UpdateWithLines(['#endif'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 1)
+    self.UpdateWithLines(['#endif'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 0)
+
+    self.UpdateWithLines(['#ifdef MACRO5',
+                          'class A {',
+                          '#elif MACRO6',
+                          'class B {',
+                          '#else',
+                          'class C {',
+                          '#endif'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 0)
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'A')
+    self.UpdateWithLines(['};'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+    self.UpdateWithLines(['class D',
+                          '#ifdef MACRO7'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 1)
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'D')
+    self.assertFalse(self.nesting_state.stack[0].is_derived)
+
+    self.UpdateWithLines(['#elif MACRO8',
+                          ': public E'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[0].name, 'D')
+    self.assertTrue(self.nesting_state.stack[0].is_derived)
+    self.assertFalse(self.nesting_state.stack[0].seen_open_brace)
+
+    self.UpdateWithLines(['#else',
+                          '{'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[0].name, 'D')
+    self.assertFalse(self.nesting_state.stack[0].is_derived)
+    self.assertTrue(self.nesting_state.stack[0].seen_open_brace)
+
+    self.UpdateWithLines(['#endif'])
+    self.assertEquals(len(self.nesting_state.pp_stack), 0)
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[0].name, 'D')
+    self.assertFalse(self.nesting_state.stack[0].is_derived)
+    self.assertFalse(self.nesting_state.stack[0].seen_open_brace)
+
+    self.UpdateWithLines([';'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+  def testTemplate(self):
+    self.UpdateWithLines(['template <T,',
+                          '          class Arg1 = tmpl<T> >'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+    self.UpdateWithLines(['class A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'A')
+
+    self.UpdateWithLines(['};',
+                          'template <T,',
+                          '  template <typename, typename> class B>',
+                          'class C'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'C')
+    self.UpdateWithLines([';'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+    self.UpdateWithLines(['class D : public Tmpl<E>'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'D')
+
+    self.UpdateWithLines(['{', '};'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+    self.UpdateWithLines(['template <class F,',
+                          '          class G,',
+                          '          class H,',
+                          '          typename I>',
+                          'static void Func() {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertFalse(isinstance(self.nesting_state.stack[0],
+                                cpplint._ClassInfo))
+    self.UpdateWithLines(['}',
+                          'template <class J> class K {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'K')
+
+  def testTemplateInnerClass(self):
+    self.UpdateWithLines(['class A {',
+                          ' public:'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+
+    self.UpdateWithLines(['  template <class B>',
+                          '  class C<alloc<B> >',
+                          '      : public A {'])
+    self.assertEquals(len(self.nesting_state.stack), 2)
+    self.assertTrue(isinstance(self.nesting_state.stack[1], cpplint._ClassInfo))
+
+  def testArguments(self):
+    self.UpdateWithLines(['class A {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'A')
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+
+    self.UpdateWithLines(['  void Func(',
+                          '    struct X arg1,'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.UpdateWithLines(['    struct X *arg2);'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+
+    self.UpdateWithLines(['};'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+    self.UpdateWithLines(['struct B {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertTrue(isinstance(self.nesting_state.stack[0], cpplint._ClassInfo))
+    self.assertEquals(self.nesting_state.stack[0].name, 'B')
+
+    self.UpdateWithLines(['#ifdef MACRO',
+                          '  void Func(',
+                          '    struct X arg1'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.UpdateWithLines(['#else'])
+
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+    self.UpdateWithLines(['  void Func(',
+                          '    struct X arg1'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+
+    self.UpdateWithLines(['#endif'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.UpdateWithLines(['    struct X *arg2);'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+
+    self.UpdateWithLines(['};'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+  def testInlineAssembly(self):
+    self.UpdateWithLines(['void CopyRow_SSE2(const uint8* src, uint8* dst,',
+                          '                  int count) {'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm, cpplint._NO_ASM)
+
+    self.UpdateWithLines(['  asm volatile ('])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm,
+                      cpplint._INSIDE_ASM)
+
+    self.UpdateWithLines(['    "sub        %0,%1                         \\n"',
+                          '  "1:                                         \\n"',
+                          '    "movdqa    (%0),%%xmm0                    \\n"',
+                          '    "movdqa    0x10(%0),%%xmm1                \\n"',
+                          '    "movdqa    %%xmm0,(%0,%1)                 \\n"',
+                          '    "movdqa    %%xmm1,0x10(%0,%1)             \\n"',
+                          '    "lea       0x20(%0),%0                    \\n"',
+                          '    "sub       $0x20,%2                       \\n"',
+                          '    "jg        1b                             \\n"',
+                          '  : "+r"(src),   // %0',
+                          '    "+r"(dst),   // %1',
+                          '    "+r"(count)  // %2',
+                          '  :',
+                          '  : "memory", "cc"'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm,
+                      cpplint._INSIDE_ASM)
+
+    self.UpdateWithLines(['#if defined(__SSE2__)',
+                          '    , "xmm0", "xmm1"'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm,
+                      cpplint._INSIDE_ASM)
+
+    self.UpdateWithLines(['#endif'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 1)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm,
+                      cpplint._INSIDE_ASM)
+
+    self.UpdateWithLines(['  );'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm, cpplint._END_ASM)
+
+    self.UpdateWithLines(['__asm {'])
+    self.assertEquals(len(self.nesting_state.stack), 2)
+    self.assertEquals(self.nesting_state.stack[-1].open_parentheses, 0)
+    self.assertEquals(self.nesting_state.stack[-1].inline_asm,
+                      cpplint._BLOCK_ASM)
+
+    self.UpdateWithLines(['}'])
+    self.assertEquals(len(self.nesting_state.stack), 1)
+
+    self.UpdateWithLines(['}'])
+    self.assertEquals(len(self.nesting_state.stack), 0)
+
+
+# pylint: disable-msg=C6409
+def setUp():
+  """Runs before all tests are executed.
+  """
+  # Enable all filters, so we don't miss anything that is off by default.
+  cpplint._DEFAULT_FILTERS = []
+  cpplint._cpplint_state.SetFilters('')
+
+
+# pylint: disable-msg=C6409
+def tearDown():
+  """A global check to make sure all error-categories have been tested.
+
+  The main tearDown() routine is the only code we can guarantee will be
+  run after all other tests have been executed.
+  """
+  try:
+    if _run_verifyallcategoriesseen:
+      ErrorCollector(None).VerifyAllCategoriesAreSeen()
+  except NameError:
+    # If nobody set the global _run_verifyallcategoriesseen, then
+    # we assume we should silently not run the test
+    pass
+
+
+if __name__ == '__main__':
+  # We don't want to run the VerifyAllCategoriesAreSeen() test unless
+  # we're running the full test suite: if we only run one test,
+  # obviously we're not going to see all the error categories.  So we
+  # only run VerifyAllCategoriesAreSeen() when no commandline flags
+  # are passed in.
+  global _run_verifyallcategoriesseen
+  _run_verifyallcategoriesseen = (len(sys.argv) == 1)
+
+  setUp()
+  unittest.main()
+  tearDown()
diff --git a/tools/ide/QtCreator/QtCreatorSetup.sh b/tools/ide/QtCreator/QtCreatorSetup.sh
new file mode 100755
index 0000000..ba220fa
--- /dev/null
+++ b/tools/ide/QtCreator/QtCreatorSetup.sh
@@ -0,0 +1,1017 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+################################################################################
+# GENERIC FUNCTIONS                                                            #
+################################################################################
+
+### print an error message #####################################################
+# Prints a error <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printError <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printError {
+  local string="ERROR:   $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a warning message ####################################################
+# Prints a warning <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printMessage <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printWarning {
+  local string="WARNING: $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)"
+}
+
+### print an information message ###############################################
+# Prints an information <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printInfo <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printInfo {
+  local string="INFO:    $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)"
+}
+
+### print a message to file ####################################################
+# Appends a <message> to a log file, specified by the variable 'LOG_FILE'.
+#
+# usage       printLog <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printLog {
+  local string="LOG:     $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+}
+
+### exit the script normally ###################################################
+# Prints a delimiter and exits the script normally (returns 0).
+#
+# usage:      quitScript
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
+  exit 0
+}
+
+### read a user input ##########################################################
+# Reads a single character user input from a set up <options> and stores it in
+# a given <return> variable.
+#
+# usage:      readUserInput <options> <return>
+# arguments:  <options>
+#                 String definiing the set of valid characters.
+#                 If the string is empty, the user can input any character.
+#             <return>
+#                 Variable to store the selected character to.
+# return:     n/a
+#
+function readUserInput {
+  local input=""
+  # read user input
+  while [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); do
+    read -p "your selection: " -n 1 -e input
+    if [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); then
+      printWarning "[$input] is no valid action\n"
+    fi
+  done
+  printLog "[$input] has been selected\n"
+  eval $2="$input"
+}
+
+### check whether argument is an option ########################################
+# Checks a <string> whether it is an option.
+# Options are defined to either start with '--' followed by any string, or
+# to start with a single '-' followed by a single character, or
+# to start with a single '-' followed by a single character, a '=' and any string.
+# Examples: '--option', '--option=arg', '-o', '-o=arg', '--'
+#
+# usage:      parseIsOption <string>
+# arguments:  <string>
+#                 A string to check whether it is an option.
+# return:     0
+#                 <string> is an option.
+#             -1
+#                 <string> is not an option.
+#
+function parseIsOption {
+  if [[ "$1" =~ ^-(.$|.=.*) ]] || [[ "$1" =~ ^--.* ]]; then
+    return 0
+  else
+    return -1
+  fi
+}
+
+### set the log file ###########################################################
+# Sets a specified <infile> as log file and checks whether it already exists.
+# If so, the log may either be appended to the file, its content can be cleared,
+# or no log is generated at all.
+# The resulting path is stored in <outvar>.
+#
+# usage:      setLogFile [--option=<option>] [--quiet] <infile> <outvar>
+# arguments:  --option=<option>
+#                 Select what to do if <file> already exists.
+#                 Possible values are 'a', 'c', 'r' and 'n'.
+#                 - a: append (starts with a separator)
+#                 - c: continue (does not insert a seperator)
+#                 - r: delete and restart
+#                 - n: no log
+#                 If no option is secified but <file> exists, an interactive selection is provided.
+#             --quiet
+#                 Suppress all messages.
+#             <infile>
+#                 Path of the wanted log file.
+#             <outvar>
+#                 Variable to store the path of the log file to.
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: invalid input
+#
+function setLogFile {
+  local filepath=""
+  local option=""
+  local quiet=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -o=*|--option=*)
+          option=${1#*=}; shift 1;;
+        -o*|--option*)
+          option="$2"; shift 2;;
+        -q|--quiet)
+          quiet=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+  filepath=$(realpath ${otherargs[0]})
+
+  # if file already exists
+  if [ -e $filepath ]; then
+    # if no option was specified, ask what to do
+    if [ -z "$option" ]; then
+      printWarning "log file $filepath already esists\n"
+      local userinput=""
+      printf "Select what to do:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput "AaRrNn" userinput
+      option=${userinput,,}
+    fi
+    # evaluate option
+    case "$option" in
+      a|c)
+        if [ $quiet = false ]; then
+          printInfo "appending log to $filepath\n"
+        fi
+        if [ $option != c ]; then
+          printf "\n" >> $filepath
+          printf "######################################################################\n" >> $filepath
+          printf "\n" >> $filepath
+        fi
+        ;;
+      r)
+        echo -n "" > $filepath
+        if [ $quiet = false ]; then
+          printInfo "content of $filepath wiped\n"
+        fi
+        ;;
+      n)
+        if [ $quiet = false ]; then
+          printInfo "no log file will be generated\n"
+        fi
+        filepath=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $option\n"; return -1;;
+    esac
+  else
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
+  fi
+
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
+}
+
+################################################################################
+# SPECIFIC FUNCTIONS                                                           #
+################################################################################
+
+### print welcome text #########################################################
+# Prints a welcome message to standard out.
+#
+# usage:      printWelcomeText
+# arguments:  n/a
+# return:     n/a
+#
+function printWelcomeText {
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "#                  Welcome to the QtCreator setup!                   #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+  printf "#                                                                    #\n"
+  printf "# This is free software; see the source for copying conditions.      #\n"
+  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+  printf "# Excellence Initiative.                                             #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+}
+
+### print help #################################################################
+# Prints a help text to standard out.
+#
+# usage:      printHelp
+# arguments:  n/a
+# return:     n/a
+#
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [-c|--clean] [-w|--wipe] [--LightRing] [--PowerManagement] [--DiWheelDrive] [-a|--all] [-q|--quit] [--log=<file>]\n"
+  printf "\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -c, --clean\n"
+  printf "              Delete project files.\n"
+  printf "          -w, --wipe\n"
+  printf "              Delete project and .user files.\n"
+  printf "          --LightRing\n"
+  printf "              Create project for the LightRing module.\n"
+  printf "          --PowerManagement\n"
+  printf "              Create project for the PowerManagement module.\n"
+  printf "          --DiWheelDrive\n"
+  printf "              Create project for the DiWheelDrive module.\n"
+  printf "          -a, --all\n"
+  printf "              Create projects for all modules.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### read directory where to create/delete projects #############################
+# Read the directory where to create/delete project files from user.
+#
+# usage:      getProjectDir <pathvar>
+# arguments:  <pathvar>
+#                 Variable to store the selected path to.
+# return:     n/a
+#
+function getProjectDir {
+  printLog "reading path for project files from user...\n"
+  local amiroosdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../../)
+  local input=""
+  read -p "Path where to create/delete project files: " -i $amiroosdir -e input
+  printLog "user selected path $(realpath $input)\n"
+  eval $1="$(realpath $input)"
+}
+
+### retrieves the ARM-NONE-EABI-GCC include directory ##########################
+# Retrieves the include directory of the currently set arm-none-eabi-gcc.
+#
+# usage:      retrieveGccIncludeDir <path>
+# arguments:  <path>
+#                 Variable to store the path to.
+# return:    0
+#                 No error or warning occurred.
+#            -1
+#                 Error: Command 'arm-none-eabi-gcc' not found.
+#
+function retrieveGccIncludeDir {
+  # retrieve binary path or link
+  local binpath=$(which arm-none-eabi-gcc)
+  if [ -z "$binpath" ]; then
+    printError "command 'arm-none-eabi-gcc' not found\n"
+    return -1
+  else 
+
+    # traverse any links
+    while [ -L "$binpath" ]; do
+      binpath=$(readlink $binpath)
+    done
+    printInfo "gcc-arm-none-eabi detected: $binpath\n"
+
+    # return include path
+    eval $1=$(realpath $(dirname ${binpath})/../arm-none-eabi/include/)
+
+    return 0
+  fi
+}
+
+### delete project files #######################################################
+# Deletes all project files and optionally .user files, too.
+#
+# usage:      deleteProjects [-p|--path=<path>] [-o|--out=<var>] [-w|-wipe]
+# arguments:  -p, --path <path>
+#                 Path where to delete the project files.
+#             -o, --out <var>
+#                 Variable to store the path to.
+#             -w, --wipe
+#                 Delete .user files as well.
+# return:
+#  -  0: no error
+#  -  1: warning: function aborted by user
+#  - -1: error: unexpected user input
+function deleteProjects {
+  local projectdir=""
+  local outvar=""
+  local wipe=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -p=*|--path=*)
+          projectdir=$(realpath "${1#*=}"); shift 1;;
+        -p|--path)
+          projectdir=$(realpath "$2"); shift 2;;
+        -o=*|--out=*)
+          outvar=${1#*=}; shift 1;;
+        -o|--out)
+          outvar=$2; shift 2;;
+        -w|--wipe)
+          wipe=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # print message
+  if [ $wipe != true ]; then
+    printInfo "deleting all QtCreator project files (*.includes, *.files, *.config, and *.creator)\n"
+  else
+    printInfo "deleting all QtCreator project files (*.includes, *.files, *.config, *.creator, and *.user)\n"
+  fi
+
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
+
+  # remove all project files
+  rm ${projectdir}/LightRing.includes 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/PowerManagement.includes 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/DiWheelDrive.includes 2>&1 | tee -a $LOG_FILE
+
+  rm ${projectdir}/LightRing.files 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/PowerManagement.files 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/DiWheelDrive.files 2>&1 | tee -a $LOG_FILE
+
+  rm ${projectdir}/LightRing.config 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/PowerManagement.config 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/DiWheelDrive.config 2>&1 | tee -a $LOG_FILE
+
+  rm ${projectdir}/LightRing.creator 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/PowerManagement.creator 2>&1 | tee -a $LOG_FILE
+  rm ${projectdir}/DiWheelDrive.creator 2>&1 | tee -a $LOG_FILE
+
+  if [ $wipe == true ]; then
+    rm ${projectdir}/LightRing.creator.user 2>&1 | tee -a $LOG_FILE
+    rm ${projectdir}/PowerManagement.creator.user 2>&1 | tee -a $LOG_FILE
+    rm ${projectdir}/DiWheelDrive.creator.user 2>&1 | tee -a $LOG_FILE
+  fi
+
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+
+  return 0
+}
+
+### create LightRing project files #############################################
+# Create project files for the LightRing module.
+#
+# usage:      createLightRingProject [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
+# arguments:  -p, --path <path>
+#                 Path where to create the project files.
+#             --gcc=<path>
+#                 Path to the GCC include directory.
+#             -o, --out <var>
+#                 Variable to store the path to.
+#             --gccout=<var>
+#                 Variable to store the path to the GCC include directory to.
+# return:     0
+#                 No error or warning occurred.
+#
+function createLightRingProject {
+  local userdir=$(pwd)
+  local projectdir=""
+  local gccincludedir=""
+  local outvar=""
+  local gccoutvar=""
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -p=*|--path=*)
+          projectdir=$(realpath "${1#*=}"); shift 1;;
+        -p|--path)
+          projectdir=$(realpath "$2"); shift 2;;
+        --gcc=*)
+          gccincludedir=$(realpath "${1#*=}"); shift 1;;
+        --gcc)
+          gccincludedir=$(realpath "$2"); shift 2;;
+        -o=*|--out=*)
+          outvar=${1#*=}; shift 1;;
+        -o|--out)
+          outvar=$2; shift 2;;
+        --gccout=*)
+          gccoutvar=$(realpath "${1#*=}"); shift 1;;
+        --gccout)
+          gccoutvar=$(realpath "$2"); shift 2;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # print message
+  printInfo "creating QtCreator project files for the LightRing module...\n"
+
+  # read absolute project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
+
+  # retrieve absolute GCC include dir
+  if [ -z "$gccincludedir" ]; then
+    retrieveGccIncludeDir gccincludedir
+  fi
+
+  # move to project directory
+  cd $projectdir
+
+  # AMiRo-OS, ChibiOS, AMiRo-BLT and AMiRo-LLD relative root directories
+  local amiroosrootdir=$(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../../os)
+  local chibiosrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../kernel/ChibiOS)
+  local amirobltrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../bootloader/AMiRo-BLT)
+  local amirolldrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../periphery-lld/AMiRo-LLD)
+
+  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
+  find $gccincludedir -type d > ${projectdir}/LightRing.includes
+  find $amiroosrootdir -type d | grep -v "/doc\|/build\|/.dep\|/PowerManagement\|/DiWheelDrive" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/abstractions/cmsis_os$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/ext/CMSIS/(include|ST/STM32F1xx)$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/oslib/(include|src)$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/ports/ARMCMx(/compilers/GCC)?$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/startup/ARMCMx/(compilers/GCC|devices/STM32F1xx)$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/(include|src)$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/lib/streams" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/osal/(lib|rt)$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/ports/(common/ARMCMx|STM32/(LLD/(CANv1|DACv1|DMAv1|EXTIv1|GPIOv1|I2Cv1|RTCv1|SDIOv1|SPIv1|TIMv1|USARTv1|USBv1|xWDGv1)|STM32F1xx))$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/license$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/rt/(include|src)$" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/os/various/(shell|cpp_wrappers)" >> ${projectdir}/LightRing.includes
+  find $chibiosrootdir -type d | grep -E "/test/(lib|rt/source/test)$" >> ${projectdir}/LightRing.includes
+  find $amirobltrootdir -type d | grep -E "/Target/Source/AMiRo$" >> ${projectdir}/LightRing.includes
+  echo "$(realpath --relative-base=$projectdir ${amirolldrootdir}/..)" >> ${projectdir}/LightRing.includes
+  find $amirolldrootdir -type d | grep -v "/doc" >> ${projectdir}/LightRing.includes
+  # generate a file that specifies all files
+  echo -n "" > ${projectdir}/LightRing.files
+  for path in `cat ${projectdir}/LightRing.includes`; do
+    find $path -maxdepth 1 -type f \( ! -iname ".*" \) |
+      grep -Ev "^.*((/arm-none-eabi/)|(PowerManagement)|(DiWheelDrive)).*$" |
+      grep -E  "^.*(\.s|\.S|\.h|\.c|\.hpp|\.cpp|\.tpp|\.ld)$" |
+      grep -Ev "^${amiroosrootdir}/hal/ports/((STM32F[^1])|(STM32F1[^0])|(STM32F10[^3])|(STM32F103[^x])|(STM32F103x[^E])).*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ext/CMSIS/ST/STM32F1xx/((stm32f1[^0x])|(stm32f10[^3])|(stm32f103[^x])|(stm32f103x[^e])).*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ext/CMSIS/include/((core_[^c])|(core_c[^m])|(core_cm[^3A-Za-z])|(cmsis_[^g])|(cmsis_g[^c]|(cmsis_gc[^c])))" |
+      grep -Ev "^${chibiosrootdir}/os/common/ports/ARMCMx/chcore_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ports/ARMCMx/compilers/GCC/.*_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/startup/ARMCMx/compilers/GCC/.*_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/hal/ports/STM32/STM32F1xx/.*f10[^3].*$" |
+      grep -Ev "^${amirobltrootdir}/Target/Source/AMiRo/helper.*$" >> ${projectdir}/LightRing.files;
+  done
+  # generate a default project configuration file if none exists so far
+  if [ ! -f ${projectdir}/LightRing.config ]; then
+    echo "// Add predefined macros for your project here. For example:" > ${projectdir}/LightRing.config
+    echo "// #define YOUR_CONFIGURATION belongs here" >> ${projectdir}/LightRing.config
+  fi
+  # generate a default .creator file if none exists so far
+  if [ ! -f ${projectdir}/LightRing}.creator ]; then
+    echo "[general]" > ${projectdir}/LightRing.creator
+  fi
+
+  # go back to user directory
+  cd $userdir
+
+  # fill the output variables
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+  if [ ! -z "$gccoutvar" ]; then
+    eval $gccoutvar="$gccincludedir"
+  fi
+
+  return 0
+}
+
+### create PowerManagement project files #######################################
+# Create project files for the PowerManagement module.
+#
+# usage:      createPowerManagementProject [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
+# arguments:  -p, --path <path>
+#                 Path where to create the project files.
+#             --gcc=<path>
+#                 Path to the GCC include directory.
+#             -o, --out <var>
+#                 Variable to store the path to.
+#             --gccout=<var>
+#                 Variable to store the path to the GCC include directory to.
+# return:     0
+#                 No error or warning occurred.
+#
+function createPowerManagementProject {
+  local userdir=$(pwd)
+  local projectdir=""
+  local gccincludedir=""
+  local outvar=""
+  local gccoutvar=""
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -p=*|--path=*)
+          projectdir=$(realpath "${1#*=}"); shift 1;;
+        -p|--path)
+          projectdir=$(realpath "$2"); shift 2;;
+        --gcc=*)
+          gccincludedir=$(realpath "${1#*=}"); shift 1;;
+        --gcc)
+          gccincludedir=$(realpath "$2"); shift 2;;
+        -o=*|--out=*)
+          outvar=${1#*=}; shift 1;;
+        -o|--out)
+          outvar=$2; shift 2;;
+        --gccout=*)
+          gccoutvar=$(realpath "${1#*=}"); shift 1;;
+        --gccout)
+          gccoutvar=$(realpath "$2"); shift 2;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # print message
+  printInfo "creating QtCreator project files for the PowerManagement module...\n"
+
+  # read absolute project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
+
+  # retrieve absolute GCC include dir
+  if [ -z "$gccincludedir" ]; then
+    retrieveGccIncludeDir gccincludedir
+  fi
+
+  # move to project directory
+  cd $projectdir
+
+  # AMiRo-OS, ChibiOS, AMiRo-BLT and AMiRo-LLD relative root directories
+  local amiroosrootdir=$(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../../os)
+  local chibiosrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../kernel/ChibiOS)
+  local amirobltrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../bootloader/AMiRo-BLT)
+  local amirolldrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../periphery-lld/AMiRo-LLD)
+
+  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
+  find $gccincludedir -type d > ${projectdir}/PowerManagement.includes
+  find $amiroosrootdir -type d | grep -v "/doc\|/build\|/.dep\|/LightRing\|/DiWheelDrive" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/abstractions/cmsis_os$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/ext/CMSIS/(include|ST/STM32F4xx)$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/oslib/(include|src)$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/ports/ARMCMx(/compilers/GCC)?$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/startup/ARMCMx/(compilers/GCC|devices/STM32F4xx)$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/(include|src)$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/lib/streams" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/osal/(lib|rt)$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/ports/(common/ARMCMx|STM32/(LLD/(ADCv2|CANv1|DACv1|DMAv2|EXTIv1|GPIOv2|I2Cv1|MACv1|OTGv1|RTCv2|SDIOv1|SPIv1|TIMv1|USARTv1|USBv1|xWDGv1)|STM32F4xx))$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/license$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/rt/(include|src)$" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/os/various/(shell|cpp_wrappers)" >> ${projectdir}/PowerManagement.includes
+  find $chibiosrootdir -type d | grep -E "/test/(lib|rt/source/test)$" >> ${projectdir}/PowerManagement.includes
+  find $amirobltrootdir -type d | grep -E "/Target/Source/AMiRo$" >> ${projectdir}/PowerManagement.includes
+  echo "$(realpath --relative-base=$projectdir ${amirolldrootdir}/..)" >> ${projectdir}/PowerManagement.includes
+  find $amirolldrootdir -type d | grep -v "/doc" >> ${projectdir}/PowerManagement.includes
+  # generate a file that specifies all files
+  echo -n "" > ${projectdir}/PowerManagement.files
+  for path in `cat ${projectdir}/PowerManagement.includes`; do
+    find $path -maxdepth 1 -type f \( ! -iname ".*" \) |
+      grep -Ev "^.*((/arm-none-eabi/)|(LightRing)|(DiWheelDrive)).*$" |
+      grep -E  "^.*(\.s|\.S|\.h|\.c|\.hpp|\.cpp|\.tpp|\.ld)$" |
+      grep -Ev "^${amiroosrootdir}/hal/ports/((STM32F[^4])|(STM32F4[^0])|(STM32F40[^5])|(STM32F405[^x])|(STM32F405x[^G])).*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ext/CMSIS/ST/STM32F4xx/((stm32f4[^0x])|(stm32f40[^5])).*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ext/CMSIS/include/((core_[^c])|(core_c[^m])|(core_cm[^4A-Za-z])|(cmsis_[^g])|(cmsis_g[^c]|(cmsis_gc[^c])))" |
+      grep -Ev "^${chibiosrootdir}/os/common/ports/ARMCMx/chcore_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ports/ARMCMx/compilers/GCC/.*_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/startup/ARMCMx/compilers/GCC/.*_v[^7]m.*$" |
+      grep -Ev "^${amirobltrootdir}/Target/Source/AMiRo/helper.*$" >> ${projectdir}/PowerManagement.files;
+  done
+  # generate a default project configuration file if none exists so far
+  if [ ! -f ${projectdir}/PowerManagement.config ]; then
+    echo "// Add predefined macros for your project here. For example:" > ${projectdir}/PowerManagement.config
+    echo "// #define YOUR_CONFIGURATION belongs here" >> ${projectdir}/PowerManagement.config
+  fi
+  # generate a default .creator file if none exists so far
+  if [ ! -f ${projectdir}/PowerManagement.creator ]; then
+    echo "[general]" > ${projectdir}/PowerManagement.creator
+  fi
+
+  # go back to user directory
+  cd $userdir
+
+  # fill the output variables
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+  if [ ! -z "$gccoutvar" ]; then
+    eval $gccoutvar="$gccincludedir"
+  fi
+
+  return 0
+}
+
+### create DiWheelDrive project files ##########################################
+# Create project files for the DiWheelDrive module.
+#
+# usage:      createDiWheelDriveProject [-p|--path=<path>] [--gcc=<path>] [-o|--out=<var>] [--gccout=<var>]
+# arguments:  -p, --path <path>
+#                 Path where to create the project files.
+#             --gcc=<path>
+#                 Path to the GCC include directory.
+#             -o, --out <var>
+#                 Variable to store the path to.
+#             --gccout=<var>
+#                 Variable to store the path to the GCC include directory to.
+# return:     0
+#                 No error or warning occurred.
+#
+function createDiWheelDriveProject {
+  local userdir=$(pwd)
+  local projectdir=""
+  local gccincludedir=""
+  local outvar=""
+  local gccoutvar=""
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -p=*|--path=*)
+          projectdir=$(realpath "${1#*=}"); shift 1;;
+        -p|--path)
+          projectdir=$(realpath "$2"); shift 2;;
+        --gcc=*)
+          gccincludedir=$(realpath "${1#*=}"); shift 1;;
+        --gcc)
+          gccincludedir=$(realpath "$2"); shift 2;;
+        -o=*|--out=*)
+          outvar=${1#*=}; shift 1;;
+        -o|--out)
+          outvar=$2; shift 2;;
+        --gccout=*)
+          gccoutvar=$(realpath "${1#*=}"); shift 1;;
+        --gccout)
+          gccoutvar=$(realpath "$2"); shift 2;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # print message
+  printInfo "creating QtCreator project files for the DiWheelDrive module...\n"
+
+  # read absolute project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
+
+  # retrieve absolute GCC include dir
+  if [ -z "$gccincludedir" ]; then
+    retrieveGccIncludeDir gccincludedir
+  fi
+
+  # move to project directory
+  cd $projectdir
+
+  # AMiRo-OS, ChibiOS, AMiRo-BLT and AMiRo-LLD relative root directories
+  local amiroosrootdir=$(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../../os)
+  local chibiosrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../kernel/ChibiOS)
+  local amirobltrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../bootloader/AMiRo-BLT)
+  local amirolldrootdir=$(realpath --relative-base=$projectdir ${amiroosrootdir}/../periphery-lld/AMiRo-LLD)
+
+  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
+  find $gccincludedir -type d > ${projectdir}/DiWheelDrive.includes
+  find $amiroosrootdir -type d | grep -v "/doc\|/build\|/.dep\|/LightRing\|/PowerManagement" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/abstractions/cmsis_os$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/ext/CMSIS/(include|ST/STM32F1xx)$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/oslib/(include|src)$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/ports/ARMCMx(/compilers/GCC)?$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/common/startup/ARMCMx/(compilers/GCC|devices/STM32F1xx)$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/(include|src)$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/lib/streams" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/osal/(lib|rt)$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/hal/ports/(common/ARMCMx|STM32/(LLD/(CANv1|DACv1|DMAv1|EXTIv1|GPIOv1|I2Cv1|RTCv1|SDIOv1|SPIv1|TIMv1|USARTv1|USBv1|xWDGv1)|STM32F1xx))$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/license$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/rt/(include|src)$" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/os/various/(shell|cpp_wrappers)" >> ${projectdir}/DiWheelDrive.includes
+  find $chibiosrootdir -type d | grep -E "/test/(lib|rt/source/test)$" >> ${projectdir}/DiWheelDrive.includes
+  find $amirobltrootdir -type d | grep -E "/Target/Source/AMiRo$" >> ${projectdir}/DiWheelDrive.includes
+  echo "$(realpath --relative-base=$projectdir ${amirolldrootdir}/..)" >> ${projectdir}/DiWheelDrive.includes
+  find $amirolldrootdir -type d | grep -v "/doc" >> ${projectdir}/DiWheelDrive.includes
+  # generate a file that specifies all files
+  echo -n "" > ${projectdir}/DiWheelDrive.files
+  for path in `cat ${projectdir}/DiWheelDrive.includes`; do
+    find $path -maxdepth 1 -type f \( ! -iname ".*" \) |
+      grep -Ev "^.*((/arm-none-eabi/)|(LightRing)|(PowerManagement)).*$" |
+      grep -E  "^.*(\.s|\.S|\.h|\.c|\.hpp|\.cpp|\.tpp|\.ld)$" |
+      grep -Ev "^${amiroosrootdir}/hal/ports/((STM32F[^1])|(STM32F1[^0])|(STM32F10[^3])|(STM32F103[^x])|(STM32F103x[^E])).*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ext/CMSIS/ST/STM32F1xx/((stm32f1[^0x])|(stm32f10[^3])|(stm32f103[^x])|(stm32f103x[^e])).*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ext/CMSIS/include/((core_[^c])|(core_c[^m])|(core_cm[^3A-Za-z])|(cmsis_[^g])|(cmsis_g[^c]|(cmsis_gc[^c])))" |
+      grep -Ev "^${chibiosrootdir}/os/common/ports/ARMCMx/chcore_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/ports/ARMCMx/compilers/GCC/.*_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/common/startup/ARMCMx/compilers/GCC/.*_v[^7]m.*$" |
+      grep -Ev "^${chibiosrootdir}/os/hal/ports/STM32/STM32F1xx/.*f10[^3].*$" |
+      grep -Ev "^${amirobltrootdir}/Target/Source/AMiRo/helper.*$" >> ${projectdir}/DiWheelDrive.files;
+  done
+  # generate a default project configuration file if none exists so far
+  if [ ! -f ${projectdir}/DiWheelDrive.config ]; then
+    echo "// Add predefined macros for your project here. For example:" > ${projectdir}/DiWheelDrive.config
+    echo "// #define YOUR_CONFIGURATION belongs here" >> ${projectdir}/DiWheelDrive.config
+  fi
+  # generate a default .creator file if none exists so far
+  if [ ! -f ${projectdir}/DiWheelDrive.creator ]; then
+    echo "[general]" > ${projectdir}/DiWheelDrive.creator
+  fi
+
+  # go back to user directory
+  cd $userdir
+
+  # fill the output variables
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+  if [ ! -z "$gccoutvar" ]; then
+    eval $gccoutvar="$gccincludedir"
+  fi
+
+  return 0
+}
+
+### create project files for all modules #######################################
+# Create project files for all modules.
+#
+# usage:      createAllProjects
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function createAllProjects {
+  # print message
+  printInfo "creating QtCreator project files for the DiWheelDrive module...\n"
+
+  # read project directory
+  local projectdir=""
+  getProjectDir projectdir
+  printInfo "files will be created in $projectdir\n"
+
+  # retrieve gcc-arm-none-eabi include dir
+  retrieveGccIncludeDir gccincludedir
+
+  # create projects
+  createLightRingProject --path="$projectdir" --gcc="$gccincludedir"
+  createPowerManagementProject --path="$projectdir" --gcc="$gccincludedir"
+  createDiWheelDriveProject --path="$projectdir" --gcc="$gccincludedir"
+
+  return 0
+}
+
+### main function of this script ###############################################
+# Creates, deletes and wipes QtCreator project files for the three AMiRo base modules.
+#
+# usage:      see function printHelp
+# arguments:  see function printHelp
+# return:     0
+#                 No error or warning ocurred.
+#
+function main {
+# print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  printf "\n"
+
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
+
+  # set log file if specified
+  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
+    # get the parameter (file name)
+    local cmdidx=1
+    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
+      cmdidx=$[cmdidx + 1]
+    done
+    local cmd="${!cmdidx}"
+    local logfile=""
+    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
+      logfile=${cmd#*=}
+    else
+      local filenameidx=$((cmdidx + 1))
+      logfile="${!filenameidx}"
+    fi
+    # optionally force silent appending
+    if [[ "$cmd" = "--LOG"* ]]; then
+      setLogFile --option=c --quiet "$logfile" LOG_FILE
+    else
+      setLogFile "$logfile" LOG_FILE
+      printf "\n"
+    fi
+  fi
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -c|--clean)
+          deleteProjects; printf "\n"; shift 1;;
+        -w|--wipe)
+          deleteProjects --wipe; printf "\n"; shift 1;;
+        --LightRing)
+          createLightRingProject; printf "\n"; shift 1;;
+        --PowerManagement)
+          createPowerManagementProject; printf "\n"; shift 1;;
+        --DiWheelDrive)
+          createDiWheelDriveProject; printf "\n"; shift 1;;
+        -a|--all)
+          createAllProjects; printf "\n"; shift 1;;
+        -q|--quit)
+          quitScript; shift 1;;
+        --log=*|--LOG=*) # already handled; ignore
+          shift 1;;
+        --log|--LOG) # already handled; ignore
+          shift 2;;
+        --noinfo) # already handled; ignore
+          shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "QtCreator setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [C] - clean project files\n"
+    printf "  [W] - wipe project and .user files\n"
+    printf "  [L] - create a project for the LightRing module\n"
+    printf "  [P] - create a project for the PowerManagement module\n"
+    printf "  [D] - create a project for the DiWheelDrive module\n"
+    printf "  [A] - create a project for all modules\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "CcWwLlPpDdAaQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      C|c)
+        deleteProjects; printf "\n";;
+      W|w)
+        deleteProjects --wipe; printf "\n";;
+      L|l)
+        createLightRingProject; printf "\n";;
+      P|p)
+        createPowerManagementProject; printf "\n";;
+      D|d)
+        createDiWheelDriveProject; printf "\n";;
+      A|a)
+        createAllProjects; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
+
diff --git a/tools/ide/QtCreator/README.txt b/tools/ide/QtCreator/README.txt
new file mode 100644
index 0000000..1c6e9d4
--- /dev/null
+++ b/tools/ide/QtCreator/README.txt
@@ -0,0 +1,115 @@
+AMiRo-OS support the QtCreator IDE and provides tools and manuals to setup the
+according project files.
+
+Copyright (C) 2016..2018  Thomas Schöpping
+
+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).
+
+
+
+################################################################################
+#                                                                              #
+#        RRRRRRRR   EEEEEEEE     AAA     DDDDDDDD   MM     MM  EEEEEEEE        #
+#        RR     RR  EE          AA AA    DD     DD  MMM   MMM  EE              #
+#        RR     RR  EE         AA   AA   DD     DD  MMMM MMMM  EE              #
+#        RRRRRRRR   EEEEEE    AA     AA  DD     DD  MM MMM MM  EEEEEE          #
+#        RR   RR    EE        AAAAAAAAA  DD     DD  MM     MM  EE              #
+#        RR    RR   EE        AA     AA  DD     DD  MM     MM  EE              #
+#        RR     RR  EEEEEEEE  AA     AA  DDDDDDDD   MM     MM  EEEEEEEE        #
+#                                                                              #
+################################################################################
+
+This file will help you to setup QtCreator projects for the operating system of
+the three basic AMiRo modules and more. It also provides instructions how to
+integrate the GCC ARM embedded toolchain into the IDE.
+
+================================================================================
+
+CONTENTS:
+
+  1  Setting up QtCreator Projects
+  2  Integration of the Toolchain
+    2.1  Toolkit Setup
+    2.2  Project Integration
+
+================================================================================
+
+
+
+1 - SETTING UP QtCreator PROJECTS
+---------------------------------
+
+To automatically generate all required files for QtCreator, run the provided
+./setup.sh script and follow the instruction. You then just have to open the
+*.creator files with the IDE.
+
+
+
+2 - INTEGRATION OF THE TOOLCHAIN
+--------------------------------
+
+In order to integrate the compiler and flashing tools into your IDE, some
+further actions are required.
+
+
+2.1 Toolkit Setup
+-----------------
+
+Start by launching the QtCreator application, open the Tools->Options settings
+and select "Build & Run". Under the tab "Compilers" add the installed
+arm-none-eabi-g++ compiler as another GCC. Under the tab "Debuggers" add the
+according arm-none-eabi-gdb debugger. Under the tab "Kits" you need to manually
+create a new kit with the following settings:
+
+  Name: AMiRo
+  Device type: Desktop
+  Sysroot: <gcc-arm-none-eabi include path>
+  Compiler: <the compiler added above>
+  Debugger: <the debugger added above>
+  QT version: none
+
+Keep any other fields at their default values. If there is a warning sign shown
+beside the new kit, check the settings for errors.
+
+
+2.2 Project Integration
+-----------------------
+
+For convenience, the absolute path to your module (e.g.
+/home/juser/amiro-os/os/modules/PowerManagement) will be referenced in the
+following as "MOD_PATH".
+
+After you have sucessfully created the project files (see section 1), open the
+projects by selecting the *.creator files with QtCreator. Select the "Projects"
+icon at the very left and switch to the "Build & Run" tab. Change the used kit
+to "AMiRo" (right above the "Build" and "Run" buttons).
+
+Next, add a new build configuration and call it "make":
+
+  Build directory: MOD_PATH
+  Build Steps: make --directory=MOD_PATH all
+  Clean Steps: make --directory=MOD_PATH clean
+
+Optionally, you can add "-j" to the build setp in order to parallelize the
+compilation process. Add yet another build configuration by clonung the "make"
+configuration and name it "make flash". For this copy, replace "all" at the end
+of the build step with "flash". Finally remove the "Default" configuration and
+repeat these steps for any further projects.
+
+================================================================================
+
diff --git a/tools/ide/idesetup.sh b/tools/ide/idesetup.sh
new file mode 100755
index 0000000..eef3902
--- /dev/null
+++ b/tools/ide/idesetup.sh
@@ -0,0 +1,440 @@
+################################################################################
+# 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).                              #
+################################################################################
+
+#!/bin/bash
+
+################################################################################
+# GENERIC FUNCTIONS                                                            #
+################################################################################
+
+### print an error message #####################################################
+# Prints a error <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printError <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printError {
+  local string="ERROR:   $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a warning message ####################################################
+# Prints a warning <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printMessage <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printWarning {
+  local string="WARNING: $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)"
+}
+
+### print an information message ###############################################
+# Prints an information <message> to standard output.
+#If variable 'LOG_FILE' is specified, the message is also appended to the given file.
+#
+# usage:      printInfo <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printInfo {
+  local string="INFO:    $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)"
+}
+
+### print a message to file ####################################################
+# Appends a <message> to a log file, specified by the variable 'LOG_FILE'.
+#
+# usage       printLog <message>
+# arguments:  <message>
+#                 Message string to print.
+# return:     n/a
+#
+function printLog {
+  local string="LOG:     $1"
+  # if a log file is specified
+  if [ -n "$LOG_FILE" ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+}
+
+### exit the script normally ###################################################
+# Prints a delimiter and exits the script normally (returns 0).
+#
+# usage:      quitScript
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
+  exit 0
+}
+
+### read a user input ##########################################################
+# Reads a single character user input from a set up <options> and stores it in
+# a given <return> variable.
+#
+# usage:      readUserInput <options> <return>
+# arguments:  <options>
+#                 String definiing the set of valid characters.
+#                 If the string is empty, the user can input any character.
+#             <return>
+#                 Variable to store the selected character to.
+# return:     n/a
+#
+function readUserInput {
+  local input=""
+  # read user input
+  while [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); do
+    read -p "your selection: " -n 1 -e input
+    if [ -z $input ] || ( [ -n "$1" ] && [[ ! $input =~ ^[$1]$ ]] ); then
+      printWarning "[$input] is no valid action\n"
+    fi
+  done
+  printLog "[$input] has been selected\n"
+  eval $2="$input"
+}
+
+### check whether argument is an option ########################################
+# Checks a <string> whether it is an option.
+# Options are defined to either start with '--' followed by any string, or
+# to start with a single '-' followed by a single character, or
+# to start with a single '-' followed by a single character, a '=' and any string.
+# Examples: '--option', '--option=arg', '-o', '-o=arg', '--'
+#
+# usage:      parseIsOption <string>
+# arguments:  <string>
+#                 A string to check whether it is an option.
+# return:     0
+#                 <string> is an option.
+#             -1
+#                 <string> is not an option.
+#
+function parseIsOption {
+  if [[ "$1" =~ ^-(.$|.=.*) ]] || [[ "$1" =~ ^--.* ]]; then
+    return 0
+  else
+    return -1
+  fi
+}
+
+### set the log file ###########################################################
+# Sets a specified <infile> as log file and checks whether it already exists.
+# If so, the log may either be appended to the file, its content can be cleared,
+# or no log is generated at all.
+# The resulting path is stored in <outvar>.
+#
+# usage:      setLogFile [--option=<option>] [--quiet] <infile> <outvar>
+# arguments:  --option=<option>
+#                 Select what to do if <file> already exists.
+#                 Possible values are 'a', 'c', 'r' and 'n'.
+#                 - a: append (starts with a separator)
+#                 - c: continue (does not insert a seperator)
+#                 - r: delete and restart
+#                 - n: no log
+#                 If no option is secified but <file> exists, an interactive selection is provided.
+#             --quiet
+#                 Suppress all messages.
+#             <infile>
+#                 Path of the wanted log file.
+#             <outvar>
+#                 Variable to store the path of the log file to.
+# return:     0
+#                 No error or warning occurred.
+#             -1
+#                 Error: invalid input
+#
+function setLogFile {
+  local filepath=""
+  local option=""
+  local quiet=false
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -o=*|--option=*)
+          option=${1#*=}; shift 1;;
+        -o*|--option*)
+          option="$2"; shift 2;;
+        -q|--quiet)
+          quiet=true; shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+  filepath=$(realpath ${otherargs[0]})
+
+  # if file already exists
+  if [ -e $filepath ]; then
+    # if no option was specified, ask what to do
+    if [ -z "$option" ]; then
+      printWarning "log file $filepath already esists\n"
+      local userinput=""
+      printf "Select what to do:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput "AaRrNn" userinput
+      option=${userinput,,}
+    fi
+    # evaluate option
+    case "$option" in
+      a|c)
+        if [ $quiet = false ]; then
+          printInfo "appending log to $filepath\n"
+        fi
+        if [ $option != c ]; then
+          printf "\n" >> $filepath
+          printf "######################################################################\n" >> $filepath
+          printf "\n" >> $filepath
+        fi
+        ;;
+      r)
+        echo -n "" > $filepath
+        if [ $quiet = false ]; then
+          printInfo "content of $filepath wiped\n"
+        fi
+        ;;
+      n)
+        if [ $quiet = false ]; then
+          printInfo "no log file will be generated\n"
+        fi
+        filepath=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $option\n"; return -1;;
+    esac
+  else
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
+  fi
+
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
+}
+
+################################################################################
+# SPECIFIC FUNCTIONS                                                           #
+################################################################################
+
+### print welcome text #########################################################
+# Prints a welcome message to standard out.
+#
+# usage:      printWelcomeText
+# arguments:  n/a
+# return:     n/a
+#
+function printWelcomeText {
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "#                 Welcome to the AMiRo-OS IDE setup!                 #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+  printf "#                                                                    #\n"
+  printf "# Copyright (c) 2016..2018  Thomas Schöpping                         #\n"
+  printf "#                                                                    #\n"
+  printf "# This is free software; see the source for copying conditions.      #\n"
+  printf "# There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR  #\n"
+  printf "# A PARTICULAR PURPOSE. The development of this software was         #\n"
+  printf "# supported by the Excellence Cluster EXC 227 Cognitive Interaction  #\n"
+  printf "# Technology. The Excellence Cluster EXC 227 is a grant of the       #\n"
+  printf "# Deutsche Forschungsgemeinschaft (DFG) in the context of the German #\n"
+  printf "# Excellence Initiative.                                             #\n"
+  printf "#                                                                    #\n"
+  printf "######################################################################\n"
+}
+
+### print help #################################################################
+# Prints a help text to standard out.
+#
+# usage:      printHelp
+# arguments:  n/a
+# return:     n/a
+#
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:    $(basename ${BASH_SOURCE[0]}) [-h|--help] [--QtCreator] [-q|--quit] [--log=<file>]\n"
+  printf "\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          --QtCreator\n"
+  printf "              Enter QtCreator setup.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### enter QtCreator setup ######################################################
+# Enter the QtCreator IDE setup.
+#
+# usage:      qtCreatorSetup
+# arguments:  n/a
+# return:     n/a
+function qtCreatorSetup {
+  printInfo "entering QtCreator setup...\n"
+  printf "\n"
+  if [ -z "$LOG_FILE" ]; then
+    $(realpath $(dirname ${BASH_SOURCE[0]}))/QtCreator/QtCreatorSetup.sh --noinfo
+  else
+    $(realpath $(dirname ${BASH_SOURCE[0]}))/QtCreator/QtCreatorSetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
+
+### main function of this script ###############################################
+# The IDE setup lets the user select an IDE of choice.
+# As of now, only QtCreator is supported.
+#
+# usage:      see function printHelp
+# arguments:  see function printHelp
+# return:     0
+#                 No error or warning occurred.
+#
+function main {
+  # print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  printf "\n"
+
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
+
+  # set log file if specified
+  if [[ $@ == *"--log"* ]] || [[ $@ == *"--LOG"* ]]; then
+    # get the parameter (file name)
+    local cmdidx=1
+    while [[ ! "${!cmdidx}" = "--log"* ]] && [[ ! "${!cmdidx}" = "--LOG"* ]]; do
+      cmdidx=$[cmdidx + 1]
+    done
+    local cmd="${!cmdidx}"
+    local logfile=""
+    if [[ "$cmd" = "--log="* ]] || [[ "$cmd" = "--LOG="* ]]; then
+      logfile=${cmd#*=}
+    else
+      local filenameidx=$((cmdidx + 1))
+      logfile="${!filenameidx}"
+    fi
+    # optionally force silent appending
+    if [[ "$cmd" = "--LOG"* ]]; then
+      setLogFile --option=c --quiet "$logfile" LOG_FILE
+    else
+      setLogFile "$logfile" LOG_FILE
+      printf "\n"
+    fi
+  fi
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        --QtCreator)
+          qtCreatorSetup; printf "\n"; shift 1;;
+        -q|--quit)
+          quitScript; printf "\n"; shift 1;;
+        --log=*|--LOG=*) # already handled; ignore
+          shift 1;;
+        --log|--LOG) # already handled; ignore
+          shift 2;;
+        --noinfo) # already handled; ignore
+          shift 1;;
+        *)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "AMiRo-OS IDE setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [C] - enter QtCreator setup\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "CcQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      C|c)
+        qtCreatorSetup; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
