commit 6feb42c8cc2d17d4b1aff4bd482ba7b88b3f872d
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Fri Feb 9 13:48:18 2018 +0100

    Patch 1.0.1:
    
    - Introduced target/Makefile for conventient building and flashing from a single location.
    - Added stm32flash (version 0.5) as Git submodule.
    - Enhancements to the various bash scripts. Most of all, these scripts can now be executed from arbitrary location.

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..6dfff5f
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "Host/stm32flash"]
+	path = Host/Source/stm32flash
+	url = https://git.code.sf.net/p/stm32flash/code
diff --git a/Host/Source/SerialBoot/main.c b/Host/Source/SerialBoot/main.c
index 0370812..a41964d 100644
--- a/Host/Source/SerialBoot/main.c
+++ b/Host/Source/SerialBoot/main.c
@@ -215,7 +215,7 @@ static void DisplayProgramInfo(void)
   printf("Copyright (c) by Feaser  http://www.feaser.com                             \n");
   printf("---------------------------------------------------------------------------\n");
   printf("This tool was modified for the 'Autonomous Mini Robot' - AMiRo.            \n");
-  printf("Copyright (c) 2016..2017  Marvin Barther, Thomas Schoepping, and Stefan    \n");
+  printf("Copyright (c) 2016..2018  Marvin Barther, Thomas Schoepping, and Stefan    \n");
   printf("                          Herbrechtsmeier                                  \n");
   printf("This is free software; see the source for copying conditions. There is NO  \n");
   printf("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
diff --git a/Host/Source/stm32flash b/Host/Source/stm32flash
new file mode 160000
index 0000000..1f934ae
--- /dev/null
+++ b/Host/Source/stm32flash
@@ -0,0 +1 @@
+Subproject commit 1f934ae86babdeea47afdfae1d856d5fd5da6c53
diff --git a/README.txt b/README.txt
index 372f6d6..04bd038 100644
--- a/README.txt
+++ b/README.txt
@@ -1,8 +1,8 @@
 AMiRo-BLT is the bootloader and flashing toolchain for the base version of the
-Autonomous Mini Robot (AMiRo) [1,2]. It is based on OpenBLT developed by Feaser
+Autonomous Mini Robot (AMiRo) [1]. It is based on OpenBLT developed by Feaser
 (see <http://feaser.com/en/openblt.php>).
 
-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,17 +24,15 @@ University, which is funded by the German Research Foundation (DFG).
 
 Authors:
  - Thomas Schöpping        <tschoepp[at]cit-ec.uni-bielefeld.de>
- - Stefan Herbechtsmeier   <sherbrec[at]cit-ec.uni-bielefeld.de>
+ - Stefan Herbrechtsmeier  <sherbrec[at]cit-ec.uni-bielefeld.de>
  - Marvin Barther
 
 References:
- [1] Herbrechtsmeier S., Rückert U., & Sitte J. (2012). "AMiRo - Autonomous Mini
-     Robot for Research and Education". In Advances in Autonomous Mini Robots
-     (pp. 101-112). Springer Berlin Heidelberg.
- [2] Schöpping T., Korthals T., Herbrechtsmeier S., & Rückert U. (2015). "AMiRo:
-     A Mini Robot for Scientific Applications" In Advances in Computational
-     Intelligence (pp. 199-205). Springer International Publishing.
- 
+ [1] S. Herbrechtsmeier, T. Korthals, T. Schopping and U. Rückert, "AMiRo: A
+     modular & customizable open-source mini robot platform," 2016 20th
+     International Conference on System Theory, Control and Computing (ICSTCC),
+     Sinaia, 2016, pp. 687-692.
+
 
 
 ################################################################################
@@ -58,14 +56,16 @@ AMiRo base modules.
 CONTENTS:
 
   1  Required software
-    1.1  stm32flash
-    1.2  GCC ARM Embedded Toolchain
-    1.3  GNU Make
-    1.4  CMake
+    1.1  Git
+    1.2  GNU Make
+    1.3  GCC
+    1.4  stm32flash
+    1.5  GCC ARM Embedded Toolchain
+    1.6  CMake
   2  Recommended Software
   3  Compiling the source code
-    3.1  target software
-    3.2  host software
+    3.1  host software
+    3.2  target software
 
 ================================================================================
 
@@ -80,41 +80,67 @@ with the microcontrollers (MCUs) of AMiRo, the former is used to write this data
 to the hardware.
 
 
+1.1 - Git
+---------
+
+Since all main- and subprojects are available as Git repositories, installing a
+recent version of the tool is mandatory.
+
+
+1.2 - GNU Make
+--------------
+
+GNU Make usually comes as preinstalled tool on Ubuntu based operating systems.
+If your system is missing GNU Make, it is recommended to install it from the
+standard repositories since no special requirements (e.g. features of a very
+recent version) are required.
+
 
-1.1 - stm32flash
+1.3 - GCC
+---------
+
+In order to build some required tools from source, GCC is required. It usually
+comes as preinstalled tool on Ubuntu based operating systems. If your system is
+missing GCC, it is recommended to install it from the standard repositories
+since no special requirements (e.g. features of a very recent version) are
+required.
+
+
+1.4 - stm32flash
 ----------------
 
-To build the tool from source, clone the GIT repository to a local folder on
-your machine:
-  >$ git clone git://git.code.sf.net/p/stm32flash/code
-Make sure that you have selected version 0.4 or later of the tool. You can now
-build the tool simply by executing 'make'. Finally, you must make the resulting
-binary (stm32flash) globally available in your environment. You can do so by
-either copying the file to an appropriate location (e.g. /usr/local/bin/) or
-creating an according link. The tool must be available as 'stm32flash' in every
-new shell.
+This tool is required to flash the bootloader binaries to the microcontrollers.
+Since it is included in this project as a submodule, you can just run the setup
+script in the root directory:
+  >$ ./setup.sh
+Follow the instructions to download the source code and compile the tool. The
+resulting binary path is ./Host/Source/stm32flash/stm32flash. Other scripts that
+require stm32flash will search for the binary at this location by default.
 
+The setup script does not install the tool to your system path, though, since
+this usually requires root permissions. However, stm32flash provides a Makefile
+with installation capabilities. Just Follow the instructions given in the file
+./Host/Source/stm32flash/INSTALL.
 
-1.2 - GCC ARM Embedded Toolchain
+
+1.5 - GCC ARM Embedded Toolchain
 --------------------------------
 
 Various versions of the GCC for ARM embedded devices can be found at
 <https://launchpad.net/gcc-arm-embedded>. For installation of the compiler
-toolchain, please follow the instructions that can be found on the web page.
-If you have access to the AMiRo-OS project as well, it is highly recommended
-to use the setup application provided there.
-
+toolchain and managing of multiple versions, it is highly recommended to use the
+provided setup script. Alternatively you can install the compiler manually by
+following the instructions that can be found on the web page.
 
-1.3 - GNU Make
---------------
-
-GNU Make usually comes as preinstalled tool on Ubuntu based operating systems.
-If your system is missing GNU Make, it is recommended to install it from the
-standard repositories since no special requirements (e.g. features of a very
-recent version) are required.
+If you are running a 64-bit operating system, you may 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
 
 
-1.4 - CMake
+1.6 - CMake
 -----------
 
 In order to build the SerialBoot host application, CMake version 2.8 or later is
@@ -146,7 +172,21 @@ accessible when the robot is fully set up, this enables to update the firmware
 even for other modules.
 
 
-3.1 - target software
+3.1 - host software
+-------------------
+
+The stm32flash tool is requried to flash bootloader binaries to the MCUs.
+Instructions for builing the tool are given in chapter 1.4 of this file.
+
+The SerialBoot tool can be built by using cmake. The according CMakeLists.txt
+file can be found in the ./Host/Source/SerialBoot/ directory. To ensure
+compatibility with other software (e.g. AMiRo-OS) it is higly recommended to use
+the provided ./setup.sh script to build SerialBoot. In the end the binary path
+should be ./Host/Source/SerialBoot/build/SerialBoot, which is the default for
+any scripts and tools that use SerialBoot.
+
+
+3.2 - target software
 ---------------------
 
 In the ./Target/Demo/ directory there are three subfolders, one for each AMiRo
@@ -155,32 +195,40 @@ base module. Within each of these is an additional Boot/ folder
 be compiled by executing 'make' in these directories.
 
 In order to flash the bootloader to a microcontroller, you first have to set
-full read and write permissions to the USB ports of your system. You can do so
-by executing the following command:
-  >$ sudo echo 'KERNEL=="ttyUSB[0-9]*",NAME="tts/USB%n",SYMLINK+="%k",MODE="0666"' > /etc/udev/rules.d/50-ttyusb.rules
+full read and write permissions to the USB ports of your system. To do so, first
+create a new file by executing the following command:
+  >$ sudo touch /etc/udev/rules.d/50-usb-serial.rules
+Open the file in a text editor of your choice (sudo required) and add the
+following lines:
+
+  # Future Technology Devices International Ltd. - TTL-232RG
+  SUBSYSTEMS=="usb", ACTION=="add", KERNEL=="ttyUSB[0-9]*",
+  ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666"
+
+  # Future Technology Devices International Ltd. - FT231X
+  SUBSYSTEMS=="usb", ACTION=="add", KERNEL=="ttyUSB[0-9]*",
+  ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE="0666"
+
 Now connect the module you want to flash directly to your system (note that
 indirect flashing is not possible for the bootloader itself) and run the command
   >$ make flash
 If the procedure was not successful, the following hints might help:
+  - Did your system apply the new udev rules?
+    Reboot and try again!
   - Could the makefile execute the stm32flash tool?
+    Reinitialize the submodule and try again!
   - Are the permissions for USB ports set correctly?
+    Check the udev rules!
   - Are there any other applications using the serial connection?
+    Close any other applications using the serial connection!
   - Is the AMiRo module connected to your system?
+    Use the programming cable to connect the module to your system.
   - Is the AMiRo module powered up?
+    Keep a charger plugged in during flashing.
 
 ATTENTION:
 Never flash a bootloader to the wrong module! Doing so might cause severe errors
 and damage the robot.
 
-
-3.2 - host software
--------------------
-
-The SerialBoot tool can be built by using cmake. The according CMakeLists.txt
-file can be found in the ./Host/Source/SerialBoot/ directory. To ensure
-compatibility with other software (e.g. AMiRo-OS) it is higly recommended to use
-the provided ./setup.sh script to build SerialBoot. In the end the binary path
-should be ./Host/Sotware/SerialBoot/build/SerialBoot.
-
 ================================================================================
 
diff --git a/Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot/main.c b/Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot/main.c
index 91ed292..dbe643f 100644
--- a/Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot/main.c
+++ b/Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot/main.c
@@ -170,7 +170,7 @@ void blCallbackHandleShutdownRequest(void);
 
 const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
   .magicNumber = BL_MAGIC_NUMBER,
-  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 0},
+  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 1},
   .vSSSP = {BL_VERSION_ID_SSSP, SSSP_VERSION_MAJOR, SSSP_VERSION_MINOR, 0},
   .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
   .cbShutdownHibernate = blCallbackShutdownHibernate,
