commit 1da30dfceaecb44356c737ecc7cf25e801a1ea9a
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Tue Sep 26 17:02:05 2017 +0200

    Bash scripts enhanced.

diff --git a/ide/QtCreator/QtCreatorSetup.sh b/ide/QtCreator/QtCreatorSetup.sh
index 787cdc3..22a95f7 100755
--- a/ide/QtCreator/QtCreatorSetup.sh
+++ b/ide/QtCreator/QtCreatorSetup.sh
@@ -1,6 +1,6 @@
 ################################################################################
-# AMiRo-OS is an operating system designed for the Autonomous Mini Robot       #
-# (AMiRo) platform.                                                            #
+# AMiRo-BLT is an bootloader and toolchain designed for the Autonomous Mini    #
+# Robot (AMiRo) platform.                                                      #
 # Copyright (C) 2016..2017  Thomas Schöpping et al.                            #
 #                                                                              #
 # This program is free software: you can redistribute it and/or modify         #
@@ -24,194 +24,259 @@
 #!/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.
+### print an error
 # 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)"
+#   - error string [required]
+# return: n/a
+function printError {
+  local string="ERROR:   $1"
+
+  # if a log file is specified
+  if [ ! -z $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
+# arguments:
+#   - warning string [required]
+# return: n/a
+function printWarning {
+  local string="WARNING: $1"
+
+  # if a log file is specified
+  if [ ! -z $LOG_FILE ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 3)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print an information text
+# arguments:
+#   - information string [required]
+# return: n/a
+function printInfo {
+  local string="INFO:    $1"
+
+  # if a log file is specified
+  if [ ! -z $LOG_FILE ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
+  fi
+  printf "$(tput setaf 2)>>> $string$(tput sgr 0)" 1>&2
+}
+
+### print a message to the log file
+# arguments:
+#   - information string [required]
+# return: n/a
+function printLog {
+  local string="LOG:     $1"
+
+  # if a log file is specified
+  if [ ! -z $LOG_FILE ]; then
+    printf "[$(date '+%Y-%m-%d %H:%M:%S')] $string" >> $LOG_FILE
   fi
+}
+
+### exit the script normally
+# arguments: n/a
+# return: 0 (success)
+function quitScript {
+  printInfo "exiting $(realpath ${BASH_SOURCE[0]})\n"
+  printf "\n"
+  printf "######################################################################\n"
 
-  # cleanup
-  unset TARGET_PATH
-  unset ORIGIN_PATH
-  unset ABSOLUTE_PATH
+  exit 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.
+### read a user input
 # 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="/"
+#   --numchars, -n  maximum number of characters to read
+#   --options, -o   possible chacters to select (only applies if numchars=1)
+#   --out, -e       output variable to store the user input to
+# return: error code
+#   -  0: no error
+#   - -1: error: invalid arguments
+function readUserInput {
+  # parse arguments
+  local arguments=$(getopt -l num-chars:,options:,out: -o n:o:e: -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
+  fi
+  eval set -- "$arguments"
+
+  # evaluate arguments
+  local numchars=1
+  local options=""
+  local outvar=""
+  while [ true ]; do
+    case "$1" in
+      --num-chars|-n)
+        numchars=$2; shift 2
+        ;;
+      --options|-o)
+        options="$2"; shift 2
+        ;;
+      --out|-e)
+        outvar=$2; shift 2
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $1\n"; return -1
+        ;;
+    esac
+  done
+
+  # read user input
+  local _userinput=""
+  while [ -z $_userinput ] || ( [ $numchars == 1 ] && [ ! -z "$options" ] && [[ ! $_userinput =~ ^["$options"]$ ]] ); do
+    read -p "your selection: " -n $numchars -e _userinput
+    if [ -z $_userinput ] || ( [ $numchars == 1 ] && [ ! -z "$options" ] && [[ ! $_userinput =~ ^["$options"]$ ]] ); then
+      printWarning "[$_userinput] is no valid action\n"
     fi
   done
+  printLog "[$_userinput] has been selected\n"
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$_userinput"
+  fi
+
+  return 0
+}
 
-  # if the relative path is more than just the current directory, cut off the trailing './'
-  if [ ! $RELATIVE_PATH == "./" ]; then
-    RELATIVE_PATH=${RELATIVE_PATH::-2}
+### set the log file
+# arguments:
+#   --file, -f    name of file [required]
+#   --option, -o  option if file already exists [optional]
+#                 a: append
+#                 r: delete and restart
+#                 n: disable log
+#                 A: silent append (no message in the log file)
+# return: error code
+#   -  0: no error
+#   -  1: warning: file already exists
+#   -  2: warning: no file specified
+#   - -1: error: invalid arguments
+function setLogFile {
+  # parse arguments
+  local arguments=$(getopt -l file:,option: -o f:o: -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
   fi
+  eval set -- "$arguments"
+
+  # evaluate arguments
+  local fname=""
+  local option=""
+  while [ true ]; do
+    case "$1" in
+      --file|f)
+        if [ ! -z $2 ]; then
+          fname="$(dirname $2)/$(basename $2)"
+        else
+          fname=""
+        fi
+        shift 2
+        ;;
+      --option|-o)
+        case $2 in
+          A)
+            option="A"
+            ;;
+          a)
+            option="a"
+            ;;
+          r)
+            option="r"
+            ;;
+          n)
+            option="n"
+            ;;
+          *) # sanity check (return error)
+            printError "unexpected argument: $1\n"; return -1
+            ;;
+        esac
+        shift 2
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $1\n"; return -1
+        ;;
+    esac
+  done
 
