diff --git a/CMakeLists.txt b/CMakeLists.txt
index e78e8929..bb3d48b8 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)
@@ -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})
@@ -147,7 +152,7 @@ else()
set(OS_FSFW "host")
endif()
-if(FSFW_BUILD_UNITTESTS)
+if(FSFW_BUILD_UNITTESTS OR FSFW_BUILD_DOCS)
configure_file(src/fsfw/FSFW.h.in fsfw/FSFW.h)
configure_file(src/fsfw/FSFWVersion.h.in fsfw/FSFWVersion.h)
else()
@@ -163,6 +168,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)
@@ -234,9 +242,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..0facfc9a 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
@@ -109,14 +109,14 @@ The `coverage.py` script located in the `script` folder can also be used to do t
## 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/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/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/misc/defaultcfg/fsfwconfig/CMakeLists.txt b/misc/defaultcfg/fsfwconfig/CMakeLists.txt
index 178fc273..3b2064ba 100644
--- a/misc/defaultcfg/fsfwconfig/CMakeLists.txt
+++ b/misc/defaultcfg/fsfwconfig/CMakeLists.txt
@@ -1,23 +1,49 @@
-target_include_directories(${TARGET_NAME} PRIVATE
+if(DEFINED TARGET_NAME)
+ target_include_directories(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-target_sources(${TARGET_NAME} PRIVATE
- ipc/missionMessageTypes.cpp
- pollingsequence/PollingSequenceFactory.cpp
- objects/FsfwFactory.cpp
-)
-
-# If a special translation file for object IDs exists, compile it.
-if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
- target_sources(${TARGET_NAME} PRIVATE
- objects/translateObjects.cpp
)
-endif()
-# If a special translation file for events exists, compile it.
-if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
target_sources(${TARGET_NAME} PRIVATE
- events/translateEvents.cpp
+ ipc/missionMessageTypes.cpp
+ pollingsequence/PollingSequenceFactory.cpp
+ objects/FsfwFactory.cpp
)
+
+ # If a special translation file for object IDs exists, compile it.
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
+ target_sources(${TARGET_NAME} PRIVATE
+ objects/translateObjects.cpp
+ )
+ endif()
+
+ # If a special translation file for events exists, compile it.
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
+ target_sources(${TARGET_NAME} PRIVATE
+ events/translateEvents.cpp
+ )
+ endif()
+else()
+ target_include_directories(${LIB_FSFW_NAME} PRIVATE
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ )
+
+ target_sources(${LIB_FSFW_NAME} PRIVATE
+ ipc/missionMessageTypes.cpp
+ pollingsequence/PollingSequenceFactory.cpp
+ objects/FsfwFactory.cpp
+ )
+
+ # If a special translation file for object IDs exists, compile it.
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
+ target_sources(${LIB_FSFW_NAME} PRIVATE
+ objects/translateObjects.cpp
+ )
+ endif()
+
+ # If a special translation file for events exists, compile it.
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/objects/translateObjects.cpp")
+ target_sources(${LIB_FSFW_NAME} PRIVATE
+ events/translateEvents.cpp
+ )
+ endif()
endif()
diff --git a/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp
index 08ad41ec..5aef4980 100644
--- a/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp
+++ b/misc/defaultcfg/fsfwconfig/objects/FsfwFactory.cpp
@@ -7,7 +7,7 @@
#include
#include
#include
-#include
+#include
#include
@@ -48,6 +48,6 @@ void Factory::setStaticFrameworkObjectIds() {
DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT;
- TmPacketStored::timeStamperId = objects::NO_OBJECT;
+ TmPacketBase::timeStamperId = objects::NO_OBJECT;
}
diff --git a/scripts/coverage.py b/scripts/coverage.py
deleted file mode 100755
index b5bd7745..00000000
--- a/scripts/coverage.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*
-"""Small portable helper script to generate LCOV HTML coverage data"""
-import os
-import platform
-import sys
-import time
-import argparse
-import webbrowser
-from typing import List
-
-
-"""Copy this helper script into your project folder. It will try to determine a CMake build folder
-and then attempt to build your project with coverage information.
-
-See Unittest documentation at https://egit.irs.uni-stuttgart.de/fsfw/fsfw for more
-information how to set up the build folder.
-"""
-def main():
-
- parser = argparse.ArgumentParser(description="Processing arguments for LCOV helper script.")
- parser.add_argument(
- '-o', '--open', action='store_true', help='Open coverage data in webbrowser'
- )
- args = parser.parse_args()
-
- build_dir_list = []
- if not os.path.isfile('README.md'):
- os.chdir('..')
- for directory in os.listdir("."):
- if os.path.isdir(directory):
- os.chdir(directory)
- check_for_cmake_build_dir(build_dir_list)
- os.chdir("..")
-
- if len(build_dir_list) == 0:
- print("No valid CMake build directory found. Trying to set up hosted build")
- build_directory = 'build-Debug-Host'
- os.mkdir(build_directory)
- os.chdir(build_directory)
- os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..')
- os.chdir('..')
- elif len(build_dir_list) == 1:
- build_directory = build_dir_list[0]
- else:
- print("Multiple build directories found!")
- build_directory = determine_build_dir(build_dir_list)
- perform_lcov_operation(build_directory)
- if os.path.isdir('fsfw-tests_coverage') and args.open:
- webbrowser.open('fsfw-tests_coverage/index.html')
-
-
-def check_for_cmake_build_dir(build_dir_dict: list):
- if os.path.isfile("CMakeCache.txt"):
- build_dir_dict.append(os.getcwd())
-
-
-def perform_lcov_operation(directory):
- os.chdir(directory)
- os.system("cmake --build . -- fsfw-tests_coverage -j")
-
-
-def determine_build_dir(build_dir_list: List[str]):
- build_directory = ""
- for idx, directory in enumerate(build_dir_list):
- print(f"{idx + 1}: {directory}")
- while True:
- idx = input("Pick the directory to perform LCOV HTML generation by index: ")
- if not idx.isdigit():
- print("Invalid input!")
- continue
-
- idx = int(idx)
- if idx > len(build_dir_list) or idx < 1:
- print("Invalid input!")
- continue
- build_directory = build_dir_list[idx - 1]
- break
- return build_directory
-
-
-if __name__ == "__main__":
- main()
diff --git a/scripts/gen-unittest.sh b/scripts/gen-unittest.sh
deleted file mode 100755
index 9ca8c399..00000000
--- a/scripts/gen-unittest.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-mkdir build-Unittest && cd build-Unittest
-cmake -DFSFW_BUILD_UNITTESTS=ON -DFSFW_OSAL=host -DCMAKE_BUILD_TYPE=Debug ..
diff --git a/scripts/helper.py b/scripts/helper.py
new file mode 100755
index 00000000..0bb430ee
--- /dev/null
+++ b/scripts/helper.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*
+"""Small portable helper script to generate test or doc configuration for the
+flight software framework
+"""
+import os
+import argparse
+import webbrowser
+import shutil
+import sys
+import time
+from typing import List
+
+
+UNITTEST_FOLDER_NAME = 'build-tests'
+DOCS_FOLDER_NAME = 'build-docs'
+
+
+def main():
+
+ parser = argparse.ArgumentParser(description="FSFW helper script")
+ choices = ('docs', 'tests')
+ parser.add_argument(
+ 'type', metavar='type', choices=choices,
+ help=f'Target type. Choices: {choices}'
+ )
+ parser.add_argument(
+ '-a', '--all', action='store_true',
+ help='Create, build and open specified type'
+ )
+ parser.add_argument(
+ '-c', '--create', action='store_true',
+ help='Create docs or test build configuration'
+ )
+ parser.add_argument(
+ '-b', '--build', action='store_true',
+ help='Build the specified type'
+ )
+ parser.add_argument(
+ '-o', '--open', action='store_true',
+ help='Open test or documentation data in webbrowser'
+ )
+
+ args = parser.parse_args()
+ if args.all:
+ args.build = True
+ args.create = True
+ args.open = True
+ elif not args.build and not args.create and not args.open:
+ print(
+ 'Please select at least one operation to perform. '
+ 'Use helper.py -h for more information'
+ )
+ sys.exit(1)
+
+ # This script can be called from root and from script folder
+ if not os.path.isfile('README.md'):
+ os.chdir('..')
+ build_dir_list = []
+ if not args.create:
+ build_dir_list = build_build_dir_list()
+
+ if args.type == 'tests':
+ handle_tests_type(args, build_dir_list)
+ elif args.type == 'docs':
+ handle_docs_type(args, build_dir_list)
+ else:
+ print('Invalid or unknown type')
+ sys.exit(1)
+
+
+def handle_docs_type(args, build_dir_list: list):
+ if args.create:
+ if os.path.exists(DOCS_FOLDER_NAME):
+ shutil.rmtree(DOCS_FOLDER_NAME)
+ create_docs_build_cfg()
+ build_directory = DOCS_FOLDER_NAME
+ elif len(build_dir_list) == 0:
+ print('No valid CMake docs build directory found. Trying to set up docs build system')
+ shutil.rmtree(DOCS_FOLDER_NAME)
+ create_docs_build_cfg()
+ build_directory = DOCS_FOLDER_NAME
+ elif len(build_dir_list) == 1:
+ build_directory = build_dir_list[0]
+ else:
+ print("Multiple build directories found!")
+ build_directory = determine_build_dir(build_dir_list)
+ os.chdir(build_directory)
+ if args.build:
+ os.system('cmake --build . -j')
+ if args.open:
+ if not os.path.isfile('docs/sphinx/index.html'):
+ # try again..
+ os.system('cmake --build . -j')
+ if not os.path.isfile('docs/sphinx/index.html'):
+ print(
+ "No Sphinx documentation file detected. "
+ "Try to build it first with the -b argument"
+ )
+ sys.exit(1)
+ webbrowser.open('docs/sphinx/index.html')
+
+
+def handle_tests_type(args, build_dir_list: list):
+ if args.create:
+ if os.path.exists(UNITTEST_FOLDER_NAME):
+ shutil.rmtree(UNITTEST_FOLDER_NAME)
+ create_tests_build_cfg()
+ build_directory = UNITTEST_FOLDER_NAME
+ elif len(build_dir_list) == 0:
+ print(
+ 'No valid CMake tests build directory found. '
+ 'Trying to set up test build system'
+ )
+ create_tests_build_cfg()
+ build_directory = UNITTEST_FOLDER_NAME
+ elif len(build_dir_list) == 1:
+ build_directory = build_dir_list[0]
+ else:
+ print("Multiple build directories found!")
+ build_directory = determine_build_dir(build_dir_list)
+ os.chdir(build_directory)
+ if args.build:
+ perform_lcov_operation(build_directory, False)
+ if args.open:
+ if not os.path.isdir('fsfw-tests_coverage'):
+ print("No Unittest folder detected. Try to build them first with the -b argument")
+ sys.exit(1)
+ webbrowser.open('fsfw-tests_coverage/index.html')
+
+
+def create_tests_build_cfg():
+ os.mkdir(UNITTEST_FOLDER_NAME)
+ os.chdir(UNITTEST_FOLDER_NAME)
+ os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_UNITTESTS=ON ..')
+ os.chdir('..')
+
+
+def create_docs_build_cfg():
+ os.mkdir(DOCS_FOLDER_NAME)
+ os.chdir(DOCS_FOLDER_NAME)
+ os.system('cmake -DFSFW_OSAL=host -DFSFW_BUILD_DOCS=ON ..')
+ os.chdir('..')
+
+
+def build_build_dir_list() -> list:
+ build_dir_list = []
+ for directory in os.listdir("."):
+ if os.path.isdir(directory):
+ os.chdir(directory)
+ build_dir_list = check_for_cmake_build_dir(build_dir_list)
+ os.chdir("..")
+ return build_dir_list
+
+
+def check_for_cmake_build_dir(build_dir_list: list) -> list:
+ if os.path.isfile("CMakeCache.txt"):
+ build_dir_list.append(os.getcwd())
+ return build_dir_list
+
+
+def perform_lcov_operation(directory: str, chdir: bool):
+ if chdir:
+ os.chdir(directory)
+ os.system("cmake --build . -- fsfw-tests_coverage -j")
+
+
+def determine_build_dir(build_dir_list: List[str]):
+ build_directory = ""
+ for idx, directory in enumerate(build_dir_list):
+ print(f"{idx + 1}: {directory}")
+ while True:
+ idx = input("Pick the directory: ")
+ if not idx.isdigit():
+ print("Invalid input!")
+ continue
+
+ idx = int(idx)
+ if idx > len(build_dir_list) or idx < 1:
+ print("Invalid input!")
+ continue
+ build_directory = build_dir_list[idx - 1]
+ break
+ return build_directory
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/src/fsfw_tests/integration/task/CMakeLists.txt b/tests/src/fsfw_tests/integration/task/CMakeLists.txt
index 0402d093..4cd481bf 100644
--- a/tests/src/fsfw_tests/integration/task/CMakeLists.txt
+++ b/tests/src/fsfw_tests/integration/task/CMakeLists.txt
@@ -1,3 +1,3 @@
-target_sources(${TARGET_NAME} PRIVATE
+target_sources(${LIB_FSFW_NAME} PRIVATE
TestTask.cpp
)
\ No newline at end of file