diff --git a/Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot/main.c b/Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot/main.c
index 7189013..02c94bd 100644
--- a/Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot/main.c
+++ b/Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot/main.c
@@ -140,7 +140,7 @@ void blCallbackHandleShutdownRequest(void);
 
 const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
   .magicNumber = BL_MAGIC_NUMBER,
-  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 0},
+  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 1},
   .vSSSP = {BL_VERSION_ID_SSSP, SSSP_VERSION_MAJOR, SSSP_VERSION_MINOR, 0},
   .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
   .cbShutdownHibernate = blCallbackShutdownHibernate,
diff --git a/Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot/main.c b/Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot/main.c
index af10977..b3f02c3 100644
--- a/Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot/main.c
+++ b/Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot/main.c
@@ -193,7 +193,7 @@ void blCallbackHandleShutdownRequest(void);
 
 const blCallbackTable_t cbtable __attribute__ ((section ("_callback_table"))) = {
   .magicNumber = BL_MAGIC_NUMBER,
-  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 0},
+  .vBootloader = {BL_VERSION_ID_AMiRoBLT_Release, BL_VERSION_MAJOR, BL_VERSION_MINOR, 1},
   .vSSSP = {BL_VERSION_ID_SSSP, SSSP_VERSION_MAJOR, SSSP_VERSION_MINOR, 0},
   .vCompiler = {BL_VERSION_ID_GCC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__},  // currently only GCC is supported
   .cbShutdownHibernate = blCallbackShutdownHibernate,
diff --git a/Target/Demo/flash.mk b/Target/Demo/flash.mk
index 06b0141..ea49a09 100644
--- a/Target/Demo/flash.mk
+++ b/Target/Demo/flash.mk
@@ -1,4 +1,4 @@
-STM32FLASH = stm32flash
+STM32FLASH := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))../../Host/Source/stm32flash/stm32flash
 ifeq ($(OS),Windows_NT)
 	STM32FLASH_PORT ?= COM5
 else