-  # compute the unique part of the target path
-  UNIQUE_POSTFIX=${TARGET_PATH#$COMMON_PREFIX}
+  # if no log file was specified
+  if [ -z $fname ]; then
+    printWarning "no log file specified (no log will be genreated)\n"
+    LOG_FILE=""
+    return 2
+  # if file already exists
+  elif [ -f $fname ]; then
+    # if no option was specified, ask what to do
+    if [ -z $option ]; then
+      printWarning "log file ${fname} already esists\n"
+      printf "Options:\n"
+      printf "  [A] - append log\n"
+      printf "  [R] - restart log (delete existing file)\n"
+      printf "  [N] - no log\n"
+      readUserInput --num-chars=1 --options="AaRrNn" --out=userinput
+      option=${userinput,,}
+    fi
 
-  # append the unique postfix to the relative path
-  RELATIVE_PATH=$RELATIVE_PATH$UNIQUE_POSTFIX
+    # evaluate option
+    case $option in
+      A)
+        LOG_FILE=$(realpath $fname)
+        ;;
+      a)
+        printInfo "appending log to existing file\n"
+        LOG_FILE=$(realpath $fname)
+        printf "\n" >> $LOG_FILE
+        printf "######################################################################\n" >> $LOG_FILE
+        printf "\n" >> $LOG_FILE
+        ;;
+      r)
+        printInfo "old log file deleted, starting clean\n"
+        LOG_FILE=$(realpath $fname)
+        rm $LOG_FILE
+        ;;
+      n)
+        printInfo "no log file will be generated\n"
+        LOG_FILE=""
+        ;;
+      *) # sanity check (return error)
+        printError "unexpected argument: $1\n"; return -1
+        ;;
+    esac
 
-  # return the result
-  if [ $# -gt 2 ]; then
-    eval $3="$RELATIVE_PATH"
+    return 1
   else
-    echo $RELATIVE_PATH
+    printInfo "log file set to $(realpath $fname)\n"
+    LOG_FILE=$(realpath $fname)
+    return 0
   fi
-
-  # clean up
-  unset START_PATH
-  unset TARGET_PATH
-  unset COMMON_PREFIX
-  unset RELATIVE_PATH
-  unset UNIQUE_POSTFIX
 }
-#-------------------------------------------------------------------------------
-
-
-
-###############################################################################
-###   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
+# 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"
@@ -226,233 +291,642 @@ if [[ $PRINT_INFO = true ]]; then
   printf "# Excellence Initiative.                                             #\n"
   printf "#                                                                    #\n"
   printf "######################################################################\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"
