diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..ec53b72b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,7 @@
+---
+BasedOnStyle: Google
+IndentWidth: 2
+---
+Language: Cpp
+ColumnLimit: 100
+---
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e78e8929..fd52291c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,6 +4,9 @@ set(FSFW_VERSION 2)
set(FSFW_SUBVERSION 0)
set(FSFW_REVISION 0)
+# Add the cmake folder so the FindSphinx module is found
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
+
option(FSFW_GENERATE_SECTIONS
"Generate function and data sections. Required to remove unused code" ON
)
@@ -12,6 +15,7 @@ if(FSFW_GENERATE_SECTIONS)
endif()
option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF)
+option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF)
if(FSFW_BUILD_UNITTESTS)
option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON)
endif()
@@ -36,7 +40,9 @@ option(FSFW_ADD_SGP4_PROPAGATOR "Add SGP4 propagator code" OFF)
set(LIB_FSFW_NAME fsfw)
set(FSFW_TEST_TGT fsfw-tests)
+set(FSFW_DUMMY_TGT fsfw-dummy)
+project(${LIB_FSFW_NAME})
add_library(${LIB_FSFW_NAME})
if(FSFW_BUILD_UNITTESTS)
@@ -50,7 +56,7 @@ if(FSFW_BUILD_UNITTESTS)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
- GIT_TAG v3.0.0-preview3
+ GIT_TAG v3.0.0-preview4
)
FetchContent_MakeAvailable(Catch2)
@@ -59,7 +65,6 @@ if(FSFW_BUILD_UNITTESTS)
set(FSFW_CONFIG_PATH tests/src/fsfw_tests/unit/testcfg)
configure_file(tests/src/fsfw_tests/unit/testcfg/FSFWConfig.h.in FSFWConfig.h)
configure_file(tests/src/fsfw_tests/unit/testcfg/TestsConfig.h.in tests/TestsConfig.h)
- configure_file(tests/src/fsfw_tests/unit/testcfg/OBSWConfig.h.in OBSWConfig.h)
project(${FSFW_TEST_TGT} CXX C)
add_executable(${FSFW_TEST_TGT})
@@ -85,7 +90,7 @@ set(FSFW_CORE_INC_PATH "inc")
set_property(CACHE FSFW_OSAL PROPERTY STRINGS host linux rtems freertos)
-# Configure Files
+# For configure files
target_include_directories(${LIB_FSFW_NAME} PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
)
@@ -147,13 +152,8 @@ else()
set(OS_FSFW "host")
endif()
-if(FSFW_BUILD_UNITTESTS)
- configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
- configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
-else()
- configure_file(src/fsfw/FSFW.h.in FSFW.h)
- configure_file(src/fsfw/FSFWVersion.h.in FSFWVersion.h)
-endif()
+configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
+configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
message(STATUS "Compiling FSFW for the ${FSFW_OS_NAME} operating system.")
@@ -163,6 +163,9 @@ if(FSFW_ADD_HAL)
add_subdirectory(hal)
endif()
add_subdirectory(contrib)
+if(FSFW_BUILD_DOCS)
+ add_subdirectory(docs)
+endif()
if(FSFW_BUILD_UNITTESTS)
if(FSFW_TESTS_GEN_COV)
@@ -189,13 +192,13 @@ if(FSFW_BUILD_UNITTESTS)
"--exclude-unreachable-branches"
)
set(COVERAGE_EXCLUDES
- "/c/msys64/mingw64/*"
+ "/c/msys64/mingw64/*" "*/fsfw_hal/*"
)
elseif(UNIX)
set(COVERAGE_EXCLUDES
"/usr/include/*" "/usr/bin/*" "Catch2/*"
"/usr/local/include/*" "*/fsfw_tests/*"
- "*/catch2-src/*"
+ "*/catch2-src/*" "*/fsfw_hal/*"
)
endif()
@@ -234,9 +237,11 @@ endif()
# The project CMakeLists file has to set the FSFW_CONFIG_PATH and add it.
# If this is not given, we include the default configuration and emit a warning.
if(NOT FSFW_CONFIG_PATH)
- message(WARNING "Flight Software Framework configuration path not set!")
set(DEF_CONF_PATH misc/defaultcfg/fsfwconfig)
- message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..")
+ if(NOT FSFW_BUILD_DOCS)
+ message(WARNING "Flight Software Framework configuration path not set!")
+ message(WARNING "Setting default configuration from ${DEF_CONF_PATH} ..")
+ endif()
add_subdirectory(${DEF_CONF_PATH})
set(FSFW_CONFIG_PATH ${DEF_CONF_PATH})
endif()
diff --git a/README.md b/README.md
index 312bc077..a2261c99 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ There are some functions like `printChar` which are different depending on the t
and need to be implemented by the mission developer.
A template configuration folder was provided and can be copied into the project root to have
-a starting point. The [configuration section](doc/README-config.md#top) provides more specific
+a starting point. The [configuration section](docs/README-config.md#top) provides more specific
information about the possible options.
## Adding the library
@@ -91,7 +91,7 @@ You can use the following commands inside the `fsfw` folder to set up the build
```sh
mkdir build-Unittest && cd build-Unittest
-cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host ..
+cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
```
You can also use `-DFSFW_OSAL=linux` on Linux systems.
@@ -107,16 +107,22 @@ cmake --build . -- fsfw-tests_coverage -j
The `coverage.py` script located in the `script` folder can also be used to do this conveniently.
+## Formatting the sources
+
+The formatting is done by the `clang-format` tool. The configuration is contained within the
+`.clang-format` file in the repository root. As long as `clang-format` is installed, you
+can run the `apply-clang-format.sh` helper script to format all source files consistently.
+
## Index
-[1. High-level overview](doc/README-highlevel.md#top)
-[2. Core components](doc/README-core.md#top)
-[3. Configuration](doc/README-config.md#top)
-[4. OSAL overview](doc/README-osal.md#top)
-[5. PUS services](doc/README-pus.md#top)
-[6. Device Handler overview](doc/README-devicehandlers.md#top)
-[7. Controller overview](doc/README-controllers.md#top)
-[8. Local Data Pools](doc/README-localpools.md#top)
+[1. High-level overview](docs/README-highlevel.md#top)
+[2. Core components](docs/README-core.md#top)
+[3. Configuration](docs/README-config.md#top)
+[4. OSAL overview](docs/README-osal.md#top)
+[5. PUS services](docs/README-pus.md#top)
+[6. Device Handler overview](docs/README-devicehandlers.md#top)
+[7. Controller overview](docs/README-controllers.md#top)
+[8. Local Data Pools](docs/README-localpools.md#top)
diff --git a/automation/Dockerfile b/automation/Dockerfile
index 93a4fe7d..a530a671 100644
--- a/automation/Dockerfile
+++ b/automation/Dockerfile
@@ -5,4 +5,10 @@ RUN apt-get --yes upgrade
#tzdata is a dependency, won't install otherwise
ARG DEBIAN_FRONTEND=noninteractive
-RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano
+RUN apt-get --yes install gcc g++ cmake make lcov git valgrind nano iputils-ping
+
+RUN git clone https://github.com/catchorg/Catch2.git && \
+ cd Catch2 && \
+ git checkout v3.0.0-preview4 && \
+ cmake -Bbuild -H. -DBUILD_TESTING=OFF && \
+ cmake --build build/ --target install
diff --git a/automation/Jenkinsfile b/automation/Jenkinsfile
index d4a8e2ab..dae2da2c 100644
--- a/automation/Jenkinsfile
+++ b/automation/Jenkinsfile
@@ -1,28 +1,23 @@
pipeline {
- agent any
environment {
- BUILDDIR = 'build-unittests'
+ BUILDDIR = 'build-tests'
+ }
+ agent {
+ dockerfile {
+ dir 'automation'
+ //force docker to redownload base image and rebuild all steps instead of caching them
+ //this way, we always get an up to date docker image one each build
+ additionalBuildArgs '--no-cache --pull'
+ reuseNode true
+ }
}
stages {
- stage('Create Docker') {
- agent {
- dockerfile {
- dir 'automation'
- additionalBuildArgs '--no-cache'
- reuseNode true
- }
- }
+ stage('Clean') {
steps {
sh 'rm -rf $BUILDDIR'
}
}
stage('Configure') {
- agent {
- dockerfile {
- dir 'automation'
- reuseNode true
- }
- }
steps {
dir(BUILDDIR) {
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..'
@@ -30,12 +25,6 @@ pipeline {
}
}
stage('Build') {
- agent {
- dockerfile {
- dir 'automation'
- reuseNode true
- }
- }
steps {
dir(BUILDDIR) {
sh 'cmake --build . -j'
@@ -43,12 +32,6 @@ pipeline {
}
}
stage('Unittests') {
- agent {
- dockerfile {
- dir 'automation'
- reuseNode true
- }
- }
steps {
dir(BUILDDIR) {
sh 'cmake --build . -- fsfw-tests_coverage -j'
@@ -56,12 +39,6 @@ pipeline {
}
}
stage('Valgrind') {
- agent {
- dockerfile {
- dir 'automation'
- reuseNode true
- }
- }
steps {
dir(BUILDDIR) {
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
diff --git a/cmake/FindSphinx.cmake b/cmake/FindSphinx.cmake
new file mode 100644
index 00000000..4a5b0700
--- /dev/null
+++ b/cmake/FindSphinx.cmake
@@ -0,0 +1,13 @@
+# Look for an executable called sphinx-build
+find_program(SPHINX_EXECUTABLE
+ NAMES sphinx-build
+ DOC "Path to sphinx-build executable")
+
+include(FindPackageHandleStandardArgs)
+
+# Handle standard arguments to find_package like REQUIRED and QUIET
+find_package_handle_standard_args(
+ Sphinx
+ "Failed to find sphinx-build executable"
+ SPHINX_EXECUTABLE
+)
\ No newline at end of file
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..a485625d
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1 @@
+/_build
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
new file mode 100644
index 00000000..fa5790db
--- /dev/null
+++ b/docs/CMakeLists.txt
@@ -0,0 +1,66 @@
+# This is based on this excellent posting provided by Sy:
+# https://devblogs.microsoft.com/cppblog/clear-functional-c-documentation-with-sphinx-breathe-doxygen-cmake/
+find_package(Doxygen REQUIRED)
+find_package(Sphinx REQUIRED)
+
+get_target_property(LIB_FSFW_PUBLIC_HEADER_DIRS ${LIB_FSFW_NAME} INTERFACE_INCLUDE_DIRECTORIES)
+# TODO: Add HAL as well
+file(GLOB_RECURSE LIB_FSFW_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/src/*.h)
+file(GLOB_RECURSE RST_DOC_FILES ${PROJECT_SOURCE_DIR}/docs/*.rst)
+
+set(DOXYGEN_INPUT_DIR ${PROJECT_SOURCE_DIR}/src)
+set(DOXYGEN_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/doxygen)
+set(DOXYGEN_INDEX_FILE ${DOXYGEN_OUTPUT_DIR}/xml/index.xml)
+set(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+set(DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+# Replace variables inside @@ with the current values
+configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY)
+
+# Doxygen won't create this for us
+file(MAKE_DIRECTORY ${DOXYGEN_OUTPUT_DIR})
+
+# Only regenerate Doxygen when the Doxyfile or public headers change
+add_custom_command(
+ OUTPUT ${DOXYGEN_INDEX_FILE}
+ DEPENDS ${LIB_FSFW_PUBLIC_HEADERS}
+ COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYFILE_OUT}
+ MAIN_DEPENDENCY ${DOXYFILE_OUT} ${DOXYFILE_IN}
+ COMMENT "Generating docs"
+ VERBATIM
+)
+
+# Nice named target so we can run the job easily
+add_custom_target(Doxygen ALL DEPENDS ${DOXYGEN_INDEX_FILE})
+
+set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
+set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/sphinx)
+set(SPHINX_INDEX_FILE ${SPHINX_BUILD}/index.html)
+
+# Only regenerate Sphinx when:
+# - Doxygen has rerun
+# - Our doc files have been updated
+# - The Sphinx config has been updated
+add_custom_command(
+ OUTPUT ${SPHINX_INDEX_FILE}
+ COMMAND
+ ${SPHINX_EXECUTABLE} -b html
+ # Tell Breathe where to find the Doxygen output
+ -Dbreathe_projects.fsfw=${DOXYGEN_OUTPUT_DIR}/xml
+ ${SPHINX_SOURCE} ${SPHINX_BUILD}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS
+ # Other docs files you want to track should go here (or in some variable)
+ ${RST_DOC_FILES}
+ ${DOXYGEN_INDEX_FILE}
+ MAIN_DEPENDENCY ${SPHINX_SOURCE}/conf.py
+ COMMENT "Generating documentation with Sphinx"
+)
+
+# Nice named target so we can run the job easily
+add_custom_target(Sphinx ALL DEPENDS ${SPHINX_INDEX_FILE})
+
+# Add an install target to install the docs
+include(GNUInstallDirs)
+install(DIRECTORY ${SPHINX_BUILD}
+DESTINATION ${CMAKE_INSTALL_DOCDIR})
diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in
new file mode 100644
index 00000000..3d01d126
--- /dev/null
+++ b/docs/Doxyfile.in
@@ -0,0 +1,7 @@
+INPUT = "@DOXYGEN_INPUT_DIR@"
+
+RECURSIVE = YES
+
+OUTPUT_DIRECTORY = "@DOXYGEN_OUTPUT_DIR@"
+
+GENERATE_XML = YES
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..d4bb2cbb
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/doc/README-config.md b/docs/README-config.md
similarity index 100%
rename from doc/README-config.md
rename to docs/README-config.md
diff --git a/doc/README-controllers.md b/docs/README-controllers.md
similarity index 100%
rename from doc/README-controllers.md
rename to docs/README-controllers.md
diff --git a/doc/README-core.md b/docs/README-core.md
similarity index 100%
rename from doc/README-core.md
rename to docs/README-core.md
diff --git a/doc/README-devicehandlers.md b/docs/README-devicehandlers.md
similarity index 100%
rename from doc/README-devicehandlers.md
rename to docs/README-devicehandlers.md
diff --git a/doc/README-highlevel.md b/docs/README-highlevel.md
similarity index 100%
rename from doc/README-highlevel.md
rename to docs/README-highlevel.md
diff --git a/doc/README-localpools.md b/docs/README-localpools.md
similarity index 98%
rename from doc/README-localpools.md
rename to docs/README-localpools.md
index 96ae2d0a..2ee75189 100644
--- a/doc/README-localpools.md
+++ b/docs/README-localpools.md
@@ -31,7 +31,9 @@ cohesive pool variables. These sets simply iterator over the list of variables a
`read` and `commit` functions of each variable. The following diagram shows the
high-level architecture of the local data pools.
-
+.. image:: ../misc/logo/FSFW_Logo_V3_bw.png
+ :alt: FSFW Logo
+
An example is shown for using the local data pools with a Gyroscope.
For example, the following code shows an implementation to access data from a Gyroscope taken
diff --git a/doc/README-osal.md b/docs/README-osal.md
similarity index 100%
rename from doc/README-osal.md
rename to docs/README-osal.md
diff --git a/doc/README-pus.md b/docs/README-pus.md
similarity index 100%
rename from doc/README-pus.md
rename to docs/README-pus.md
diff --git a/docs/api.rst b/docs/api.rst
new file mode 100644
index 00000000..d2ee6c69
--- /dev/null
+++ b/docs/api.rst
@@ -0,0 +1,16 @@
+API
+====
+
+.. toctree::
+ :maxdepth: 4
+
+ api/objectmanager
+ api/task
+ api/ipc
+ api/returnvalue
+ api/event
+ api/modes
+ api/health
+ api/action
+ api/devicehandler
+ api/controller
diff --git a/docs/api/action.rst b/docs/api/action.rst
new file mode 100644
index 00000000..31825b89
--- /dev/null
+++ b/docs/api/action.rst
@@ -0,0 +1,15 @@
+Action Module API
+=================
+
+``ActionHelper``
+-----------------
+
+.. doxygenclass:: ActionHelper
+ :members:
+
+``HasActionsIF``
+-----------------
+
+.. doxygenclass:: HasActionsIF
+ :members:
+ :protected-members:
diff --git a/docs/api/controller.rst b/docs/api/controller.rst
new file mode 100644
index 00000000..27136be6
--- /dev/null
+++ b/docs/api/controller.rst
@@ -0,0 +1,16 @@
+Controller API
+=================
+
+``ControllerBase``
+-------------------------
+
+.. doxygenclass:: ControllerBase
+ :members:
+ :protected-members:
+
+``ExtendedControllerBase``
+-----------------------------
+
+.. doxygenclass:: ExtendedControllerBase
+ :members:
+ :protected-members:
diff --git a/docs/api/devicehandler.rst b/docs/api/devicehandler.rst
new file mode 100644
index 00000000..f709b640
--- /dev/null
+++ b/docs/api/devicehandler.rst
@@ -0,0 +1,16 @@
+Device Handler Base API
+=========================
+
+``DeviceHandlerBase``
+-----------------------
+
+.. doxygenclass:: DeviceHandlerBase
+ :members:
+ :protected-members:
+
+``DeviceHandlerIF``
+-----------------------
+
+.. doxygenclass:: DeviceHandlerIF
+ :members:
+ :protected-members:
diff --git a/docs/api/event.rst b/docs/api/event.rst
new file mode 100644
index 00000000..7553c963
--- /dev/null
+++ b/docs/api/event.rst
@@ -0,0 +1,6 @@
+.. _eventapi:
+
+Event API
+============
+
+.. doxygenfile:: Event.h
diff --git a/docs/api/health.rst b/docs/api/health.rst
new file mode 100644
index 00000000..b1d4c1b2
--- /dev/null
+++ b/docs/api/health.rst
@@ -0,0 +1,9 @@
+Health API
+===========
+
+``HasHealthIF``
+------------------
+
+.. doxygenclass:: HasHealthIF
+ :members:
+ :protected-members:
diff --git a/docs/api/ipc.rst b/docs/api/ipc.rst
new file mode 100644
index 00000000..17a91f00
--- /dev/null
+++ b/docs/api/ipc.rst
@@ -0,0 +1,9 @@
+IPC Module API
+=================
+
+``MessageQueueIF``
+-------------------
+
+.. doxygenclass:: MessageQueueIF
+ :members:
+ :protected-members:
diff --git a/docs/api/modes.rst b/docs/api/modes.rst
new file mode 100644
index 00000000..7b6b0dca
--- /dev/null
+++ b/docs/api/modes.rst
@@ -0,0 +1,10 @@
+Modes API
+=========
+
+
+``HasModesIF``
+---------------
+
+.. doxygenclass:: HasModesIF
+ :members:
+ :protected-members:
diff --git a/docs/api/objectmanager.rst b/docs/api/objectmanager.rst
new file mode 100644
index 00000000..e90deb57
--- /dev/null
+++ b/docs/api/objectmanager.rst
@@ -0,0 +1,30 @@
+Object Manager API
+=========================
+
+``SystemObject``
+--------------------
+
+.. doxygenclass:: SystemObject
+ :members:
+ :protected-members:
+
+``ObjectManager``
+-----------------------
+
+.. doxygenclass:: ObjectManager
+ :members:
+ :protected-members:
+
+``SystemObjectIF``
+--------------------
+
+.. doxygenclass:: SystemObjectIF
+ :members:
+ :protected-members:
+
+``ObjectManagerIF``
+-----------------------
+
+.. doxygenclass:: ObjectManagerIF
+ :members:
+ :protected-members:
diff --git a/docs/api/returnvalue.rst b/docs/api/returnvalue.rst
new file mode 100644
index 00000000..b0d43916
--- /dev/null
+++ b/docs/api/returnvalue.rst
@@ -0,0 +1,10 @@
+.. _retvalapi:
+
+Returnvalue API
+==================
+
+.. doxygenfile:: HasReturnvaluesIF.h
+
+.. _fwclassids:
+
+.. doxygenfile:: FwClassIds.h
diff --git a/docs/api/task.rst b/docs/api/task.rst
new file mode 100644
index 00000000..b218dac1
--- /dev/null
+++ b/docs/api/task.rst
@@ -0,0 +1,8 @@
+Task API
+=========
+
+``ExecutableObjectIF``
+-----------------------
+
+.. doxygenclass:: ExecutableObjectIF
+ :members:
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 00000000..62b17192
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,56 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+
+# -- Project information -----------------------------------------------------
+
+project = 'Flight Software Framework'
+copyright = '2021, Institute of Space Systems (IRS)'
+author = 'Institute of Space Systems (IRS)'
+
+# The full version, including alpha/beta/rc tags
+release = '2.0.1'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [ "breathe" ]
+
+breathe_default_project = "fsfw"
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'alabaster'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
\ No newline at end of file
diff --git a/docs/config.rst b/docs/config.rst
new file mode 100644
index 00000000..ed317aed
--- /dev/null
+++ b/docs/config.rst
@@ -0,0 +1,41 @@
+Configuring the FSFW
+=====================
+
+The FSFW can be configured via the ``fsfwconfig`` folder. A template folder has been provided in
+``misc/defaultcfg`` to have a starting point for this. The folder should be added
+to the include path. The primary configuration file is the ``FSFWConfig.h`` folder. Some
+of the available options will be explained in more detail here.
+
+Auto-Translation of Events
+----------------------------
+
+The FSFW allows the automatic translation of events, which allows developers to track triggered
+events directly via console output. Using this feature requires:
+
+1. ``FSFW_OBJ_EVENT_TRANSLATION`` set to 1 in the configuration file.
+2. Special auto-generated translation files which translate event IDs and object IDs into
+ human readable strings. These files can be generated using the
+ `fsfwgen Python scripts `_.
+3. The generated translation files for the object IDs should be named ``translatesObjects.cpp``
+ and ``translateObjects.h`` and should be copied to the ``fsfwconfig/objects`` folder
+4. The generated translation files for the event IDs should be named ``translateEvents.cpp`` and
+ ``translateEvents.h`` and should be copied to the ``fsfwconfig/events`` folder
+
+An example implementations of these translation file generators can be found as part
+of the `SOURCE project here `_
+or the `FSFW example `_
+
+Configuring the Event Manager
+----------------------------------
+
+The number of allowed subscriptions can be modified with the following
+parameters:
+
+.. code-block:: cpp
+
+ namespace fsfwconfig {
+ //! Configure the allocated pool sizes for the event manager.
+ static constexpr size_t FSFW_EVENTMGMR_MATCHTREE_NODES = 240;
+ static constexpr size_t FSFW_EVENTMGMT_EVENTIDMATCHERS = 120;
+ static constexpr size_t FSFW_EVENTMGMR_RANGEMATCHERS = 120;
+ }
diff --git a/docs/controllers.rst b/docs/controllers.rst
new file mode 100644
index 00000000..28f57393
--- /dev/null
+++ b/docs/controllers.rst
@@ -0,0 +1,2 @@
+Controllers
+=============
diff --git a/docs/core.rst b/docs/core.rst
new file mode 100644
index 00000000..ef6f6165
--- /dev/null
+++ b/docs/core.rst
@@ -0,0 +1,70 @@
+.. _core:
+
+Core Modules
+=============
+
+The core modules provide the most important functionalities of the Flight Software Framework.
+
+Clock
+------
+
+- This is a class of static functions that can be used at anytime
+- Leap Seconds must be set if any time conversions from UTC to other times is used
+
+Object Manager
+---------------
+
+- Must be created during program startup
+- The component which handles all references. All :cpp:class:`SystemObject`\s register at this
+ component.
+- All :cpp:class:`SystemObject`\s needs to have a unique Object ID. Those can be managed like
+ framework objects.
+- A reference to an object can be retrieved by calling the ``get`` function of
+ :cpp:class:`ObjectManagerIF`. The target type must be specified as a template argument.
+ A ``nullptr`` check of the returning pointer must be done. This function is based on
+ run-time type information.
+
+ .. code-block:: cpp
+
+ template T* ObjectManagerIF::get(object_id_t id);
+
+- A typical way to create all objects on startup is a handing a static produce function to the
+ ObjectManager on creation. By calling ``ObjectManager::instance()->initialize(produceFunc)`` the
+ produce function will be called and all :cpp:class:`SystemObject`\s will be initialized
+ afterwards.
+
+Event Manager
+---------------
+
+- Component which allows routing of events
+- Other objects can subscribe to specific events, ranges of events or all events of an object.
+- Subscriptions can be done during runtime but should be done during initialization
+- Amounts of allowed subscriptions can be configured in ``FSFWConfig.h``
+
+Health Table
+---------------
+
+- A component which holds every health state
+- Provides a thread safe way to access all health states without the need of message exchanges
+
+Stores
+--------------
+
+- The message based communication can only exchange a few bytes of information inside the message
+ itself. Therefore, additional information can be exchanged with Stores. With this, only the
+ store address must be exchanged in the message.
+- Internally, the FSFW uses an IPC Store to exchange data between processes. For incoming TCs a TC
+ Store is used. For outgoing TM a TM store is used.
+- All of them should use the Thread Safe Class storagemanager/PoolManager
+
+Tasks
+---------
+
+There are two different types of tasks:
+
+- The PeriodicTask just executes objects that are of type ExecutableObjectIF in the order of the
+ insertion to the Tasks.
+- FixedTimeslotTask executes a list of calls in the order of the given list. This is intended for
+ DeviceHandlers, where polling should be in a defined order. An example can be found in
+ ``defaultcfg/fsfwconfig/pollingSequence`` folder
+
diff --git a/docs/devicehandlers.rst b/docs/devicehandlers.rst
new file mode 100644
index 00000000..58c2df78
--- /dev/null
+++ b/docs/devicehandlers.rst
@@ -0,0 +1,3 @@
+Device Handlers
+==================
+
diff --git a/doc/doxy/.gitignore b/docs/doxy/.gitignore
similarity index 100%
rename from doc/doxy/.gitignore
rename to docs/doxy/.gitignore
diff --git a/doc/doxy/OPUS.doxyfile b/docs/doxy/OPUS.doxyfile
similarity index 100%
rename from doc/doxy/OPUS.doxyfile
rename to docs/doxy/OPUS.doxyfile
diff --git a/docs/getting_started.rst b/docs/getting_started.rst
new file mode 100644
index 00000000..069e98cd
--- /dev/null
+++ b/docs/getting_started.rst
@@ -0,0 +1,115 @@
+Getting Started
+================
+
+
+Getting started
+----------------
+
+The `Hosted FSFW example`_ provides a good starting point and a demo to see the FSFW capabilities.
+It is recommended to get started by building and playing around with the demo application.
+There are also other examples provided for all OSALs using the popular embedded platforms
+Raspberry Pi, Beagle Bone Black and STM32H7.
+
+Generally, the FSFW is included in a project by providing
+a configuration folder, building the static library and linking against it.
+There are some functions like ``printChar`` which are different depending on the target architecture
+and need to be implemented by the mission developer.
+
+A template configuration folder was provided and can be copied into the project root to have
+a starting point. The [configuration section](docs/README-config.md#top) provides more specific
+information about the possible options.
+
+Adding the library
+-------------------
+
+The following steps show how to add and use FSFW components. It is still recommended to
+try out the example mentioned above to get started, but the following steps show how to
+add and link against the FSFW library in general.
+
+1. Add this repository as a submodule
+
+ .. code-block:: console
+
+ git submodule add https://egit.irs.uni-stuttgart.de/fsfw/fsfw.git fsfw
+
+2. Add the following directive inside the uppermost ``CMakeLists.txt`` file of your project
+
+ .. code-block:: cmake
+
+ add_subdirectory(fsfw)
+
+3. Make sure to provide a configuration folder and supply the path to that folder with
+ the `FSFW_CONFIG_PATH` CMake variable from the uppermost `CMakeLists.txt` file.
+ It is also necessary to provide the `printChar` function. You can find an example
+ implementation for a hosted build
+ `here `_.
+
+4. Link against the FSFW library
+
+ .. code-block:: cmake
+
+ target_link_libraries( PRIVATE fsfw)
+
+
+5. It should now be possible use the FSFW as a static library from the user code.
+
+Building the unittests
+-------------------------
+
+The FSFW also has unittests which use the `Catch2 library`_.
+These are built by setting the CMake option ``FSFW_BUILD_UNITTESTS`` to ``ON`` or `TRUE`
+from your project `CMakeLists.txt` file or from the command line.
+
+The fsfw-tests binary will be built as part of the static library and dropped alongside it.
+If the unittests are built, the library and the tests will be built with coverage information by
+default. This can be disabled by setting the `FSFW_TESTS_COV_GEN` option to `OFF` or `FALSE`.
+
+You can use the following commands inside the ``fsfw`` folder to set up the build system
+
+.. code-block:: console
+
+ mkdir build-tests && cd build-tests
+ cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host ..
+
+
+You can also use ``-DFSFW_OSAL=linux`` on Linux systems.
+
+Coverage data in HTML format can be generated using the `Code coverage`_ CMake module.
+To build the unittests, run them and then generare the coverage data in this format,
+the following command can be used inside the build directory after the build system was set up
+
+.. code-block:: console
+
+ cmake --build . -- fsfw-tests_coverage -j
+
+
+The ``helper.py`` script located in the ``script`` folder can also be used to create, build
+and open the unittests conveniently. Try ``helper.py -h`` for more information.
+
+Building the documentation
+----------------------------
+
+The FSFW documentation is built using the tools Sphinx, doxygen and breathe based on the
+instructions provided in `this blogpost `_. You can set up a
+documentation build system using the following commands
+
+.. code-block:: bash
+
+ mkdir build-docs && cd build-docs
+ cmake -DFSFW_BUILD_DOCS=ON -DFSFW_OSAL=host ..
+
+Then you can generate the documentation using
+
+.. code-block:: bash
+
+ cmake --build . -j
+
+You can find the generated documentation inside the ``docs/sphinx`` folder inside the build
+folder. Simply open the ``index.html`` in the webbrowser of your choice.
+
+The ``helper.py`` script located in the ``script`` folder can also be used to create, build
+and open the documentation conveniently. Try ``helper.py -h`` for more information.
+
+.. _`Hosted FSFW example`: https://egit.irs.uni-stuttgart.de/fsfw/fsfw-example-hosted
+.. _`Catch2 library`: https://github.com/catchorg/Catch2
+.. _`Code coverage`: https://github.com/bilke/cmake-modules/tree/master
diff --git a/docs/highlevel.rst b/docs/highlevel.rst
new file mode 100644
index 00000000..08f44777
--- /dev/null
+++ b/docs/highlevel.rst
@@ -0,0 +1,149 @@
+.. _highlevel:
+
+High-level overview
+===================
+
+Structure
+----------
+
+The general structure is driven by the usage of interfaces provided by objects.
+The FSFW uses C++11 as baseline. The intention behind this is that this C++ Standard should be
+widely available, even with older compilers.
+The FSFW uses dynamic allocation during the initialization but provides static containers during runtime.
+This simplifies the instantiation of objects and allows the usage of some standard containers.
+Dynamic Allocation after initialization is discouraged and different solutions are provided in the
+FSFW to achieve that. The fsfw uses run-time type information but exceptions are not allowed.
+
+Failure Handling
+-----------------
+
+Functions should return a defined :cpp:type:`ReturnValue_t` to signal to the caller that something has
+gone wrong. Returnvalues must be unique. For this the function :cpp:func:`HasReturnvaluesIF::makeReturnCode`
+or the :ref:`macro MAKE_RETURN_CODE ` can be used. The ``CLASS_ID`` is a unique ID for that type of object.
+See the :ref:`FSFW Class IDs file `. The user can add custom ``CLASS_ID``\s via the
+``fsfwconfig`` folder.
+
+OSAL
+------------
+
+The FSFW provides operation system abstraction layers for Linux, FreeRTOS and RTEMS.
+The OSAL provides periodic tasks, message queues, clocks and semaphores as well as mutexes.
+The :ref:`OSAL README ` provides more detailed information on provided components
+and how to use them.
+
+Core Components
+----------------
+
+The FSFW has following core components. More detailed informations can be found in the
+:ref:`core component section `:
+
+1. Tasks: Abstraction for different (periodic) task types like periodic tasks or tasks
+ with fixed timeslots
+2. ObjectManager: This module stores all `SystemObjects` by mapping a provided unique object ID
+ to the object handles.
+3. Static Stores: Different stores are provided to store data of variable size (like telecommands
+ or small telemetry) in a pool structure without using dynamic memory allocation.
+ These pools are allocated up front.
+4. Clock: This module provided common time related functions
+5. EventManager: This module allows routing of events generated by `SystemObjects`
+6. HealthTable: A component which stores the health states of objects
+
+Static IDs in the framework
+--------------------------------
+
+Some parts of the framework use a static routing address for communication.
+An example setup of IDs can be found in the example config in ``misc/defaultcfg/fsfwconfig/objects``
+inside the function ``Factory::setStaticFrameworkObjectIds``.
+
+Events
+----------------
+
+Events are tied to objects. EventIds can be generated by calling the
+:ref:`macro MAKE_EVENT ` or the function :cpp:func:`event::makeEvent`.
+This works analog to the returnvalues. Every object that needs own Event IDs has to get a
+unique ``SUBSYSTEM_ID``. Every :cpp:class:`SystemObject` can call
+:cpp:func:`SystemObject::triggerEvent` from the parent class.
+Therefore, event messages contain the specific EventId and the objectId of the object that
+has triggered.
+
+Internal Communication
+-------------------------
+
+Components communicate mostly via Messages through Queues.
+Those queues are created by calling the singleton ``QueueFactory::instance()->create`` which
+will create `MessageQueue` instances for the used OSAL.
+
+External Communication
+--------------------------
+
+The external communication with the mission control system is mostly up to the user implementation.
+The FSFW provides PUS Services which can be used to but don't need to be used.
+The services can be seen as a conversion from a TC to a message based communication and back.
+
+TMTC Communication
+~~~~~~~~~~~~~~~~~~~
+
+The FSFW provides some components to facilitate TMTC handling via the PUS commands.
+For example, a UDP or TCP PUS server socket can be opened on a specific port using the
+files located in ``osal/common``. The FSFW example uses this functionality to allow sending
+telecommands and receiving telemetry using the
+`TMTC commander application `_.
+
+Simple commands like the PUS Service 17 ping service can be tested by simply running the
+``tmtc_client_cli.py`` or ``tmtc_client_gui.py`` utility in
+the `example tmtc folder `_
+while the `fsfw_example` application is running.
+
+More generally, any class responsible for handling incoming telecommands and sending telemetry
+can implement the generic ``TmTcBridge`` class located in ``tmtcservices``. Many applications
+also use a dedicated polling task for reading telecommands which passes telecommands
+to the ``TmTcBridge`` implementation.
+
+CCSDS Frames, CCSDS Space Packets and PUS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the communication is based on CCSDS Frames and Space Packets, several classes can be used to
+distributed the packets to the corresponding services. Those can be found in ``tcdistribution``.
+If Space Packets are used, a timestamper has to be provided by the user.
+An example can be found in the ``timemanager`` folder, which uses ``CCSDSTime::CDS_short``.
+
+Device Handlers
+--------------------------
+
+DeviceHandlers are another important component of the FSFW. The idea is, to have a software
+counterpart of every physical device to provide a simple mode, health and commanding interface.
+By separating the underlying Communication Interface with
+``DeviceCommunicationIF``, a device handler (DH) can be tested on different hardware.
+The DH has mechanisms to monitor the communication with the physical device which allow
+for FDIR reaction. Device Handlers can be created by implementing ``DeviceHandlerBase``.
+A standard FDIR component for the DH will be created automatically but can
+be overwritten by the user. More information on DeviceHandlers can be found in the
+related [documentation section](doc/README-devicehandlers.md#top).
+
+Modes and Health
+--------------------
+
+The two interfaces ``HasModesIF`` and ``HasHealthIF`` provide access for commanding and monitoring
+of components. On-board mode management is implement in hierarchy system.
+
+- Device handlers and controllers are the lowest part of the hierarchy.
+- The next layer are assemblies. Those assemblies act as a component which handle
+ redundancies of handlers. Assemblies share a common core with the top level subsystem components
+- The top level subsystem components are used to group assemblies, controllers and device handlers.
+ For example, a spacecraft can have a atttitude control subsystem and a power subsystem.
+
+Those assemblies are intended to act as auto-generated components from a database which describes
+the subsystem modes. The definitions contain transition and target tables which contain the DH,
+Assembly and Controller Modes to be commanded.
+Transition tables contain as many steps as needed to reach the mode from any other mode, e.g. a
+switch into any higher AOCS mode might first turn on the sensors, than the actuators and the
+controller as last component.
+The target table is used to describe the state that is checked continuously by the subsystem.
+All of this allows System Modes to be generated as Subsystem object as well from the same database.
+This System contains list of subsystem modes in the transition and target tables.
+Therefore, it allows a modular system to create system modes and easy commanding of those, because
+only the highest components must be commanded.
+
+The health state represents if the component is able to perform its tasks.
+This can be used to signal the system to avoid using this component instead of a redundant one.
+The on-board FDIR uses the health state for isolation and recovery.
diff --git a/doc/images/PoolArchitecture.png b/docs/images/PoolArchitecture.png
similarity index 100%
rename from doc/images/PoolArchitecture.png
rename to docs/images/PoolArchitecture.png
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 00000000..b37c0904
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,69 @@
+.. Flight Software Framework documentation master file, created by
+ sphinx-quickstart on Tue Nov 30 10:56:03 2021.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Flight Software Framework (FSFW) documentation
+================================================
+
+.. image:: ../misc/logo/FSFW_Logo_V3_bw.png
+ :alt: FSFW Logo
+
+The Flight Software Framework is a C++ Object Oriented Framework for unmanned,
+automated systems like Satellites.
+
+The initial version of the Flight Software Framework was developed during
+the Flying Laptop Project by the University of Stuttgart in cooperation
+with Airbus Defence and Space GmbH.
+
+Quick facts
+---------------
+
+The framework is designed for systems, which communicate with external devices, perform control
+loops, receive telecommands and send telemetry, and need to maintain a high level of availability.
+Therefore, a mode and health system provides control over the states of the software and the
+controlled devices. In addition, a simple mechanism of event based fault detection, isolation and
+recovery is implemented as well.
+
+The FSFW provides abstraction layers for operating systems to provide a uniform operating system
+abstraction layer (OSAL). Some components of this OSAL are required internally by the FSFW but is
+also very useful for developers to implement the same application logic on different operating
+systems with a uniform interface.
+
+Currently, the FSFW provides the following OSALs:
+
+- Linux
+- Host
+- FreeRTOS
+- RTEMS
+
+The recommended hardware is a microprocessor with more than 1 MB of RAM and 1 MB of non-volatile
+memory. For reference, current applications use a Cobham Gaisler UT699 (LEON3FT), a
+ISISPACE IOBC or a Zynq-7020 SoC. The ``fsfw`` was also successfully run on the
+STM32H743ZI-Nucleo board and on a Raspberry Pi and is currently running on the active
+satellite mission Flying Laptop.
+
+Index
+-------
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Contents:
+
+ getting_started
+ highlevel
+ core
+ config
+ osal
+ pus
+ devicehandlers
+ controllers
+ localpools
+ api
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
diff --git a/docs/localpools.rst b/docs/localpools.rst
new file mode 100644
index 00000000..d2afd0a0
--- /dev/null
+++ b/docs/localpools.rst
@@ -0,0 +1,181 @@
+Local Data Pools
+=========================================
+
+The following text is targeted towards mission software developers which would like
+to use the local data pools provided by the FSFW to store data like sensor values so they can be
+used by other software objects like controllers as well. If a custom class should have a local
+pool which can be used by other software objects as well, following steps have to be performed:
+
+1. Create a ``LocalDataPoolManager`` member object in the custom class
+2. Implement the ``HasLocalDataPoolIF`` with specifies the interface between the local pool
+ manager and the class owning the local pool.
+
+The local data pool manager is also able to process housekeeping service requests in form
+of messages, generate periodic housekeeping packet, generate notification and snapshots of changed
+variables and datasets and process notifications and snapshots coming from other objects.
+The two former tasks are related to the external interface using telemetry and telecommands (TMTC)
+while the later two are related to data consumers like controllers only acting on data change
+detected by the data creator instead of checking the data manually each cycle. Two important
+framework classes ``DeviceHandlerBase`` and ``ExtendedControllerBase`` already perform the two steps
+shown above so the steps required are altered slightly.
+
+Storing and Accessing pool data
+-------------------------------------
+
+The pool manager is responsible for thread-safe access of the pool data, but the actual
+access to the pool data from the point of view of a mission software developer happens via proxy
+classes like pool variable classes. These classes store a copy
+of the pool variable with the matching datatype and copy the actual data from the local pool
+on a ``read`` call. Changed variables can then be written to the local pool with a ``commit`` call.
+The ``read`` and ``commit`` calls are thread-safe and can be called concurrently from data creators
+and data consumers. Generally, a user will create a dataset class which in turn groups all
+cohesive pool variables. These sets simply iterator over the list of variables and call the
+``read`` and ``commit`` functions of each variable. The following diagram shows the
+high-level architecture of the local data pools.
+
+.. image:: ../docs/images/PoolArchitecture.png
+ :alt: Pool Architecture
+
+An example is shown for using the local data pools with a Gyroscope.
+For example, the following code shows an implementation to access data from a Gyroscope taken
+from the SOURCE CubeSat project:
+
+.. code-block:: cpp
+
+ class GyroPrimaryDataset: public StaticLocalDataSet<3 * sizeof(float)> {
+ public:
+ /**
+ * Constructor for data users
+ * @param gyroId
+ */
+ GyroPrimaryDataset(object_id_t gyroId):
+ StaticLocalDataSet(sid_t(gyroId, gyrodefs::GYRO_DATA_SET_ID)) {
+ setAllVariablesReadOnly();
+ }
+
+ lp_var_t angVelocityX = lp_var_t(sid.objectId,
+ gyrodefs::ANGULAR_VELOCITY_X, this);
+ lp_var_t angVelocityY = lp_var_t(sid.objectId,
+ gyrodefs::ANGULAR_VELOCITY_Y, this);
+ lp_var_t angVelocityZ = lp_var_t(sid.objectId,
+ gyrodefs::ANGULAR_VELOCITY_Z, this);
+ private:
+
+ friend class GyroHandler;
+ /**
+ * Constructor for data creator
+ * @param hkOwner
+ */
+ GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner):
+ StaticLocalDataSet(hkOwner, gyrodefs::GYRO_DATA_SET_ID) {}
+ };
+
+There is a public constructor for users which sets all variables to read-only and there is a
+constructor for the GyroHandler data creator by marking it private and declaring the ``GyroHandler``
+as a friend class. Both the atittude controller and the ``GyroHandler`` can now
+use the same class definition to access the pool variables with ``read`` and ``commit`` semantics
+in a thread-safe way. Generally, each class requiring access will have the set class as a member
+class. The data creator will also be generally a ``DeviceHandlerBase`` subclass and some additional
+steps are necessary to expose the set for housekeeping purposes.
+
+Using the local data pools in a ``DeviceHandlerBase`` subclass
+--------------------------------------------------------------
+
+It is very common to store data generated by devices like a sensor into a pool which can
+then be used by other objects. Therefore, the ``DeviceHandlerBase`` already has a
+local pool. Using the aforementioned example, the ``GyroHandler`` will now have the set class
+as a member:
+
+.. code-block:: cpp
+
+ class GyroHandler: ... {
+
+ public:
+ ...
+ private:
+ ...
+ GyroPrimaryDataset gyroData;
+ ...
+ };
+
+
+The constructor used for the creators expects the owner class as a parameter, so we initialize
+the object in the `GyroHandler` constructor like this:
+
+.. code-block:: cpp
+
+ GyroHandler::GyroHandler(object_id_t objectId, object_id_t comIF,
+ CookieIF *comCookie, uint8_t switchId):
+ DeviceHandlerBase(objectId, comIF, comCookie), switchId(switchId),
+ gyroData(this) {}
+
+
+We need to assign the set to a reply ID used in the ``DeviceHandlerBase``.
+The combination of the ``GyroHandler`` object ID and the reply ID will be the 64-bit structure ID
+``sid_t`` and is used to globally identify the set, for example when requesting housekeeping data or
+generating update messages. We need to assign our custom set class in some way so that the local
+pool manager can access the custom data sets as well.
+By default, the ``getDataSetHandle`` will take care of this tasks. The default implementation for a
+``DeviceHandlerBase`` subclass will use the internal command map to retrieve
+a handle to a dataset from a given reply ID. Therefore,
+we assign the set in the ``fillCommandAndReplyMap`` function:
+
+.. code-block:: cpp
+
+ void GyroHandler::fillCommandAndReplyMap() {
+ ...
+ this->insertInCommandAndReplyMap(gyrodefs::GYRO_DATA, 3, &gyroData);
+ ...
+ }
+
+
+Now, we need to create the actual pool entries as well, using the ``initializeLocalDataPool``
+function. Here, we also immediately subscribe for periodic housekeeping packets
+with an interval of 4 seconds. They are still disabled in this example and can be enabled
+with a housekeeping service command.
+
+.. code-block:: cpp
+
+ ReturnValue_t GyroHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
+ LocalDataPoolManager &poolManager) {
+ localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_X,
+ new PoolEntry({0.0}));
+ localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Y,
+ new PoolEntry({0.0}));
+ localDataPoolMap.emplace(gyrodefs::ANGULAR_VELOCITY_Z,
+ new PoolEntry({0.0}));
+ localDataPoolMap.emplace(gyrodefs::GENERAL_CONFIG_REG42,
+ new PoolEntry({0}));
+ localDataPoolMap.emplace(gyrodefs::RANGE_CONFIG_REG43,
+ new PoolEntry({0}));
+
+ poolManager.subscribeForPeriodicPacket(gyroData.getSid(), false, 4.0, false);
+ return HasReturnvaluesIF::RETURN_OK;
+ }
+
+Now, if we receive some sensor data and converted them into the right format,
+we can write it into the pool like this, using a guard class to ensure the set is commited back
+in any case:
+
+.. code-block:: cpp
+
+ PoolReadGuard readHelper(&gyroData);
+ if(readHelper.getReadResult() == HasReturnvaluesIF::RETURN_OK) {
+ if(not gyroData.isValid()) {
+ gyroData.setValidity(true, true);
+ }
+
+ gyroData.angVelocityX = angularVelocityX;
+ gyroData.angVelocityY = angularVelocityY;
+ gyroData.angVelocityZ = angularVelocityZ;
+ }
+
+
+The guard class will commit the changed data on destruction automatically.
+
+Using the local data pools in a ``ExtendedControllerBase`` subclass
+----------------------------------------------------------------------
+
+Coming soon
+
+
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 00000000..922152e9
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.http://sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/docs/osal.rst b/docs/osal.rst
new file mode 100644
index 00000000..7ac66e47
--- /dev/null
+++ b/docs/osal.rst
@@ -0,0 +1,63 @@
+.. _osal:
+
+Operating System Abstraction Layer (OSAL)
+============================================
+
+Some specific information on the provided OSALs are provided.
+
+Linux
+-------
+
+This OSAL can be used to compile for Linux host systems like Ubuntu 20.04 or for
+embedded Linux targets like the Raspberry Pi. This OSAL generally requires threading support
+and real-time functionalities. For most UNIX systems, this is done by adding ``-lrt`` and
+``-lpthread`` to the linked libraries in the compilation process. The CMake build support provided
+will do this automatically for the ``fsfw`` target. It should be noted that most UNIX systems need
+to be configured specifically to allow the real-time functionalities required by the FSFW.
+
+Hosted OSAL
+-------------------
+
+This is the newest OSAL. Support for Semaphores has not been implemented yet and will propably be
+implemented as soon as C++20 with Semaphore support has matured. This OSAL can be used to run the
+FSFW on any host system, but currently has only been tested on Windows 10 and Ubuntu 20.04. Unlike
+the other OSALs, it uses dynamic memory allocation (e.g. for the message queue implementation).
+Cross-platform serial port (USB) support might be added soon.
+
+FreeRTOS OSAL
+------------------
+
+FreeRTOS is not included and the developer needs to take care of compiling the FreeRTOS sources and
+adding the ``FreeRTOSConfig.h`` file location to the include path. This OSAL has only been tested
+extensively with the pre-emptive scheduler configuration so far but it should in principle also be
+possible to use a cooperative scheduler. It is recommended to use the `heap_4` allocation scheme.
+When using newlib (nano), it is also recommended to add ``#define configUSE_NEWLIB_REENTRANT`` to
+the FreeRTOS configuration file to ensure thread-safety.
+
+When using this OSAL, developers also need to provide an implementation for the
+``vRequestContextSwitchFromISR`` function. This has been done because the call to request a context
+switch from an ISR is generally located in the ``portmacro.h`` header and is different depending on
+the target architecture or device.
+
+RTEMS OSAL
+---------------
+
+The RTEMS OSAL was the first implemented OSAL which is also used on the active satellite Flying Laptop.
+
+TCP/IP socket abstraction
+------------------------------
+
+The Linux and Host OSAL provide abstraction layers for the socket API. Currently, only UDP sockets
+have been imlemented. This is very useful to test TMTC handling either on the host computer
+directly (targeting localhost with a TMTC application) or on embedded Linux devices, sending
+TMTC packets via Ethernet.
+
+Example Applications
+----------------------
+
+There are example applications available for each OSAL
+
+- `Hosted OSAL `_
+- `Linux OSAL for MCUs `_
+- `FreeRTOS OSAL on the STM32H743ZIT `_
+- `RTEMS OSAL on the STM32H743ZIT `_
diff --git a/docs/pus.rst b/docs/pus.rst
new file mode 100644
index 00000000..8dbb2104
--- /dev/null
+++ b/docs/pus.rst
@@ -0,0 +1,2 @@
+PUS Services
+==============
diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt
index 7a9a0ffa..424a012d 100644
--- a/hal/CMakeLists.txt
+++ b/hal/CMakeLists.txt
@@ -3,7 +3,13 @@ cmake_minimum_required(VERSION 3.13)
# Can also be changed by upper CMakeLists.txt file
find_library(LIB_FSFW_NAME fsfw REQUIRED)
-option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Required gpiod library" OFF)
+option(FSFW_HAL_ADD_LINUX "Add the Linux HAL to the sources. Requires gpiod library" OFF)
+# On by default for now because I did not have an issue including and compiling those files
+# and libraries on a Desktop Linux system and the primary target of the FSFW is still embedded
+# Linux. The only exception from this is the gpiod library which requires a dedicated installation,
+# but CMake is able to determine whether this library is installed with find_library.
+option(FSFW_HAL_LINUX_ADD_PERIPHERAL_DRIVERS "Add peripheral drivers for embedded Linux" ON)
+
option(FSFW_HAL_ADD_RASPBERRY_PI "Add Raspberry Pi specific code to the sources" OFF)
option(FSFW_HAL_ADD_STM32H7 "Add the STM32H7 HAL to the sources" OFF)
option(FSFW_HAL_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON)
diff --git a/hal/src/fsfw_hal/CMakeLists.txt b/hal/src/fsfw_hal/CMakeLists.txt
index f5901e91..b7559d4b 100644
--- a/hal/src/fsfw_hal/CMakeLists.txt
+++ b/hal/src/fsfw_hal/CMakeLists.txt
@@ -1,7 +1,7 @@
add_subdirectory(devicehandlers)
add_subdirectory(common)
-if(FSFW_HAL_ADD_LINUX)
+if(UNIX)
add_subdirectory(linux)
endif()
diff --git a/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp b/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp
index 7c56ebcf..4c4b4d14 100644
--- a/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp
+++ b/hal/src/fsfw_hal/common/gpio/GpioCookie.cpp
@@ -1,50 +1,48 @@
#include "fsfw_hal/common/gpio/GpioCookie.h"
+
#include "fsfw/serviceinterface/ServiceInterface.h"
-GpioCookie::GpioCookie() {
-}
+GpioCookie::GpioCookie() {}
ReturnValue_t GpioCookie::addGpio(gpioId_t gpioId, GpioBase* gpioConfig) {
- if (gpioConfig == nullptr) {
+ if (gpioConfig == nullptr) {
#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "GpioCookie::addGpio: gpioConfig is nullpointer" << std::endl;
+ sif::warning << "GpioCookie::addGpio: gpioConfig is nullpointer" << std::endl;
#else
- sif::printWarning("GpioCookie::addGpio: gpioConfig is nullpointer\n");
-#endif
- return HasReturnvaluesIF::RETURN_FAILED;
- }
- auto gpioMapIter = gpioMap.find(gpioId);
- if(gpioMapIter == gpioMap.end()) {
- auto statusPair = gpioMap.emplace(gpioId, gpioConfig);
- if (statusPair.second == false) {
-#if FSFW_VERBOSE_LEVEL >= 1
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "GpioCookie::addGpio: Failed to add GPIO " << gpioId <<
- " to GPIO map" << std::endl;
-#else
- sif::printWarning("GpioCookie::addGpio: Failed to add GPIO %d to GPIO map\n", gpioId);
-#endif
-#endif
- return HasReturnvaluesIF::RETURN_FAILED;
- }
- return HasReturnvaluesIF::RETURN_OK;
- }
-#if FSFW_VERBOSE_LEVEL >= 1
-#if FSFW_CPP_OSTREAM_ENABLED == 1
- sif::warning << "GpioCookie::addGpio: GPIO already exists in GPIO map " << std::endl;
-#else
- sif::printWarning("GpioCookie::addGpio: GPIO already exists in GPIO map\n");
-#endif
+ sif::printWarning("GpioCookie::addGpio: gpioConfig is nullpointer\n");
#endif
return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ auto gpioMapIter = gpioMap.find(gpioId);
+ if (gpioMapIter == gpioMap.end()) {
+ auto statusPair = gpioMap.emplace(gpioId, gpioConfig);
+ if (statusPair.second == false) {
+#if FSFW_VERBOSE_LEVEL >= 1
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::warning << "GpioCookie::addGpio: Failed to add GPIO " << gpioId << " to GPIO map"
+ << std::endl;
+#else
+ sif::printWarning("GpioCookie::addGpio: Failed to add GPIO %d to GPIO map\n", gpioId);
+#endif
+#endif
+ return HasReturnvaluesIF::RETURN_FAILED;
+ }
+ return HasReturnvaluesIF::RETURN_OK;
+ }
+#if FSFW_VERBOSE_LEVEL >= 1
+#if FSFW_CPP_OSTREAM_ENABLED == 1
+ sif::warning << "GpioCookie::addGpio: GPIO already exists in GPIO map " << std::endl;
+#else
+ sif::printWarning("GpioCookie::addGpio: GPIO already exists in GPIO map\n");
+#endif
+#endif
+ return HasReturnvaluesIF::RETURN_FAILED;
}
-GpioMap GpioCookie::getGpioMap() const {
- return gpioMap;
-}
+GpioMap GpioCookie::getGpioMap() const { return gpioMap; }
GpioCookie::~GpioCookie() {
- for(auto& config: gpioMap) {
- delete(config.second);
- }
+ for (auto& config : gpioMap) {
+ delete (config.second);
+ }
}
diff --git a/hal/src/fsfw_hal/common/gpio/GpioCookie.h b/hal/src/fsfw_hal/common/gpio/GpioCookie.h
index 0473fe0f..cf836eae 100644
--- a/hal/src/fsfw_hal/common/gpio/GpioCookie.h
+++ b/hal/src/fsfw_hal/common/gpio/GpioCookie.h
@@ -1,12 +1,12 @@
#ifndef COMMON_GPIO_GPIOCOOKIE_H_
#define COMMON_GPIO_GPIOCOOKIE_H_
-#include "GpioIF.h"
-#include "gpioDefinitions.h"
-
#include
#include
+#include "GpioIF.h"
+#include "gpioDefinitions.h"
+
/**
* @brief Cookie for the GpioIF. Allows the GpioIF to determine which
* GPIOs to initialize and whether they should be configured as in- or
@@ -17,25 +17,24 @@
*
* @author J. Meier
*/
-class GpioCookie: public CookieIF {
-public:
+class GpioCookie : public CookieIF {
+ public:
+ GpioCookie();
- GpioCookie();
+ virtual ~GpioCookie();
- virtual ~GpioCookie();
+ ReturnValue_t addGpio(gpioId_t gpioId, GpioBase* gpioConfig);
- ReturnValue_t addGpio(gpioId_t gpioId, GpioBase* gpioConfig);
+ /**
+ * @brief Get map with registered GPIOs.
+ */
+ GpioMap getGpioMap() const;
- /**
- * @brief Get map with registered GPIOs.
- */
- GpioMap getGpioMap() const;
-
-private:
- /**
- * Returns a copy of the internal GPIO map.
- */
- GpioMap gpioMap;
+ private:
+ /**
+ * Returns a copy of the internal GPIO map.
+ */
+ GpioMap gpioMap;
};
#endif /* COMMON_GPIO_GPIOCOOKIE_H_ */
diff --git a/hal/src/fsfw_hal/common/gpio/GpioIF.h b/hal/src/fsfw_hal/common/gpio/GpioIF.h
index af73f94c..5cca1481 100644
--- a/hal/src/fsfw_hal/common/gpio/GpioIF.h
+++ b/hal/src/fsfw_hal/common/gpio/GpioIF.h
@@ -1,9 +1,10 @@
#ifndef COMMON_GPIO_GPIOIF_H_
#define COMMON_GPIO_GPIOIF_H_
-#include "gpioDefinitions.h"
-#include
#include
+#include
+
+#include "gpioDefinitions.h"
class GpioCookie;
@@ -13,42 +14,41 @@ class GpioCookie;
* @author J. Meier
*/
class GpioIF : public HasReturnvaluesIF {
-public:
+ public:
+ virtual ~GpioIF(){};
- virtual ~GpioIF() {};
+ /**
+ * @brief Called by the GPIO using object.
+ * @param cookie Cookie specifying informations of the GPIOs required
+ * by a object.
+ */
+ virtual ReturnValue_t addGpios(GpioCookie* cookie) = 0;
- /**
- * @brief Called by the GPIO using object.
- * @param cookie Cookie specifying informations of the GPIOs required
- * by a object.
- */
- virtual ReturnValue_t addGpios(GpioCookie* cookie) = 0;
+ /**
+ * @brief By implementing this function a child must provide the
+ * functionality to pull a certain GPIO to high logic level.
+ *
+ * @param gpioId A unique number which specifies the GPIO to drive.
+ * @return Returns RETURN_OK for success. This should never return RETURN_FAILED.
+ */
+ virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0;
- /**
- * @brief By implementing this function a child must provide the
- * functionality to pull a certain GPIO to high logic level.
- *
- * @param gpioId A unique number which specifies the GPIO to drive.
- * @return Returns RETURN_OK for success. This should never return RETURN_FAILED.
- */
- virtual ReturnValue_t pullHigh(gpioId_t gpioId) = 0;
+ /**
+ * @brief By implementing this function a child must provide the
+ * functionality to pull a certain GPIO to low logic level.
+ *
+ * @param gpioId A unique number which specifies the GPIO to drive.
+ */
+ virtual ReturnValue_t pullLow(gpioId_t gpioId) = 0;
- /**
- * @brief By implementing this function a child must provide the
- * functionality to pull a certain GPIO to low logic level.
- *
- * @param gpioId A unique number which specifies the GPIO to drive.
- */
- virtual ReturnValue_t pullLow(gpioId_t gpioId) = 0;
-
- /**
- * @brief This function requires a child to implement the functionality to read the state of
- * an ouput or input gpio.
- *
- * @param gpioId A unique number which specifies the GPIO to read.
- * @param gpioState State of GPIO will be written to this pointer.
- */
- virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
+ /**
+ * @brief This function requires a child to implement the functionality to read the state of
+ * an ouput or input gpio.
+ *
+ * @param gpioId A unique number which specifies the GPIO to read.
+ * @param gpioState State of GPIO will be written to this pointer.
+ */
+ virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
};
#endif /* COMMON_GPIO_GPIOIF_H_ */
diff --git a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h
index c6f21195..b429449b 100644
--- a/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h
+++ b/hal/src/fsfw_hal/common/gpio/gpioDefinitions.h
@@ -1,44 +1,34 @@
#ifndef COMMON_GPIO_GPIODEFINITIONS_H_
#define COMMON_GPIO_GPIODEFINITIONS_H_
+#include