diff --git a/Target/Makefile b/Target/Makefile
new file mode 100644
index 0000000..084801f
--- /dev/null
+++ b/Target/Makefile
@@ -0,0 +1,59 @@
+################################################################################
+# AMiRo-BLT is the bootloader and flashing toolchain for the base version of   #
+# the Autonomous Mini Robot (AMiRo). It is based on OpenBLT developed by       #
+# Feaser (see <http://feaser.com/en/openblt.php>).                             #
+# 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).                              #
+################################################################################
+
+
+
+ROOT_PATH = ..
+DWD_PATH = $(ROOT_PATH)/Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot
+PM_PATH = $(ROOT_PATH)/Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot
+LR_PATH = $(ROOT_PATH)/Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot
+
+all:
+	$(MAKE) -C $(DWD_PATH)
+	$(MAKE) -C $(PM_PATH)
+	$(MAKE) -C $(LR_PATH)
+
+clean:
+	$(MAKE) -C $(DWD_PATH) clean
+	$(MAKE) -C $(PM_PATH) clean
+	$(MAKE) -C $(LR_PATH) clean
+
+DiWheelDrive:
+	$(MAKE) -C $(DWD_PATH)
+
+PowerManagement:
+	$(MAKE) -C $(PM_PATH)
+
+LightRing:
+	$(MAKE) -C $(LR_PATH)
+
+flash_DiWheelDrive:
+	$(MAKE) -C $(DWD_PATH) flash
+
+flash_PowerManagement:
+	$(MAKE) -C $(PM_PATH) flash
+
+flash_LightRing:
+	$(MAKE) -C $(LR_PATH) flash
+
diff --git a/compiler/GCC/gccsetup.sh b/compiler/GCC/gccsetup.sh
new file mode 100755
index 0000000..b49e1f2
--- /dev/null
+++ b/compiler/GCC/gccsetup.sh
@@ -0,0 +1,921 @@
+################################################################################
+# AMiRo-BLT is an bootloader and toolchain 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 GCC 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|--install] [-c|--change] [-q|--quit] [--log=<file>]\n"
+  printf "\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -i, --install\n"
+  printf "              Install another version.\n"
+  printf "          -u, --uninstall\n"
+  printf "              Unistall a version.\n"
+  printf "          -c, --change\n"
+  printf "              Change the default version.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### detect installed versions ##################################################
+# Detect all installed version of arm-none-eabi-gcc, if any.
+#
+# usage:      detectInstalledVersions <binarray> <current> [<current_idx>]
+# arguments:  <binarray>
+#                 Array variable to store all detected binary paths to. 
+#             <current>
+#                 Variable to store the currently active binary to.
+#             <current_idx>
+#                 Index of the curretly selected version in the output array (<binarray>).
+# return:     n/a
+#
+function detectInstalledVersions {
+  local armgcc_command=$(command -v arm-none-eabi-gcc)
+  local armgcc_commanddir=${HOME}/gcc-none-eabi
+  local armgcc_currentbin=""
+  local armgcc_installdir=${HOME}/gcc-none-eabi
+  local armgcc_bins=()
+  local armgcc_bincnt=0
+
+  # check for already installed versions
+  if [ -n "$armgcc_command" ]; then
+    # follow the link to the actual binary
+    armgcc_commanddir=$(dirname $armgcc_command)
+    armgcc_currentbin=$armgcc_command
+    while [ -L $armgcc_currentbin ]; do
+      # differentiate between relative and absolute paths
+      if [[ $(readlink $armgcc_currentbin) = /* ]]; then
+        armgcc_currentbin=$(readlink $armgcc_currentbin)
+      else
+        armgcc_currentbin=$(realpath $(dirname $armgcc_currentbin)/$(readlink $armgcc_currentbin))
+      fi
+    done
+    # the installation location is assumed to be two directories up
+    armgcc_installdir=$(realpath $(dirname ${armgcc_currentbin})/../..)
+    # list all detected instalations
+    for dir in $(ls -d ${armgcc_installdir}/*/); do
+      if [ -f ${dir}/bin/arm-none-eabi-gcc ]; then
+        armgcc_bins[$armgcc_bincnt]=${dir}bin/arm-none-eabi-gcc
+        armgcc_bincnt=$((armgcc_bincnt + 1))
+      fi
+    done
+
+    # set the output variables
+    eval "$1=(${armgcc_bins[*]})"
+    eval $2="$armgcc_currentbin"
+    if [ -n "$3" ]; then
+      for (( bin=0; bin<${#armgcc_bins[@]}; ++bin )); do
+        if [ ${armgcc_bins[bin]} = "$armgcc_currentbin" ]; then
+          eval $3=$bin
+        fi
+      done
+    fi
+  else
+    eval "$1=()"
+    eval $2=""
+    if [ -n "$3" ]; then
+      eval $3=""
+    fi
+  fi
+}
+
+### install new version ########################################################
+# Fetches an installation package from the internet, installs it and expands
+# the $PATH environment variable (via .bashrc) if required.
+#
+# usage:      installNewVersion [-i|--install=<path>] [-l|--link=<path>]
+# argumenst:  -i, --install <path>
+#                 Path where to install the new version to.
+#             -l, --link <path>
+#                 Path where to create according links.
+# return:     0
+#                 No error or warnign occurred.
+#             1
+#                 Warning: Installation aborted by user.
+#
+function installNewVersion {
+  local installbasedir=${HOME}/gcc-arm-embedded
+  local linkdir="/usr/bin"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -i=*|--install=*)
+          installbasedir=$(realpath "${1#*=}"); shift 1;;
+        -i|--install)
+          installbasedir="$2"; shift 2;;
+        -l=*|--link=*)
+          linkdir=$(realpath "${1#*=}"); shift 1;;
+        -l|--link)
+          linkdir="$2"; shift 2;;
+        *) # sanity check (exit with error)
+          printError "invalid option: $1\n"; shift 1;;
+      esac
+    else
+      otherargs+=("$1")
+      shift 1
+    fi
+  done
+
+  # read download URL form user
+  printLog "read installation url from user\n"
+  local armgcc_downloadurl=""
+  while [ -z "$armgcc_downloadurl" ]; do
+    read -p "Download link for the installation file: " -e armgcc_downloadurl
+    if [ -z "$armgcc_downloadurl" ]; then
+      printWarning "installation aborted by user\n"
+      return 1
+    fi
+    if [[ $armgcc_downloadurl != *".tar.bz2" ]]; then
+      printWarning "please specify a .tar.bz2 file\n"
+      armgcc_downloadurl=""
+    fi
+    if [ ! wget --spider $armgcc_downloadurl 2>/dev/null ]; then
+      printWarning "$armgcc_downloadurl can not be reached\n"
+      armgcc_downloadurl=""
+    fi
+  done
+  printLog "user selected $armgcc_downloadurl\n"
+
+  # if the file already exists, ask the user if it should be downloaded again
+  local armgcc_tarball=$(basename "$armgcc_downloadurl")
+  if [ -e "$armgcc_tarball" ]; then
+    printWarning "$armgcc_tarball already exists. Delete and redownload? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        rm "$armgcc_tarball"
+        wget "$armgcc_downloadurl" | tee -a $LOG_FILE
+        ;;
+      N|n)
+        ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  else
+    wget "$armgcc_downloadurl" | tee -a $LOG_FILE
+  fi
+
+  # extract tarball
+  printInfo "extracting ${armgcc_tarball}...\n"
+  tar -jxf "$armgcc_tarball" | tee -a $LOG_FILE
+  local compilerdir=`tar --bzip2 -tf ${armgcc_tarball} | sed -e 's@/.*@@' | uniq`
+
+  # install gcc arm embedded
+  printLog "read installation directory from user\n"
+  local installdir=""
+  read -p "Installation directory: " -i ${installbasedir}/${compilerdir} -e installdir
+  printLog "user selected $installdir\n"
+  printLog "read link directory\n"
+  read -p "Link directory: " -i $linkdir -e linkdir
+  printLog "user selected $linkdir\n"
+  # if the installation path already exists, ask user to overwrite
+  if [ -d "$installdir" ]; then
+    printWarning "$installdir already exists. Overwrite? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        ;;
+      N|n)
+        printWarning "installation aborted by user\n"
+        return 1
+        ;;
+      *) # sanity check (exit with error)
+        printError "invalid option: $userinput\n";;
+    esac
+  # make sure the whole ínstallation path exists
+  else
+    while [ ! -d $(dirname "$installdir") ]; do
+      local dir=$(dirname "$installdir") 
+      while [ ! -d $(dirname "$dir") ]; do
+        dir=$(dirname "$dir")
+      done
+      echo "mkdir $dir"
+      mkdir "$dir"
+    done
+  fi
+  # copy the extracted compiler folder
+  cp -fR "$compilerdir" "$installdir"
+  # make sure whole link path exists
+  while [ ! -d "$linkdir" ]; do
+    local dir="$linkdir"
+    while [ ! -d $(dirname "$linkdir") ]; do
+      dir=$(dirname "$dir")
+    done
+    mkdir "$dir"
+  done
+  # create / overwrite links
+  ls ${installdir}/bin/ | xargs -i ln -sf ${installdir}/bin/{} ${linkdir}/{}
+  printInfo "default version set to $(arm-none-eabi-gcc -dumpversion)\n"
+
+  # append the link directory to the PATH environment variable if required
+  if [[ ! "$linkdir" = *"$PATH"* ]]; then
+    local bashrc_file=${HOME}/.bashrc
+    local bashrc_identifier="##### AMiRo ENVIRONMENT CONFIGURATION #####"
+    local bashrc_note="# DO NOT EDIT THESE LINES MANUALLY!"
+    local bashrc_entry="export PATH=\$PATH:$linkdir"
+
+    # find and edit old entry, or append a new one to the file
+    local bashrc_idlines=$(grep -x -n "$bashrc_identifier" "$bashrc_file" | cut -f1 -d:) # string of line numbers
+    bashrc_idlines=(${bashrc_idlines//"\n"/" "}) # array of line numbers
+    case ${#bashrc_idlines[@]} in
+
+      # append a new entry to the BASHRC_FILE
+      0)
+        # make sure the last line is empty
+        if [[ ! $(tail -1 $bashrc_file) =~ ^[\ \t]*$ ]]; then
+          printf "\n" >> $bashrc_file
+        fi
+        # append text to file
+        sed -i '$a'"$bashrc_identifier\n$bashrc_note\n$bashrc_entry\n$bashrc_identifier\n" $bashrc_file
+        # print note
+        printInfo "Your $bashrc_file has been updated. You need to source it to apply the changes in your environment.\n"
+        read -p "  Understood!"
+        ;;
+
+      # extend the old entry
+      2)
+        # don't do anything if the line is already present
+        local bashrc_entrylines=$(grep -x -n "$bashrc_entry" $bashrc_file | cut -f1 -d:) # string of line numbers
+        bashrc_entrylines=(${bashrc_entrylines//"\n"/" "}) # array of line numbers
+        if [[ ${#bashrc_entrylines[@]} = 0 ]]; then
+          # insert the entry before the closing identifier
+          sed -i "${bashrc_idlines[1]}"'i'"$bashrc_entry" $bashrc_file
+          # print note
+          printInfo "Your $bashrc_file has been updated. You need to source it to apply the changes in your environment.\n"
+          read -p "  Understood!"
+        elif [[ ${#bashrc_entrylines[@]} -eq 1 && ( ${bashrc_entrylines[0]} -lt ${bashrc_idlines[0]} || ${bashrc_entrylines[0]} -gt ${bashrc_idlines[1]} ) ]]; then
+          # print an error that there is an entry at the wrong place
+          printError "corrupted entry in your $bashrc_file detected\n"
+          printf "The following entry was found at the wrong place:\n"
+          printf "\n"
+          printf "$bashrc_entry\n"
+          printf "\n"
+          printf "To fix this, delete the line and rerun this setup.\n"
+          read -p "  Understood!"
+        elif [[ ${#bashrc_entrylines[@]} -gt 1 ]]; then
+          # print an error that there are multiple entries
+          printError "corrupted entry in your $bashrc_file detected\n"
+          printf "There are multiple identical entries in your $bashrc_file file.\n"
+          printf "To fix it, make sure that it contains the following line exactly once:\n"
+          printf "\n"
+          printf "$bashrc_entry\n"
+          printf "\n"
+          read -p "  Understood!"
+        fi
+        ;;
+
+      # error state (corrupted entry detected)
+      *)
+        printError "unable to append link directory to \$PATH variable\n"
+        printf "There seems to be a broken entry in your $bashrc_file file.\n"
+        printf "To fix it, make sure that the following line appears exactly twice and encloses your AMiRo related settings:\n"
+        printf "\n"
+        printf "$bashrc_identifier\n"
+        printf "\n"
+        read -p "  Understood!"
+        ;;
+    esac
+  fi
+
+  # clean up the current directory
+  rm "$armgcc_tarball"
+  rm -rf "$compilerdir"
+
+  return 0
+}
+
+### uninstall a version ########################################################
+# Select an installed version and uninstall it from the system.
+#
+# usage:      uninstallVersion <versions> <current_idx> <linkdir>
+# arguments:  <version>
+#                 Array of available versions (full path to binary).
+#             <current_idx>
+#                 Index of the currently selected version in the array.
+#             <linkdir>
+#                 Path where to delete old links.
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Installation aborted by user.
+#             -1
+#                 Error: An exception occurred.
+#
+function uninstallVersion {
+  local versions=("${!1}")
+  local current_idx="$2"
+  local linkdir="$3"
+
+  # check whether at least two installations were detected
+  if [ ${#versions[@]} -eq 0 ]; then
+    printError "no installation detected\n"
+    return -1
+  else
+    # print all available versions
+    printInfo "choose the installation to uninstall to or type 'A' to abort:\n"
+    for (( cnt=0; cnt<${#versions[@]}; ++cnt )); do
+      if [ $cnt -eq $current_idx ]; then
+        printf "*%3u: %s\n" $(($cnt + 1)) ${versions[$cnt]}
+      else
+        printf " %3u: %s\n" $(($cnt + 1)) ${versions[$cnt]}
+      fi
+    done
+
+    # read user selection
+    printLog "read user slection\n"
+    local userinput=""
+    while [ -z $userinput ] ; do
+      read -p "your selection: " -e userinput
+      printLog "user selection: $userinput\n"
+      if [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#versions[@]} ] && [[ ! "$userinput" =~ ^[Aa]$ ]]; then
+        printWarning "Please enter an integer between 1 and ${#versions[@]} or 'A' to abort.\n"
+        userinput=""
+      fi
+      if [ ${#versions[@]} -gt 1 ] && [ $((userinput - 1)) -eq $current_idx ]; then
+        printWarning "Unable to uninstall currently selected version (as long as there are others).\n"
+        userinput=""
+      fi
+    done
+
+    if [[ "$userinput" =~ ^[Aa]$ ]]; then
+      printWarning "aborted by user\n"
+      return 1
+    else
+      local idx=$((userinput - 1))
+      printf "\n"
+      # prompt selected and aks user for confirmation
+      printInfo "${versions[$idx]} will be removed. Continue? [y/n]\n"
+      readUserInput "YyNn" userinput
+      case "$userinput" in
+        Y|y)
+          ;;
+        N|n)
+          printWarning "uninstallation process aborted by user\n"
+          return 1
+          ;;
+        *) # sanity check (exit with error)
+          printError "invalid option: $userinput\n"
+          return -1
+          ;;
+      esac
+      # find and delete any links pointing to the version to be deleted
+      for link in `find $linkdir -maxdepth 1 -type l`; do
+        local l=$link
+        # follow the link to the actual binary
+        while [ -L $l ]; do
+          # differentiate between relative and absolute paths
+          if [[ $(readlink $l) = /* ]]; then
+            l=$(readlink $l)
+          else
+            l=$(realpath $(dirname $l)/$(readlink $l))
+          fi
+        done
+        # delete the link if it points to the version to be uninstalled
+        if [ $(dirname $l) == $(dirname ${versions[$idx]}) ]; then
+          rm $link
+        fi
+      done
+      # delete the version directory (assumed to be one directory up)
+      rm -rf $(realpath $(dirname ${versions[$idx]})/..)
+      printInfo "${versions[$idx]} has been removed.\n"
+    fi
+  fi
+
+  return 0
+}
+
+### change default version #####################################################
+# Change the default arm-none-eabi-gcc version.
+#
+# usage:      changeDefaultVersion <versions> <linkdir>
+# argumenst:  <versions>
+#                 Array of available versions (full path to binary).
+#             <linkdir>
+#                 Path where to delete old and create new links.
+# return:     0
+#                 No error or warnign occurred.
+#             -1
+#                 Error: no installation detected.
+#
+function changeDefaultVersion {
+  local versions=("${!1}")
+  local linkdir="$2"
+
+  # check whether an installation was detected
+  if [ ${#versions[@]} -eq 0 ]; then
+    printError "no installation detected\n"
+    return -1
+  else
+    # print all available versions
+    printInfo "choose the installation to switch to or type 'A' to abort:\n"
+    for (( cnt=0; cnt<${#versions[@]}; ++cnt )); do
+      printf "  %2u: %s\n" $(($cnt + 1)) ${versions[$cnt]}
+    done
+
+    # read user selection
+    printLog "read user slection\n"
+    local userinput=""
+    while [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#versions[@]} ] && [[ ! "$userinput" =~ ^[Aa]$ ]]; do
+      read -p "your selection: " -e userinput
+      printLog "user selection: $userinput\n"
+      if [[ ! "$userinput" =~ ^[0-9]+$ ]] || [ ! "$userinput" -gt 0 ] || [ ! "$userinput" -le ${#versions[@]} ] && [[ ! "$userinput" =~ ^[Aa]$ ]]; then
+        printWarning "Please enter an integer between 1 and ${#versions[@]} or 'A' to abort.\n"
+      fi
+    done
+
+    if [[ "$userinput" =~ ^[Aa]$ ]]; then
+      printWarning "aborted by user\n"
+    else
+      local idx=$((userinput - 1))
+      # find and delete old links
+      rm `find $linkdir -maxdepth 1 -type l | grep -Ev "*[0-9]\.[0-9]\.[0-9]"`
+      # create new links
+      local bindir=$(dirname ${versions[$idx]})
+      ls $bindir | xargs -i ln -sf $bindir/{} $linkdir/{}
+      printInfo "default version set to $(arm-none-eabi-gcc -dumpversion)\n"
+    fi
+  fi
+
+  return 0
+}
+
+### 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"
+
+  # detect installed versions and inform user
+  local installedversions=()
+  local currentversion=""
+  local currentversionidx="n/a"
+  detectInstalledVersions installedversions currentversion currentversionidx
+  case "${#installedversions[@]}" in
+    0)
+      printInfo "no installation has been detected\n";;
+    1)
+      printInfo "1 installation has been detected:\n";;
+    *)
+      printInfo "${#installedversions[@]} installations have been detected:\n";;
+  esac
+  for (( idx=0; idx<${#installedversions[@]}; ++idx )); do
+    if [ ${installedversions[$idx]} = "$currentversion" ]; then
+      printInfo "  * ${installedversions[$idx]}\n"
+    else
+      printInfo "    ${installedversions[$idx]}\n"
+    fi
+  done
+  printf "\n"
+
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -i|--install)
+          if [ -z "$currentversion" ]; then
+            installNewVersion
+          else
+            installNewVersion --install=$(realpath $(dirname $currentversion)/../..) --link=$(realpath $(dirname $currentversion)/../..)
+          fi
+          detectInstalledVersions installedversions currentversion currentversionidx
+          printf "\n"; shift 1;;
+        -u|--uninstall)
+          if [ ! -z "$currentversion" ]; then
+            uninstallVersion installedversions[@] $currentversionidx $(realpath $(dirname $currentversion)/../..)
+            detectInstalledVersions installedversions currentversion currentversionidx
+          else
+            printError "no installation detected\n"
+          fi
+          printf "\n"; shift 1;;
+        -c|--change)
+          if [ ! -z "$currentversion" ]; then
+            changeDefaultVersion installedversions[@] $(realpath $(dirname $currentversion)/../..)
+          else
+            printError "no installation detected\n"
+          fi
+          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 "GCC setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [I] - install another version\n"
+    printf "  [U] - uninstall a version\n"
+    printf "  [C] - change default version\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "IiUuCcQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      I|i)
+        if [ -z "$currentversion" ]; then
+          installNewVersion
+        else
+          installNewVersion --install=$(realpath $(dirname $currentversion)/../..) --link=$(realpath $(dirname $currentversion)/../..)
+        fi
+        detectInstalledVersions installedversions currentversion currentversionidx
+        printf "\n";;
+      U|u)
+        if [ ! -z "$currentversion" ]; then
+          uninstallVersion installedversions[@] $currentversionidx $(realpath $(dirname $currentversion)/../..)
+          detectInstalledVersions installedversions currentversion currentversionidx
+        else
+          printError "no installation detected\n"
+        fi
+        printf "\n";;
+      C|c)
+        if [ ! -z "$currentversion" ]; then
+          changeDefaultVersion installedversions[@] $(realpath $(dirname $currentversion)/../..)
+        else
+          printError "no installation detected\n"
+        fi
+        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/compiler/compilersetup.sh b/compiler/compilersetup.sh
new file mode 100755
index 0000000..74459d4
--- /dev/null
+++ b/compiler/compilersetup.sh
@@ -0,0 +1,440 @@
+################################################################################
+# AMiRo-BLT is an bootloader and toolchain 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 compiler 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] [--GCC] [-q|--quit] [--log=<file>]\n"
+  printf "\n"
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          --GCC\n"
+  printf "              Enter GCC setup.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
+
+### enter GCC setup ############################################################
+# Enter the arm-none-eabi-gcc setup.
+#
+# usage:      gccSetup
+# arguments:  n/a
+# return:     n/a
+function gccSetup {
+  printInfo "entering GCC setup...\n"
+  printf "\n"
+  if [ -z "$LOG_FILE" ]; then
+    $(realpath $(dirname ${BASH_SOURCE[0]}))/GCC/gccsetup.sh --noinfo
+  else
+    $(realpath $(dirname ${BASH_SOURCE[0]}))/GCC/gccsetup.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;;
+        --GCC)
+          gccSetup; 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-BLT compiler setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [G] - enter GCC setup\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "GgQq" userinput
+    printf "\n"
+
+    # evaluate user selection
+    case "$userinput" in
+      G|g)
+        gccSetup; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n"; printf "\n";;
+    esac
+  done
+
+  exit 0
+}
+
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
+
+main "$@"
diff --git a/ide/QtCreator/QtCreatorSetup.sh b/ide/QtCreator/QtCreatorSetup.sh
index 787cdc3..741fa86 100755
--- a/ide/QtCreator/QtCreatorSetup.sh
+++ b/ide/QtCreator/QtCreatorSetup.sh
@@ -1,7 +1,7 @@
 ################################################################################
-# AMiRo-OS is an operating system designed for the Autonomous Mini Robot       #
-# (AMiRo) platform.                                                            #
-# Copyright (C) 2016..2017  Thomas Schöpping et al.                            #
+# AMiRo-BLT is an bootloader and toolchain 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         #
@@ -24,198 +24,264 @@
 #!/bin/bash
 
 ################################################################################
-###   HELPER FUNCTIONS                                                       ###
+# GENERIC FUNCTIONS                                                            #
 ################################################################################
 
-#-------------------------------------------------------------------------------
-# toAbsolutePath $1 [$2]
-#
-# Makes a given path absolute and either echos the result or stores it in the
-# specified variable.
-# arguments:
-#   $1: the path to be converted
-#   $2: a variable to store the resulting path [optiional]
-function toAbsolutePath {
-  # the path that shall be converted if required
-  TARGET_PATH=$1
-
-  # store the path where the script was called from
-  ORIGIN_PATH="${PWD}/"
-
-  # check, whether the target is a directory or not
-  if [ -d $TARGET_PATH ]; then
-    cd $TARGET_PATH
-    # special case: the target is the root directory
-    if [ $TARGET_PATH = "/" ]; then
-      ABSOLUTE_PATH="${PWD}"
-    else
-      ABSOLUTE_PATH="${PWD}/"
-    fi
-  else
-    cd $(dirname $TARGET_PATH)
-    ABSOLUTE_PATH="${PWD}/$(basename $TARGET_PATH)"
+### 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
-  cd $ORIGIN_PATH
+  printf "$(tput setaf 1)>>> $string$(tput sgr 0)" 1>&2
+}
 
-  # return the result
-  if [ $# -gt 1 ]; then
-    eval $2="$ABSOLUTE_PATH"
-  else
-    echo $ABSOLUTE_PATH
+### 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)"
+}
 
-  # cleanup
-  unset TARGET_PATH
-  unset ORIGIN_PATH
-  unset ABSOLUTE_PATH
+### 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)"
 }
-#-------------------------------------------------------------------------------
-
-#-------------------------------------------------------------------------------
-# getRelativePath $1 $2 [$3]
-#
-# Computes the relative path from one to another location.
-# The result is then either stored in a specified variable, or just echoed.
-# arguments:
-#   $1: the path to start from
-#       If this is not a directory, only the path will be used
-#   $2: the target location
-#   $3: a variable to store the resulting path [optional]
-function getRelativePath {
-  # make start and target location absolute
-  START_PATH=$(toAbsolutePath $1)
-  if [ ! -d $START_PATH ]; then
-    START_PATH="$(dirname $START_PATH)/"
-  fi
-  TARGET_PATH=$(toAbsolutePath $2)
-
-  # initialize the common prefix and the relative path from START_PATH to TARGET_PATH
-  COMMON_PREFIX=$START_PATH
-  RELATIVE_PATH="./"
-  # while the common prefix is no substring of the target path
-  while [ "${TARGET_PATH#$COMMON_PREFIX}" == "$TARGET_PATH" ]; do
-    read
-    # reduce the common prefix and record the relative path
-    COMMON_PREFIX="$(dirname $COMMON_PREFIX)/"
-    RELATIVE_PATH="../$RELATIVE_PATH"
-    # special case: if only root is the common prefix, remove the just appended '/'
-    if [ $COMMON_PREFIX == "//" ]; then
-      COMMON_PREFIX="/"
-    fi
-  done
 
-  # if the relative path is more than just the current directory, cut off the trailing './'
-  if [ ! $RELATIVE_PATH == "./" ]; then
-    RELATIVE_PATH=${RELATIVE_PATH::-2}
+### 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
+}
 
-  # compute the unique part of the target path
-  UNIQUE_POSTFIX=${TARGET_PATH#$COMMON_PREFIX}
+### 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"
+}
 
-  # append the unique postfix to the relative path
-  RELATIVE_PATH=$RELATIVE_PATH$UNIQUE_POSTFIX
+### 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
+}
 
-  # return the result
-  if [ $# -gt 2 ]; then
-    eval $3="$RELATIVE_PATH"
+### 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
-    echo $RELATIVE_PATH
+    if [ $quiet = false ]; then
+      printInfo "log file set to $filepath\n"
+    fi
   fi
 
-  # clean up
-  unset START_PATH
-  unset TARGET_PATH
-  unset COMMON_PREFIX
-  unset RELATIVE_PATH
-  unset UNIQUE_POSTFIX
+  eval ${otherargs[1]}="$filepath"
+
+  return 0
 }
-#-------------------------------------------------------------------------------
-
-
-
-###############################################################################
-###   INITIALIZATION                                                        ###
-###############################################################################
-
-# ignore case when comparing strings
-shopt -s nocasematch
-
-# detect what exactly should be done
-NOINFO_FLAG="NOINFO"
-HELP_FLAG="HELP"
-CLEAN_FLAG="CLEAN"
-WIPE_FLAG="WIPE"
-LIGHTRING_FLAG="LR"
-POWERMANAGEMENT_FLAG="PM"
-DIWHEELDRIVE_FLAG="DWD"
-
-# start with an empty array
-ARG_LIST=()
-# try to interpret all given arguments
-for ARG in "$@"; do
-  case $ARG in
-    "no_info")
-      ARG_LIST+=( "$NOINFO_FLAG" )
-      ;;
-    "help")
-      ARG_LIST+=( "$HELP_FLAG" )
-      ;;
-    "clean")
-      ARG_LIST+=( "$CLEAN_FLAG" )
-      ;;
-    "wipe")
-      ARG_LIST+=( "$WIPE_FLAG" )
-      ;;
-    "all")
-      ARG_LIST+=( "$LIGHTRING_FLAG" "$POWERMANAGEMENT_FLAG" "$DIWHEELDRIVE_FLAG" )
-      ;;
-    "LightRing"|"LR")
-      ARG_LIST+=( "$LIGHTRING_FLAG" )
-      ;;
-    "PowerManagement"|"PM")
-      ARG_LIST+=( "$POWERMANAGEMENT_FLAG" )
-      ;;
-    "DiWheelDrive"|"DWD")
-      ARG_LIST+=( "$DIWHEELDRIVE_FLAG" )
-      ;;
-  esac
-done
-
-# evaluate if a help text shall be printed and which further actions to take
-PRINT_INFO=true
-PRINT_HELP=false
-ACTION_REQUESTED=false
-for ARG in ${ARG_LIST[@]}; do
-  case $ARG in
-    $NOINFO_FLAG)
-      PRINT_INFO=false
-      ;;
-    $HELP_FLAG)
-      PRINT_HELP=true
-      ;;
-    $CLEAN_FLAG|$WIPE_FLAG|$LIGHTRING_FLAG|$POWERMANAGEMENT_FLAG|$DIWHEELDRIVE_FLAG)
-      ACTION_REQUESTED=true
-      ;;
-    *)
-      PRINT_HELP=true
-      ;;
-  esac
-done
-
-# print the info prompt
-if [[ $PRINT_INFO = true ]]; then
-
-  ##############################################################################
-  ###   PRINT INFO                                                           ###
-  ##############################################################################
 
+################################################################################
+# 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 QtCreator IDE setup            #\n"
+  printf "#                  Welcome to the QtCreator setup!                   #\n"
   printf "#                                                                    #\n"
   printf "######################################################################\n"
   printf "#                                                                    #\n"
-  printf "# Copyright (c) 2016..2017  Thomas Schöpping                         #\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"
@@ -226,233 +292,646 @@ if [[ $PRINT_INFO = true ]]; then
   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"
-fi
-
-# print setup header
-printf "QtCreator projects setup\n"
-printf "========================\n"
-printf "\n"
-
-# print the help text
-if [[ ${#ARG_LIST[@]} == 0 ||
-      (${#ARG_LIST[@]} == 1 && ${ARG_LIST[0]} == "$NOINFO_FLAG") ||
-      $PRINT_HELP = true ]]; then
-
-  ##############################################################################
-  ###   PRINT HELP                                                           ###
-  ##############################################################################
-
-  printf "The following commands are available:                                 \n"
-  printf "                                                                      \n"
-  printf "  help            - Prints this help text.                            \n"
-  printf "  clean           - Deletes all files created by this script.         \n"
-  printf "  wipe            - Deletes the .user files, created by QtCreator.    \n"
-  printf "  LightRing       - Creates a project for the LightRing module.       \n"
-  printf "  PowerManagement - Creates a project for the PowerManagement module. \n"
-  printf "  DiWheelDrive    - Creates a project for the DiWheelDrive module.    \n"
-  printf "  all             - Creates all three projects.                       \n"
-  printf "                                                                      \n"
-  printf "Any of these commands can be combined, e.g.                           \n"
-  printf "  $> ./setup.sh PowerManagement DiWheelDrive                          \n"
-  printf "will create two projects.                                             \n"
-  printf "\n"
-  printf "Note that this script does not create a project for the SerialBoot    \n"
-  printf "application. Since it uses CMAKE, QtCreator can import it directly.   \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"
+}
 
-fi
+### 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 amirobltdir=$(realpath $(dirname $(realpath ${BASH_SOURCE[0]}))/../../Target/)
+  local input=""
+  read -p "Path where to create/delete project files: " -i $amirobltdir -e input
+  printLog "user selected path $(realpath $input)\n"
+  eval $1="$(realpath $input)"
+}
 
-# execute action
-if [ $ACTION_REQUESTED = true ]; then
+### 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
+}
 
-  ##############################################################################
-  ###   CONFIGURATION                                                        ###
-  ##############################################################################
+### 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
 
-  # the current user dir
-  USER_DIR="${PWD}/"
+  # 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
 
-  # the directory containing this script file
-  toAbsolutePath $(dirname ${BASH_SOURCE[0]}) SCRIPT_DIR
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-  # the root directory of the project
-  toAbsolutePath ${SCRIPT_DIR}../.. PROJECT_ROOT_PATH
+  # 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
 
-  # the relative path where all project files shall be generated
-  read -p "path where to create/delete the project files: " -i "$PROJECT_ROOT_PATH" -e QTCREATOR_FILES_PATH
-  toAbsolutePath $QTCREATOR_FILES_PATH QTCREATOR_FILES_PATH
+  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
 
-  # the include path for GCC specific headers
-  ARM_NONE_EABI_GCC_BIN=$(which arm-none-eabi-gcc)
-  while [ -L $ARM_NONE_EABI_GCC_BIN ]; do
-    ARM_NONE_EABI_GCC_BIN=$(readlink $ARM_NONE_EABI_GCC_BIN)
-  done
-  toAbsolutePath "$(dirname $ARM_NONE_EABI_GCC_BIN)/../arm-none-eabi/include/" ARM_NONE_EABI_GCC_INCLUDE_PATH
+  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
 
-  # a common path for all projects
-  COMMON_SOURCE_INCLUDE_PATH=${PROJECT_ROOT_PATH}Target/Source
+  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
 
-  # the paths to the individual projects
-  POWERMANAGEMENT_PROJECT_ROOT_PATH=${PROJECT_ROOT_PATH}Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot
-  DIWHEELDRIVE_PROJECT_ROOT_PATH=${PROJECT_ROOT_PATH}Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot
-  LIGHTRING_PROJECT_ROOT_PATH=${PROJECT_ROOT_PATH}Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot
+  if [ $wipe == true ]; then
+    rm ${projectdir}/LightRing.user 2>&1 | tee -a $LOG_FILE
+    rm ${projectdir}/PowerManagement.user 2>&1 | tee -a $LOG_FILE
+    rm ${projectdir}/DiWheelDrive.user 2>&1 | tee -a $LOG_FILE
+  fi
 
-  # the prefix names for the projects to be generated
-  LIGHTRING_PROJECT_PREFIX="LightRing"
-  POWERMANAGEMENT_PROJECT_PREFIX="PowerManagement"
-  DIWHEELDRIVE_PROJECT_PREFIX="DiWheelDrive"
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
 
-  printf "\n"
+  return 0
+}
 
-  ##############################################################################
-  ###   SETUP                                                                ###
-  ##############################################################################
+### 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
 
-  # move to the project root directory
-  cd $QTCREATOR_FILES_PATH
+  # print message
+  printInfo "creating QtCreator project files for the LightRing module...\n"
 
-  for ARG in ${ARG_LIST[@]}; do
-    case $ARG in
+  # read absolute project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-      ##########################################################################
-      ###   CLEAN STEP                                                       ###
-      ##########################################################################
+  # retrieve absolute GCC include dir
+  if [ -z "$gccincludedir" ]; then
+    retrieveGccIncludeDir gccincludedir
+  fi
 
-      $CLEAN_FLAG)
-        printf "removing project files..."
+  # move to project directory
+  cd $projectdir
+
+  # create project files
+  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
+  find $gccincludedir -type d > ${projectdir}/LightRing.includes
+  find $(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../Target/Source) -type d | grep -v "ARMCM4_STM32" >> ${projectdir}/LightRing.includes
+  find $(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot) -type d | grep -v "bin\|cmd\|ethernetlib\|fatfs\|uip\|obj" >> ${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 -v "/arm-none-eabi/" | grep -E ".*(\.h|\.c|\.x)$" >> ${projectdir}/LightRing.files
+  done
+  # generate a default project configuration file if none exists so far
+  if [ ! -f ${projectdir}/LightRing.config ]; then
+    echo -e "// Add predefined macros for your project here. For example:" > ${projectdir}/LightRing.config
+    echo -e "// #define YOUR_CONFIGURATION belongs here" >> ${projectdir}/LightRing.config
+    echo -e "" >> ${projectdir}/LightRing.config
+  fi
+  # generate a default .creator file if none exists so far
+  if [ ! -f ${projectdir}/LightRing.creator ]; then
+    echo -e "[general]" > ${projectdir}/LightRing.creator
+    echo -e "" >> ${projectdir}/LightRing.creator
+  fi
 
-        # remove all files
-        rm ${LIGHTRING_PROJECT_PREFIX}.includes 2> /dev/null
-        rm ${LIGHTRING_PROJECT_PREFIX}.files 2> /dev/null
-        rm ${LIGHTRING_PROJECT_PREFIX}.config 2> /dev/null
-        rm ${LIGHTRING_PROJECT_PREFIX}.creator 2> /dev/null
+  # go back to user directory
+  cd $userdir
 
-        rm ${POWERMANAGEMENT_PROJECT_PREFIX}.includes 2> /dev/null
-        rm ${POWERMANAGEMENT_PROJECT_PREFIX}.files 2> /dev/null
-        rm ${POWERMANAGEMENT_PROJECT_PREFIX}.config 2> /dev/null
-        rm ${POWERMANAGEMENT_PROJECT_PREFIX}.creator 2> /dev/null
+  # fill the output variables
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+  if [ ! -z "$gccoutvar" ]; then
+    eval $gccoutvar="$gccincludedir"
+  fi
 
-        rm ${DIWHEELDRIVE_PROJECT_PREFIX}.includes 2> /dev/null
-        rm ${DIWHEELDRIVE_PROJECT_PREFIX}.files 2> /dev/null
-        rm ${DIWHEELDRIVE_PROJECT_PREFIX}.config 2> /dev/null
-        rm ${DIWHEELDRIVE_PROJECT_PREFIX}.creator 2> /dev/null
+  return 0
+}
 
-        printf "\tdone\n"
-        ;;
+### 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
 
-      ##########################################################################
-      ###   WIPE STEP                                                        ###
-      ##########################################################################
+  # print message
+  printInfo "creating QtCreator project files for the PowerManagement module...\n"
 
-      $WIPE_FLAG)
-        printf "removing .user project files..."
+  # read absolute project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-        # remove all user files
-        rm ${POWERMANAGEMENT_PROJECT_PREFIX}.creator.user 2> /dev/null
-        rm ${DIWHEELDRIVE_PROJECT_PREFIX}.creator.user 2> /dev/null
-        rm ${LIGHTRING_PROJECT_PREFIX}.creator.user 2> /dev/null
+  # retrieve absolute GCC include dir
+  if [ -z "$gccincludedir" ]; then
+    retrieveGccIncludeDir gccincludedir
+  fi
 
-        printf "\tdone\n"
-        ;;
+  # move to project directory
+  cd $projectdir
+
+  # create project files
+  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
+  find $gccincludedir -type d > ${projectdir}/PowerManagement.includes
+  find $(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../Target/Source) -type d | grep -v "ARMCM4_STM32" >> ${projectdir}/PowerManagement.includes
+  find $(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot) -type d | grep -v "bin\|cmd\|ethernetlib\|fatfs\|uip\|obj" >> ${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 -v "/arm-none-eabi/" | grep -E ".*(\.h|\.c|\.x)$" >> ${projectdir}/PowerManagement.files
+  done
+  # generate a default project configuration file if none exists so far
+  if [ ! -f ${projectdir}/PowerManagement.config ]; then
+    echo -e "// Add predefined macros for your project here. For example:" > ${projectdir}/PowerManagement.config
+    echo -e "// #define YOUR_CONFIGURATION belongs here" >> ${projectdir}/PowerManagement.config
+    echo -e "" >> ${projectdir}/PowerManagement.config
+  fi
+  # generate a default .creator file if none exists so far
+  if [ ! -f ${projectdir}/PowerManagement.creator ]; then
+    echo -e "[general]" > ${projectdir}/PowerManagement.creator
+    echo -e "" >> ${projectdir}/PowerManagement.creator
+  fi
 
-      ##########################################################################
-      ###   LIGHTRING SETUP                                                  ###
-      ##########################################################################
+  # go back to user directory
+  cd $userdir
 
-      $LIGHTRING_FLAG)
-        printf "creating project files for ${LIGHTRING_PROJECT_PREFIX} (STM32F103RET6)..."
 
-        # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-        find $ARM_NONE_EABI_GCC_INCLUDE_PATH -type d > ${LIGHTRING_PROJECT_PREFIX}.includes
-        find $COMMON_SOURCE_INCLUDE_PATH -type d | grep -v "ARMCM4_STM32" >> ${LIGHTRING_PROJECT_PREFIX}.includes
-        find $LIGHTRING_PROJECT_ROOT_PATH -type d | grep -v "uip\|fatfs\|ethernetlib\|cmd\|ide" >> ${LIGHTRING_PROJECT_PREFIX}.includes
+  # fill the output variables
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+  if [ ! -z "$gccoutvar" ]; then
+    eval $gccoutvar="$gccincludedir"
+  fi
 
-        # generate a file that specifies all files
-        echo -n "" > ${LIGHTRING_PROJECT_PREFIX}.files
-        for path in `cat ${LIGHTRING_PROJECT_PREFIX}.includes`; do
-          find $path -maxdepth 1 -type f \( ! -iname ".*" \) | grep -v "/arm-none-eabi/" | grep -E ".*(\.h|\.c|\.x)$" >> ${LIGHTRING_PROJECT_PREFIX}.files
-        done
+  return 0
+}
 
-        # 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
+### 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
 
-        # 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
+  # print message
+  printInfo "creating QtCreator project files for the DiWheelDrive module...\n"
 
-        printf "\tdone\n"
-        ;;
+  # read absolute project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-      ##########################################################################
-      ###   POWERMANAGEMENT SETUP                                            ###
-      ##########################################################################
+  # retrieve absolute GCC include dir
+  if [ -z "$gccincludedir" ]; then
+    retrieveGccIncludeDir gccincludedir
+  fi
 
-      $POWERMANAGEMENT_FLAG)
-        printf "creating project files for ${POWERMANAGEMENT_PROJECT_PREFIX} (STM32F405RGT6)..."
+  # move to project directory
+  cd $projectdir
 
-        # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-        find $ARM_NONE_EABI_GCC_INCLUDE_PATH -type d > ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
-        find $COMMON_SOURCE_INCLUDE_PATH -type d | grep -v "ARMCM3_STM32" >> ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
-        find $POWERMANAGEMENT_PROJECT_ROOT_PATH -type d | grep -v "uip\|fatfs\|ethernetlib\|cmd\|ide" >> ${POWERMANAGEMENT_PROJECT_PREFIX}.includes
 
-        # generate a file that specifies all files
-        echo -n "" > ${POWERMANAGEMENT_PROJECT_PREFIX}.files
-        for path in `cat ${POWERMANAGEMENT_PROJECT_PREFIX}.includes`; do
-          find $path -maxdepth 1 -type f \( ! -iname ".*" \) | grep -v "/arm-none-eabi/" | grep -E ".*(\.h|\.c|\.x)$" >> ${POWERMANAGEMENT_PROJECT_PREFIX}.files
-        done
+  # create project files
+  # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
+  find $gccincludedir -type d > ${projectdir}/DiWheelDrive.includes
+  find $(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../Target/Source) -type d | grep -v "ARMCM4_STM32" >> ${projectdir}/DiWheelDrive.includes
+  find $(realpath --relative-base=$projectdir $(dirname ${BASH_SOURCE[0]})/../../Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot) -type d | grep -v "bin\|cmd\|ethernetlib\|fatfs\|uip\|obj" >> ${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 -v "/arm-none-eabi/" | grep -E ".*(\.h|\.c|\.x)$" >> ${projectdir}/DiWheelDrive.files
+  done
+  # generate a default project configuration file if none exists so far
+  if [ ! -f ${projectdir}/DiWheelDrive.config ]; then
+    echo -e "// Add predefined macros for your project here. For example:" > ${projectdir}/DiWheelDrive.config
+    echo -e "// #define YOUR_CONFIGURATION belongs here" >> ${projectdir}/DiWheelDrive.config
+    echo -e "" >> ${projectdir}/DiWheelDrive.config
+  fi
+  # generate a default .creator file if none exists so far
+  if [ ! -f ${projectdir}/DiWheelDrive.creator ]; then
+    echo -e "[general]" > ${projectdir}/DiWheelDrive.creator
+    echo -e "" >> ${projectdir}/DiWheelDrive.creator
+  fi
 
-        # 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
+  # go back to user directory
+  cd $userdir
 
-        # 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
 
-        printf "\tdone\n"
-        ;;
+  # fill the output variables
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
+  if [ ! -z "$gccoutvar" ]; then
+    eval $gccoutvar="$gccincludedir"
+  fi
 
-      ##########################################################################
-      ###   DIWHEELDRIVE SETUP                                               ###
-      ##########################################################################
+  return 0
+}
 
-      $DIWHEELDRIVE_FLAG)
-        printf "creating project files for ${DIWHEELDRIVE_PROJECT_PREFIX} (STM32F103RET6)..."
+### create project files for al 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"
 
-        # generate a file that contains all subdirectories as includes (but ignore hidden and documentation directories)
-        find $ARM_NONE_EABI_GCC_INCLUDE_PATH -type d > ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
-        find $COMMON_SOURCE_INCLUDE_PATH -type d | grep -v "ARMCM4_STM32" >> ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
-        find $DIWHEELDRIVE_PROJECT_ROOT_PATH -type d | grep -v "uip\|fatfs\|ethernetlib\|cmd\|ide" >> ${DIWHEELDRIVE_PROJECT_PREFIX}.includes
+  # read project directory
+  local projectdir=""
+  getProjectDir projectdir
+  printInfo "files will be created in $projectdir\n"
 
-        # generate a file that specifies all files
-        echo -n "" > ${DIWHEELDRIVE_PROJECT_PREFIX}.files
-        for path in `cat ${DIWHEELDRIVE_PROJECT_PREFIX}.includes`; do
-          find $path -maxdepth 1 -type f \( ! -iname ".*" \) | grep -v "/arm-none-eabi/" | grep -E ".*(\.h|\.c|\.x)$" >> ${DIWHEELDRIVE_PROJECT_PREFIX}.files
-        done
+  # retrieve gcc-arm-none-eabi include dir
+  retrieveGccIncludeDir gccincludedir
 
-        # 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
+  # create projects
+  createLightRingProject --path="$projectdir" --gcc="$gccincludedir"
+  createPowerManagementProject --path="$projectdir" --gcc="$gccincludedir"
+  createDiWheelDriveProject --path="$projectdir" --gcc="$gccincludedir"
 
-        # 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
+  return 0
+}
 
-        printf "\tdone\n"
-        ;;
+### 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
-fi
+
+  exit 0
+}
 
 ################################################################################
-###   OUTRO                                                                  ###
+# SCRIPT ENTRY POINT                                                           #
 ################################################################################
 
+main "$@"
+
diff --git a/ide/idesetup.sh b/ide/idesetup.sh
new file mode 100755
index 0000000..faf861c
--- /dev/null
+++ b/ide/idesetup.sh
@@ -0,0 +1,440 @@
+################################################################################
+# AMiRo-BLT is an bootloader and toolchain 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 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-BLT 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 "$@"
diff --git a/setup.sh b/setup.sh
index 37c518e..ba56fb5 100755
--- a/setup.sh
+++ b/setup.sh
@@ -1,7 +1,7 @@
 ################################################################################
 # AMiRo-BLT is an bootloader and toolchain designed for the Autonomous Mini    #
 # Robot (AMiRo) platform.                                                      #
-# Copyright (C) 2016..2017  Thomas Schöpping et al.                            #
+# 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         #
@@ -23,15 +23,265 @@
 
 #!/bin/bash
 
-# initial info text (can be disabled with 'no_info' as last argument)
-if [[ ! ${!#} = "no_info" ]]; then
+################################################################################
+# 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 setup!                   #\n"
   printf "#                                                                    #\n"
   printf "######################################################################\n"
   printf "#                                                                    #\n"
-  printf "# Copyright (c) 2016..2017  Thomas Schöpping                         #\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"
@@ -42,111 +292,323 @@ if [[ ! ${!#} = "no_info" ]]; then
   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] [-f|--stm32flash] [-s|--SerialBoot] [-e|--IDE] [-c|--compiler] [-q|--quit] [--log=<file>]\n"
   printf "\n"
-fi
+  printf "options:  -h, --help\n"
+  printf "              Print this help text.\n"
+  printf "          -f, --stm32flash\n"
+  printf "              Run st,32flash tool setup.\n"
+  printf "          -s, --SerialBoot\n"
+  printf "              Run SerialBoot tool setup.\n"
+  printf "          -e, --IDE\n"
+  printf "              Enter IDE setup.\n"
+  printf "          -c, --compiler\n"
+  printf "              Enter compiler setup.\n"
+  printf "          -q, --quit\n"
+  printf "              Quit the script.\n"
+  printf "          --log=<file>\n"
+  printf "              Specify a log file.\n"
+}
 
-# initialization of variables
-ARG_IDX=1
-USER_INPUT=${!ARG_IDX}
+### stm32flash tool setup ######################################################
+# Fetches the source code for the stm32flash tool and builds the binary.
+# If the tool was already initialized, it can be wiped and rebuilt.
+#
+# usage:      stm32flashSetup
+# arguments:  n/a
+# return:     0
+#                 No error or warning occurred.
+#             1
+#                 Warning: Setup aborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function stm32flashSetup {
+  local amirobltdir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local stm32flashdir=${amirobltdir}/Host/Source/stm32flash
+  local userdir=$(pwd)
+
+  # if the stm32flash folder is not empty
+  if [ ! -z "$(ls -A $stm32flashdir)" ]; then
+    printWarning "$stm32flashdir is not empty. Delete and reinitialize? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        printInfo "wiping ${stm32flashdir}...\n"
+        # checkout base commit and delete all local branches
+        cd $amirobltdir
+        git submodule update --force --checkout $stm32flashdir | tee -a $LOG_FILE
+        cd $stm32flashdir
+        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 $amirobltdir
+        # deinit stm32flash submodule and delete any remaining files
+        git submodule deinit -f $stm32flashdir 2>&1 | tee -a $LOG_FILE
+        rm -rf $stm32flashdir/*
+        cd $userdir
+        ;;
+      N|n)
+        printWarning "stm32flash setup aborted by user\n"
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n";
+        return -1
+        ;;
+    esac
+  fi
 
-while [[ ! $USER_INPUT =~ ^[Ee]$ ]]; do
+  # initialize submodule
+  printInfo "initializing stm32flash submodule...\n"
+  cd $amirobltdir
+  git submodule update --init $stm32flashdir 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 $stm32flashdir 2>&1 | tee -a $LOG_FILE;;
+      N|n)
+        printWarning "stm32flash initialization aborted by user\n"
+        cd $userdir
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n"; return -1;;
+    esac
+  done
+  cd $userdir
 
-  # main menu info prompt and selection
-  printf "AMiRo-BLT setup\n"
-  printf "===============\n"
+  # build the stm32flash tool
+  printInfo "compiling stm32flash\n"
+  cd $stm32flashdir
+  make 2>&1 | tee -a $LOG_FILE
+  cd $userdir
+
+  return 0
+}
+
+### SerialBoot tool setup ######################################################
+# Builds the SerialBoot tool.
+# If the tool was built before, it can be deleted and rebuilt.
+#
+# usage:      serialBootSetup
+# arguments:  n/a
+# return:     0
+#                 No errort or warning occurred.
+#             1
+#                 Warning: Setup aborted by user.
+#             -1
+#                 Error: Unexpected user input.
+#
+function serialBootSetup {
+  local amirobltdir=$(dirname $(realpath ${BASH_SOURCE[0]}))
+  local serialbootdir=${amirobltdir}/Host/Source/SerialBoot
+  local userdir=$(pwd)
+
+  # if a build folder already exists
+  if [ -d "${serialbootdir}/build/" ]; then
+    printWarning "SerialBoot has been built before. Delete and rebuild? [y/n]\n"
+    local userinput=""
+    readUserInput "YyNn" userinput
+    case "$userinput" in
+      Y|y)
+        printInfo "deleting ${serialbootdir}build/...\n"
+        rm -rf "${serialbootdir}build/"
+        ;;
+      N|n)
+        printWarning "SerialBoot setup aborted by user\n"
+        return 1
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected input: $userinput\n";
+        return -1
+        ;;
+    esac
+  fi
+
+  # build SerialBoot
+  printInfo "compiling SerialBoot...\n"
+  mkdir ${serialbootdir}/build
+  cd ${serialbootdir}/build
+  cmake .. 2>&1 | tee -a $LOG_FILE
+  make 2>&1 | tee -a $LOG_FILE
+  cd $userdir
+
+  return 0
+}
+
+### IDE setup ##################################################################
+# Enter the IDE setup.
+#
+# usage:      ideSetup
+# arguments:  n/a
+# return:     n/a
+#
+function ideSetup {
+  printInfo "entering IDE setup\n"
   printf "\n"
-  if [[ -z $USER_INPUT || $USER_INPUT == "no_info" ]]; then
-    printf "Please select one of the following actions:\n"
-    printf "    [S] - SerialBoot flashing tool setup\n"
-    printf "    [Q] - setup QtCreator projects\n"
-    printf "    [E] - exit this setup\n"
-
-    while [[ ! $USER_INPUT =~ ^[SsQqEe]$ ]]; do
-      read -p "your selection: " -n 1 -e USER_INPUT
-      if [[ ! $USER_INPUT =~ ^[SsQqEe]$ ]]; then
-        printf "[%s] is no valid action. \n" $USER_INPUT
-      fi
-    done
+  if [ -z "$LOG_FILE" ]; then
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/ide/idesetup.sh --noinfo
+  else
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/ide/idesetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
 
-    printf "\n"
+### compiler setup #############################################################
+# Enter the compiler setup.
+#
+# usage:      compilerSetup
+# arguments:  n/a
+# return:     n/a
+#
+function compilerSetup {
+  printInfo "entering IDE setup\n"
+  printf "\n"
+  if [ -z "$LOG_FILE" ]; then
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/compiler/compilersetup.sh --noinfo
+  else
+    $(dirname $(realpath ${BASH_SOURCE[0]}))/compiler/compilersetup.sh --LOG="$LOG_FILE" --noinfo
+  fi
+}
+
+### main function of this script ###############################################
+# A setup to initialize dependencies, setup IDE projects and configure the
+# compiler 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"
-    printf "\n"
   fi
+  printf "\n"
 
-  # action selection
-  case $USER_INPUT in
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    quitScript
+  fi
 
-    # SerailBoot setup
-    S|s)
-      # print setup header
-      printf "SerialBoot setup\n"
-      printf "================\n"
+  # 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"
 
-      USER_DIR=${PWD}
-      cd $(dirname ${BASH_SOURCE[0]})/Host/Source/SerialBoot
-      BUILD_SERIALBOOT=true
-
-      # test for existing binary
-      if [ -f build/SerialBoot ]; then
-        printf "WARNING: SerialBoot binary already exists.\n"
-        read -p "Would you like to delete and rebuild it? [Y|n] " -n 1 -i "Y" -e USER_INPUT
-        if [[ $USER_INPUT =~ ^[Yy]$ ]]; then
-          BUILD_SERIALBOOT=true
-          rm -rf build/
-        elif [[ ! $USER_INPUT =~ ^[YyNn]$ ]]; then
-          BUILD_SERIALBOOT=false
-          printf "'%s' is no valid selection. Aborting setup.\n" $USER_INPUT
-        else
-          BUILD_SERIALBOOT=false
-        fi
-      fi
-
-      # build the tool, if requested
-      if [ $BUILD_SERIALBOOT = true ]; then
-        mkdir build
-        cd build
-        cmake ..
-        make
-      fi
-
-      cd $USER_DIR
-      ;;
-
-    # QtCreator setup
-    Q|q)
-      # calling the script with no arguments prints the help and returns
-      source $(dirname ${BASH_SOURCE[0]})/ide/QtCreator/QtCreatorSetup.sh "no_info"
-      printf "\n"
-      # set deafult arguments and call the script again
-      USER_INPUT="clean all"
-      read -p "select commands: " -i "$USER_INPUT" -e USER_INPUT
-      printf "\n"
-      source $(dirname ${BASH_SOURCE[0]})/ide/QtCreator/QtCreatorSetup.sh "no_info" $USER_INPUT
-      ;;
-
-    # exit
-    E|e)
-      break;
-      ;;
-
-    # sanity check
-    *)
-      printf "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
-      printf "ERROR (${LINENO}): unexpected state; aborting script\n"
-      printf "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
-      printf "\n"
-      exit
-      ;;
+  # parse arguments
+  local otherargs=()
+  while [ $# -gt 0 ]; do
+    if ( parseIsOption $1 ); then
+      case "$1" in
+        -h|--help) # already handled; ignore
+          shift 1;;
+        -f|--stm32flash)
+          stm32flashSetup; printf "\n"; shift 1;;
+        -s|--SerialBoot)
+          serialBootSetup; printf "\n"; shift 1;;
+        -e|--IDE)
+          ideSetup; printf "\n"; shift 1;;
+        -c|--compiler)
+          compilerSetup; 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
 
-  esac
+  # interactive menu
+  while ( true ); do
+    # main menu info prompt and selection
+    printInfo "AMiRo-BLT setup main menu\n"
+    printf "Please select one of the following actions:\n"
+    printf "  [F] - get and build stm32flash tool\n"
+    printf "  [S] - build SerialBoot tool\n"
+    printf "  [E] - IDE project setup\n"
+    printf "  [C] - enter compiler setup\n"
+    printf "  [Q] - quit this setup\n"
+    local userinput=""
+    readUserInput "FfSsEeCcQq" userinput
+    printf "\n"
 
-  printf "\n"
-  printf "######################################################################\n"
-  printf "\n"
+    # evaluate user selection
+    case "$userinput" in
+      F|f)
+        stm32flashSetup; printf "\n";;
+      S|s)
+        serialBootSetup; printf "\n";;
+      E|e)
+        ideSetup; printf "\n";;
+      C|c)
+        compilerSetup; printf "\n";;
+      Q|q)
+        quitScript;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $userinput\n";;
+    esac
+  done
+
+  exit 0
+}
 
-  let ARG_IDX++
-  USER_INPUT=${!ARG_IDX}
+################################################################################
+# SCRIPT ENTRY POINT                                                           #
+################################################################################
 
-done
+main "$@"
 