+}
+
+### print help text
+# arguments: n/a
+# return: n/a
+function printHelp {
+  printInfo "printing help text\n"
+  printf "usage:  $(basename ${BASH_SOURCE[0]}) [options]\n"
+  printf "options:\n"
+  printf "  --help, -h              Print this help text.\n"
+  printf "  --clean, -c             Delete project files.\n"
+  printf "  --wipe, -w              Delete project and .user files.\n"
+  printf "  --LightRing, -L         Create a project for the LightRing module.\n"
+  printf "  --PowerManagement, -P   Create a project for the PowerManagement module.\n"
+  printf "  --DiWheelDrive, -D      Create a project for the DiWheelDrive module.\n"
+  printf "  --All, -A               Create projects for all modules.\n"
+  printf "  --quit, -q              Quit the script.\n"
+  printf "  --log=<file>            Specify a log file.\n"
+}
 
-fi
+### read directory where to create/delete projects
+# arguments:
+#   - $1: variable to store the path to [required]
+# return: n/a
+function getProjectDir {
+  printLog "reading path for project files\n"
+  local amirobltdir="$(realpath $(dirname ${BASH_SOURCE[0]})/../../Target/)"
+  local pojectdir=""
+  read -p "Path where to create/delete project files: " -i $amirobltdir -e projectdir
+  printLog "user selected path $(realpath $projectdir)\n"
+  eval $1="$(realpath $projectdir)"
+}
 
-# execute action
-if [ $ACTION_REQUESTED = true ]; then
+### retrieves the ARM-NONE-EABI-GCC include directory
+# arguments:
+#   - $1: variable to store the path to [required]
+# return:
+#  -  0: no error
+#  - -1: error: 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 "arm-none-eabi-gcc not found\n"
+    return -1
+  fi
 
-  ##############################################################################
-  ###   CONFIGURATION                                                        ###
-  ##############################################################################
+  # traverse any links
+  while [ -L "$binpath" ]; do
+    binpath=$(readlink $binpath)
+  done
+  printInfo "gcc-arm-none-eabi detected: $binpath\n"
 
-  # the current user dir
-  USER_DIR="${PWD}/"
+  # return include path
+  eval $1=$(realpath $(dirname ${binpath})/../arm-none-eabi/include/)
 
-  # the directory containing this script file
-  toAbsolutePath $(dirname ${BASH_SOURCE[0]}) SCRIPT_DIR
+  return 0
+}
 
-  # the root directory of the project
-  toAbsolutePath ${SCRIPT_DIR}../.. PROJECT_ROOT_PATH
+### delete project files
+# arguments:
+#  --path, -p <path>  path where to delete the project files
+#  --out, -o <var>    variable to store the path to
+#  --wipe, -w         delete .user files as well
+# return:
+#  -  0: no error
+#  -  1: warning: function aborted by user
+#  - -1: error: unexpected user input
+function deleteProjects {
+  # parse arguments
+  local arguments=$(getopt -l path:,out:,wipe -o p:o:w -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
+  fi
+  eval set -- "$arguments"
 
-  # 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
+  local projectdir=""
+  local outvar=""
+  local wipe=false
 
-  # 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)
+  # handle command line arguments
+  while [ true ]; do
+    case $1 in
+      --path|-p)
+        projectdir="$2"; shift 2
+        ;;
+      --out|-o)
+        outvar=$2; shift 2
+        ;;
+      --wipe|-w)
+        wipe=true; shift 1
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $1\n"; return 1
+        ;;
+    esac
   done
-  toAbsolutePath "$(dirname $ARM_NONE_EABI_GCC_BIN)/../arm-none-eabi/include/" ARM_NONE_EABI_GCC_INCLUDE_PATH
 
-  # a common path for all projects
-  COMMON_SOURCE_INCLUDE_PATH=${PROJECT_ROOT_PATH}Target/Source
-
-  # 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
+  # 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 prefix names for the projects to be generated
-  LIGHTRING_PROJECT_PREFIX="LightRing"
-  POWERMANAGEMENT_PROJECT_PREFIX="PowerManagement"
-  DIWHEELDRIVE_PROJECT_PREFIX="DiWheelDrive"
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-  printf "\n"
+  # 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
 
-  ##############################################################################
-  ###   SETUP                                                                ###
-  ##############################################################################
+  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
 
-  # move to the project root directory
-  cd $QTCREATOR_FILES_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
 
-  for ARG in ${ARG_LIST[@]}; do
-    case $ARG in
+  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
 
-      ##########################################################################
-      ###   CLEAN STEP                                                       ###
-      ##########################################################################
+  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
 
-      $CLEAN_FLAG)
-        printf "removing project files..."
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  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
+  return 0
+}
 
-        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
+### create LightRing project files
+# arguments:
+#  --path, -p <path>  path where to create the project files
+#  --out, -o <var>    variable to store the path to
+# return:
+#  -  0: no error
+#  -  1: warning: function aborted by user
+#  - -1: error: unexpected user input
+function createLightRingProject {
+  # parse arguments
+  local arguments=$(getopt -l path:,out: -o p:o: -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
+  fi
+  eval set -- "$arguments"
 
-        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
+  local projectdir=""
+  local outvar=""
 
-        printf "\tdone\n"
+  # handle command line arguments
+  while [ true ]; do
+    case $1 in
+      --path|-p)
+        projectdir="$2"; shift 2
+        ;;
+      --out|-o)
+        outvar=$2; shift 2
+        ;;
+      --) # end of options reached
+        shift; break
         ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $1\n"; return 1
+        ;;
+    esac
+  done
+
+  # print message
+  printInfo "creating QtCreator project files for the LightRing module\n"
+
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
+
+  # retrieve gcc-arm-none-eabi include dir
+  local gccincludedir=""
+  retrieveGccIncludeDir gccincludedir
+  if [ -z "$gccincludedir" ]; then
+    return -1
+  fi
+
+  # 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 $(dirname ${BASH_SOURCE[0]})/../../Target/Source/) -type d | grep -v "ARMCM4_STM32" >> ${projectdir}/LightRing.includes
+  find $(realpath $(dirname ${BASH_SOURCE[0]})/../../Target/Demo/ARMCM3_STM32F103_LightRing_GCC/Boot/) -type d | grep -v "uip\|fatfs\|ethernetlib\|cmd\|ide" >> ${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
+
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
 
-      ##########################################################################
-      ###   WIPE STEP                                                        ###
-      ##########################################################################
+  return 0
+}
 
-      $WIPE_FLAG)
-        printf "removing .user project files..."
+### create PowerManagement project files
+# arguments:
+#  --path, -p <path>  path where to create the project files
+#  --out, -o <var>    variable to store the path to
+# return:
+#  -  0: no error
+#  -  1: warning: function aborted by user
+#  - -1: error: unexpected user input
+function createPowerManagementProject {
+  # parse arguments
+  local arguments=$(getopt -l path:,out: -o p:o: -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
+  fi
+  eval set -- "$arguments"
 
-        # 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
+  local projectdir=""
+  local outvar=""
 
-        printf "\tdone\n"
+  # handle command line arguments
+  while [ true ]; do
+    case $1 in
+      --path|-p)
+        projectdir="$2"; shift 2
+        ;;
+      --out|-o)
+        outvar=$2; shift 2
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $1\n"; return 1
         ;;
+    esac
+  done
+
+  # print message
+  printInfo "creating QtCreator project files for the PowerManagement module\n"
 
-      ##########################################################################
-      ###   LIGHTRING SETUP                                                  ###
-      ##########################################################################
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
+
+  # retrieve gcc-arm-none-eabi include dir
+  local gccincludedir=""
+  retrieveGccIncludeDir gccincludedir
+  if [ -z "$gccincludedir" ]; then
+    return -1
+  fi
 
-      $LIGHTRING_FLAG)
-        printf "creating project files for ${LIGHTRING_PROJECT_PREFIX} (STM32F103RET6)..."
+  # 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 $(dirname ${BASH_SOURCE[0]})/../../Target/Source/) -type d | grep -v "ARMCM3_STM32" >> ${projectdir}/PowerManagement.includes
+  find $(realpath $(dirname ${BASH_SOURCE[0]})/../../Target/Demo/ARMCM4_STM32F405_Power_Management_GCC/Boot/) -type d | grep -v "uip\|fatfs\|ethernetlib\|cmd\|ide" >> ${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
 
-        # 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
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  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
+# arguments:
+#  --path, -p <path>  path where to create the project files
+#  --out, -o <var>    variable to store the path to
+# return:
+#  -  0: no error
+#  -  1: warning: function aborted by user
+#  - -1: error: unexpected user input
+function createDiWheelDriveProject {
+  # parse arguments
+  local arguments=$(getopt -l path:,out: -o p:o: -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
+  fi
+  eval set -- "$arguments"
 
-        # 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
+  local projectdir=""
+  local outvar=""
 
-        printf "\tdone\n"
+  # handle command line arguments
+  while [ true ]; do
+    case $1 in
+      --path|-p)
+        projectdir="$2"; shift 2
+        ;;
+      --out|-o)
+        outvar=$2; shift 2
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $1\n"; return 1
         ;;
+    esac
+  done
 
-      ##########################################################################
-      ###   POWERMANAGEMENT SETUP                                            ###
-      ##########################################################################
+  # print message
+  printInfo "creating QtCreator project files for the DiWheelDrive module\n"
 
-      $POWERMANAGEMENT_FLAG)
-        printf "creating project files for ${POWERMANAGEMENT_PROJECT_PREFIX} (STM32F405RGT6)..."
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-        # 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
+  # retrieve gcc-arm-none-eabi include dir
+  local gccincludedir=""
+  retrieveGccIncludeDir gccincludedir
+  if [ -z "$gccincludedir" ]; then
+    return -1
+  fi
 
-        # 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 $(dirname ${BASH_SOURCE[0]})/../../Target/Source/) -type d | grep -v "ARMCM4_STM32" >> ${projectdir}/DiWheelDrive.includes
+  find $(realpath $(dirname ${BASH_SOURCE[0]})/../../Target/Demo/ARMCM3_STM32F103_DiWheelDrive_GCC/Boot/) -type d | grep -v "uip\|fatfs\|ethernetlib\|cmd\|ide" >> ${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
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
 
-        # generate a default .creator file if none exists so far
-        if [ ! -f ${POWERMANAGEMENT_PROJECT_PREFIX}.creator ]; then
-          echo -e "[general]\n" > ${POWERMANAGEMENT_PROJECT_PREFIX}.creator
-        fi
+  return 0
+}
 
-        printf "\tdone\n"
+### create project files for al modules
+# arguments:
+#  --path, -p <path>  path where to create the project files
+#  --out, -o <var>    variable to store the path to
+# return:
+#  -  0: no error
+#  -  1: warning: function aborted by user
+#  - -1: error: unexpected user input
+function createAllProjects {
+  # parse arguments
+  local arguments=$(getopt -l path:,out: -o p:o: -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    return -1
+  fi
+  eval set -- "$arguments"
+
+  local projectdir=""
+  local outvar=""
+
+  # handle command line arguments
+  while [ true ]; do
+    case $1 in
+      --path|-p)
+        projectdir="$2"; shift 2
+        ;;
+      --out|-o)
+        outvar=$2; shift 2
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $1\n"; return 1
         ;;
+    esac
+  done
 
-      ##########################################################################
-      ###   DIWHEELDRIVE SETUP                                               ###
-      ##########################################################################
+  # print message
+  printInfo "creating QtCreator projects files for all modules\n"
 
-      $DIWHEELDRIVE_FLAG)
-        printf "creating project files for ${DIWHEELDRIVE_PROJECT_PREFIX} (STM32F103RET6)..."
+  # read project directory if required
+  if [ -z "$projectdir" ]; then
+    getProjectDir projectdir
+  fi
 
-        # 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
+  # create projects
+  createLightRingProject --path="$projectdir"
+  createPowerManagementProject --path="$projectdir"
+  createDiWheelDriveProject --path="$projectdir"
 
-        # 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
+  # store the path to the output variable, if required
+  if [ ! -z "$outvar" ]; then
+    eval $outvar="$projectdir"
+  fi
 
-        # 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
+  return 0
+}
 
-        # 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
+################################################################################
+# SCRIPT MAIN FUNCTION                                                         #
+################################################################################
+
+### main function of this script
+# arguments: see help text
+# return: error code
+#   - 0: no error
+#   - 1: error
+function main {
+
+  # parse arguments
+  local arguments=$(getopt -l help,clean,wipe,LightRing,PowerManagement,DiWheelDrive,All,quit,log:,LOG:,noinfo -o hcwLPDAq -- "$@")
+  if [ $? != 0 ]; then
+    printError "could not interprete arguments."
+    exit 1
+  fi
+  eval set -- "$arguments"
+
+  # print welcome/info text if not suppressed
+  if [[ $@ != *"--noinfo"* ]]; then
+    printWelcomeText
+  else
+    printf "######################################################################\n"
+  fi
+  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 filenameidx=$[cmdidx + 1]
+    # optionally force silent appending
+    if [ "${!cmdidx}" == "--LOG" ]; then
+      setLogFile --file="${!filenameidx}" --option=A
+    else
+      setLogFile --file="${!filenameidx}"
+      printf "\n"
+    fi
+  fi
+
+  # log script name
+  printLog "this is $(realpath ${BASH_SOURCE[0]})\n"
 
-        printf "\tdone\n"
+  # if --help or -h was specified, print the help text and exit
+  if [[ $@ == *"--help"* || $@ == *"-h"* ]]; then
+    printHelp
+    printf "\n"
+    exitScript
+  fi
+
+  # handle command line arguments
+  local projectfilesdir=""
+  while [ true ]; do
+    case $1 in
+      --help|-h) # already handled; ignore
+        shift 1;
+        ;;
+      --clean|-c)
+        if [ -z "$projectfilesdir" ]; then
+          deleteProjects --out=projectfilesdir
+        else
+          deleteProjects --path="$projectfilesdir"
+        fi
+        printf "\n"
+        shift 1
+        ;;
+      --wipe|-w)
+          if [ -z "$projectfilesdir" ]; then
+          deleteProjects --out=projectfilesdir
+        else
+          deleteProjects --wipe --path="$projectfilesdir"
+        fi
+        printf "\n"
+        shift 1
         ;;
+      --LightRing|-L)
+        if [ -z "$projectfilesdir" ]; then
+          createLightRingProject --out=projectfilesdir
+        else
+          createLightRingProject --path="$projectfilesdir"
+        fi
+        printf "\n"
+        shift 1
+        ;;
+      --PowerManagement|-P)
+        if [ -z "$projectfilesdir" ]; then
+          createPowerManagementProject --out=projectfilesdir
+        else
+          createPowerManagementProject --path="$projectfilesdir"
+        fi
+        printf "\n"
+        shift 1
+        ;;
+      --DiWheelDrive|-D)
+        if [ -z "$projectfilesdir" ]; then
+          createDiWheelDriveProject --out=projectfilesdir
+        else
+          createDiWheelDriveProject --path="$projectfilesdir"
+        fi
+        printf "\n"
+        shift 1
+        ;;
+      --All|-A)
+        if [ -z "$projectfilesdir" ]; then
+          createAllProjects --out=projectfilesdir
+        else
+          createAllProjects --path="$projectfilesdir"
+        fi
+        printf "\n"
+        shift 1
+        ;;
+      --quit|-q)
+        quitScript
+        ;;
+      --log|--LOG) # already handled; ignore
+        shift 2
+        ;;
+      --noinfo) # already processed; ignore
+        shift 1
+        ;;
+      --) # end of options reached
+        shift; break
+        ;;
+      *) # sanity check (exit with error)
+        printError "unexpected argument: $1\n"; exit -1
+        ;;
+    esac
+  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"
+    readUserInput --num-chars=1 --options="CcWwLlPpDdAaQq" --out=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"; exit -1
+        ;;
     esac
   done
-fi
+
+  exit 0
+}
 
 ################################################################################
-###   OUTRO                                                                  ###
+# SCRIPT ENTRY POINT                                                           #
 ################################################################################
 
+main "$@"
+
