diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18386d43e4eb8acb3468acf9d855a11e4a916584..57a3c6e5c9412d9ab5d671eab32f047683c208e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,19 @@
 All notable changes to this project will be documented in this file.
 
 ## [Unreleased]
+
+## [0.09] - 30-09-2022
+### Added
+- decompression/compression for non-imagette data
+- functions to create and configure a compression configuration
+- add max_used_bits feature
+- add max used bit version field to the compression entity
+###Changed
+- Change the build system form make to meson
+- Change DEFAULT_CFG_MODEL and DEFAULT_CFG_DIFF to CMP_DIF_XXX constats
+### Fixed
+- now the adaptive compression size (ap1_cmp_size, ap2_cmp_size) is calculate when the --rdcu_par option is used
+
 ## [0.08] - 19-01-2021
 ### Added
 - Relax the requirements on the input format
@@ -16,6 +29,9 @@ E.g. "# comment\n ABCD 1    2\n34B 12\n" are interpreted as {0xAB, 0xCD,
 ### Changed
 - update the header definition according to PLATO-UVIE-PL-UM-0001 Draft 6
     - changed version_id from 16 to 32 bit in the generic header. Add spare bits to the adaptive imagette header and the non-imagette header, so that the compressed data start address is 4 byte-aligned.
+### Fixed
+- Fix a bug in the definition in imagette header
+### Changed
 - Rename cmp_tool_lib.c to cmp_io.c
 
 ## [0.07] - 13-12-2021
diff --git a/INSTALL.md b/INSTALL.md
new file mode 100644
index 0000000000000000000000000000000000000000..7665bcb92bd15a7bb678129d1bb3eda586d10873
--- /dev/null
+++ b/INSTALL.md
@@ -0,0 +1,145 @@
+# Installation Instructions
+## Getting started
+
+### Install git and python 3.7+
+
+If you're on Linux, you probably already have these. On macOS and Windows, you can use the
+[official Python installer](https://www.python.org/downloads).
+
+### Install meson and ninja
+
+Meson 0.56 or newer is required.  
+You can get meson through your package manager or using:
+
+```pip3 install meson```
+
+Check if meson is included in your PATH.
+
+You should get `ninja` using your [package manager](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages) or download the [official
+release](https://github.com/ninja-build/ninja/releases) and put the `ninja`
+binary in your PATH.
+
+### Get the Source Code
+
+We use the version control system [git](https://git-scm.com/downloads) to get a copy of the source code.
+
+```
+git clone https://gitlab.phaidra.org/loidoltd15/cmp_tool.git  
+cd cmp_tool
+```
+## Build the cmp\_tool
+### Build the cmp\_tool for Debugging
+
+First, we create the `builddir` directory. Everything we build will be inside this directory.
+
+```
+meson setup builddir
+```
+
+We change to the build directory and build the cmp_tool:
+
+```
+cd builddir
+meson compile cmp_tool
+```
+
+Now you should find the cmp\_tool executable in the folder.
+
+### Release Build
+
+If you want to create an optimized release version, we can create a build directory for it:
+
+```
+meson setup build_relase_dir --buildtype=release
+cd build_relase_dir
+meson compile cmp_tool
+```
+
+You find the build executable in the `build_relase_dir` directory
+
+### Build for Windows
+
+Unfortunately, the cmp\_tool does not support the Microsoft MSVC compiler. To build the cmp\_tool for Windows you can use the Mingw-w64 GCC compiler.
+For this, you need the [Mingw-w64 toolchain](https://www.mingw-w64.org/downloads/). To compile on Windows, do this in the Cygwin64 Terminal:
+
+```
+meson setup buiddir_win --native-file=mingw-w64-64.txt
+cd buiddir_win
+meson compile
+```
+
+### Cross-compile for Windows
+Cross-compile for Windows is also possible with the [Mingw-w64 toolchain](https://www.mingw-w64.org/downloads/). To cross-compile for Windows use the following commands: 
+
+```
+meson setup buiddir_cross_win --cross-file=mingw-w64-64.txt
+cd buiddir_cross_win
+meson compile
+```
+
+## Tests
+### External dependencies
+
+To run the unit tests you need the [ruby interpreter](https://www.ruby-lang.org/en/documentation/installation/).  
+To run the cmp\_tool interface test you need the [pytest](https://docs.pytest.org/en/7.0.x/index.html) framework. The easiest way to install pytest is with `pip3`:
+
+```
+pip3 install pytest
+```
+### Run tests
+First, cd in the build directory:
+
+```
+cd <name of the build directory>
+```
+
+You can easily run the test of all the components:
+
+```
+meson test
+```
+
+To list all available tests:
+
+```
+meson test --list
+```
+
+Meson also supports running the tests under GDB. Just doing this:
+
+```
+meson test --gdb <testname>
+```
+
+### Producing a coverage report
+
+First, configure the build with this command.
+
+```
+cd <name of the build directory>
+meson configure -Db_coverage=true
+```
+
+Then issue the following commands.
+
+```
+meson test
+ninja coverage-html
+```
+
+The coverage report can be found in the `meson-logs/coveragereport` subdirectory.
+
+## Documentation 
+### External dependencies
+To generate the documentation you need the [Doxygen](https://www.doxygen.nl/index.html) program.
+Optional you can install the "dot" tool from [graphviz](http://www.graphviz.org/) to generate more advanced diagrams and graphs.  
+
+### Generate Documentation
+
+To generate the documentation you need to run:
+
+```
+cd <name of the build directory>
+meson compile doc
+```
+
diff --git a/Makefile b/Makefile
deleted file mode 100644
index 6038a8737bfa8f1b32d8555b46980b2a074adc24..0000000000000000000000000000000000000000
--- a/Makefile
+++ /dev/null
@@ -1,50 +0,0 @@
-CC               = gcc
-SOURCEDIR	       = lib
-INCLUDEDIR       = include
-BUILDDIR         = ./
-CFLAGS          := -Wall -Wextra -std=gnu99 -mno-ms-bitfields -pedantic -Wshadow \
-		    -Wunreachable-code #-Wdocumentation #-Wsign-conversion
-RELCFLAGS       := -O2 # Release flags
-DBCFLAGS        := -O0 -g3 -fsanitize=address -fsanitize=undefined #debug flags
-COVFLAGS        := -fprofile-arcs -ftest-coverage #coverage flags
-CPPFLAGS        := -I $(INCLUDEDIR)
-LDFLAGS         := -lm
-SOURCES         := cmp_tool.c \
-		    $(SOURCEDIR)/rmap.c \
-		    $(SOURCEDIR)/rdcu_ctrl.c \
-		    $(SOURCEDIR)/rdcu_cmd.c \
-		    $(SOURCEDIR)/rdcu_rmap.c \
-		    $(SOURCEDIR)/cmp_support.c \
-		    $(SOURCEDIR)/cmp_data_types.c \
-		    $(SOURCEDIR)/cmp_rdcu.c \
-		    $(SOURCEDIR)/cmp_icu.c \
-		    $(SOURCEDIR)/decmp.c \
-		    $(SOURCEDIR)/rdcu_pkt_to_file.c \
-		    $(SOURCEDIR)/cmp_guess.c \
-		    $(SOURCEDIR)/cmp_io.c \
-		    $(SOURCEDIR)/cmp_entity.c
-TARGET          := cmp_tool
-
-DEBUG?=1
-ifeq  "$(shell expr $(DEBUG) \> 1)" "1"
-	    CFLAGS += -DDEBUGLEVEL=$(DEBUG)
-else
-	    CFLAGS += -DDEBUGLEVEL=1
-endif
-
-
-all: $(SOURCES)
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(RELCFLAGS) $^ -o $(TARGET) $(LDFLAGS)
-
-debug: $(SOURCES)
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DBCFLAGS) $^ -o $(TARGET) $(LDFLAGS)
-
-integration: $(SOURCES)
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(DBCFLAGS) $(COVFLAGS) $^ -o $(TARGET) $(LDFLAGS)
-	pytest test/cmp_tool/cmp_tool_integration_test.py
-	lcov --rc lcov_branch_coverage=1 --capture --directory ./ --output-file coverage.info
-	genhtml --rc lcov_branch_coverage=1 --branch-coverage coverage.info --output-directory out
-#firefox out/index.html
-
-clean:
-	rm -rf $(TARGET) *.gcno *.gcda coverage.info out
diff --git a/README.md b/README.md
index 325a24c78f8767358abc5604d6463f301955ecf9..cad1887c99f2df6c0a2a992a434bd911858f06e1 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 If you find a bug or have a feature request please file an [issue][1] or send
 me an [email][2].  
-Compiled executables can be found [here][3].
+Compiled executables can be found [here][3]. The building instructions can be found [here](INSTALL.md).
 
 ## Usage
 
@@ -86,7 +86,7 @@ You can find the user manual [here](doc).
 A simple example to show how the compression tool works.
 Instructions on how to perform compression without headers can be found [here](how_to_no_header.md).
 
-0. Download the [tool][3] or run `make` to build the tool
+0. Download the [tool][3] or [build the tool](INSTALL.md) yourself
 
 1. Create a configuration file
 * Create a cfg directory  
diff --git a/cmp_tool.c b/cmp_tool.c
old mode 100755
new mode 100644
index fd8401f96975fd06a4c82b7a0216758ab33aae2a..3572c23398944893dd291d74cca53bb76d7b836c
--- a/cmp_tool.c
+++ b/cmp_tool.c
@@ -25,23 +25,34 @@
 #include <getopt.h>
 #include <time.h>
 
-#include "include/cmp_io.h"
-#include "include/cmp_icu.h"
-#include "include/decmp.h"
-#include "include/cmp_guess.h"
-#include "include/cmp_entity.h"
-#include "include/rdcu_pkt_to_file.h"
+#include "cmp_tool-config.h"
+#include "cmp_io.h"
+#include "cmp_icu.h"
+#include "cmp_rdcu.h" /*TODO: shift setup to support */
+#include "decmp.h"
+#include "cmp_guess.h"
+#include "cmp_entity.h"
+#include "rdcu_pkt_to_file.h"
+#include "cmp_data_types.h"
 
 
-#define VERSION "0.08"
-
 #define BUFFER_LENGTH_DEF_FAKTOR 2
 
-
 #define DEFAULT_MODEL_ID 53264  /* random default id */
 #define DEFAULT_MODEL_COUNTER 0
 
 
+/* find a good set of compression parameters for a given dataset */
+static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode,
+			  int guess_level);
+
+/* compress the data and write the results to files */
+static int compression(struct cmp_cfg *cfg, struct cmp_info *info);
+
+/* decompress the data and write the results in file(s)*/
+static int decompression(struct cmp_entity *ent, uint16_t *input_model_buf);
+
+
 /*
  * For long options that have no equivalent short option, use a
  * non-character as a pseudo short option, starting with CHAR_MAX + 1.
@@ -79,7 +90,7 @@ static const char *output_prefix = DEFAULT_OUTPUT_PREFIX;
 
 /* if non zero additional RDCU parameters are included in the compression
  * configuration and decompression information files */
-static int print_rdcu_cfg;
+static int add_rdcu_pars;
 
 /* if non zero generate RDCU setup packets */
 static int rdcu_pkt_mode;
@@ -94,17 +105,6 @@ static int verbose_en;
 /* if non zero add a compression entity header in front of the compressed data */
 static int include_cmp_header = 1;
 
-/* find a good set of compression parameters for a given dataset */
-static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode,
-			  int guess_level);
-
-/* compress the data and write the results to files */
-static int compression(struct cmp_cfg *cfg, struct cmp_info *info);
-
-/* decompress the data and write the results in file(s)*/
-static int decompression(uint32_t *cmp_data_adr, uint16_t *input_model_buf,
-			 struct cmp_info *info);
-
 /* model ID string set by the --model_id option */
 static const char *model_id_str;
 
@@ -140,16 +140,16 @@ int main(int argc, char **argv)
 	int guess_level = DEFAULT_GUESS_LEVEL;
 	int print_diff_cfg = 0;
 
-	struct cmp_cfg cfg = {0}; /* compressor configuration struct */
-	struct cmp_info info = {0}; /* decompression information struct */
-
-	/* buffer containing all read in compressed data for decompression (including header if used) */
-	void *decomp_input_buf = NULL;
-	/* address to the compressed data for the decompression */
-	uint32_t *cmp_data_adr = NULL;
+	/* buffer containing all read in compressed data for decompression */
+	struct cmp_entity *decomp_entity = NULL;
 	/* buffer containing the read in model */
 	uint16_t *input_model_buf = NULL;
 
+	struct cmp_info info = {0}; /* decompression information struct */
+	struct cmp_cfg cfg = {0}; /* compressor configuration struct */
+
+	cfg.data_type = DATA_TYPE_IMAGETTE; /* use imagette as default data type */
+
 	/* show help if no arguments are provided */
 	if (argc < 2) {
 		print_help(program_name);
@@ -160,7 +160,7 @@ int main(int argc, char **argv)
 				  NULL)) != -1) {
 		switch (opt) {
 		case 'a': /* --rdcu_par */
-			print_rdcu_cfg = 1;
+			add_rdcu_pars = 1;
 			break;
 		case 'c':
 			cmp_operation = 1;
@@ -190,7 +190,7 @@ int main(int argc, char **argv)
 			verbose_en = 1;
 			break;
 		case 'V': /* --version */
-			printf("%s version %s\n", PROGRAM_NAME, VERSION);
+			printf("%s version %s\n", PROGRAM_NAME, CMP_TOOL_VERSION);
 			exit(EXIT_SUCCESS);
 			break;
 		case DIFF_CFG_OPTION:
@@ -262,20 +262,38 @@ int main(int argc, char **argv)
 #endif
 
 	if (print_model_cfg == 1) {
-		print_cfg(&DEFAULT_CFG_MODEL, print_rdcu_cfg);
+		cfg = rdcu_cfg_create(CMP_DEF_IMA_MODEL_DATA_TYPE, CMP_DEF_IMA_MODEL_CMP_MODE,
+				      CMP_DEF_IMA_MODEL_MODEL_VALUE, CMP_DEF_IMA_MODEL_LOSSY_PAR);
+		rdcu_cfg_buffers(&cfg, NULL, 0, NULL, CMP_DEF_IMA_MODEL_RDCU_DATA_ADR,
+				 CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR, CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR,
+				 CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR, 0);
+		rdcu_cfg_imagette(&cfg,
+				  CMP_DEF_IMA_MODEL_GOLOMB_PAR, CMP_DEF_IMA_MODEL_SPILL_PAR,
+				  CMP_DEF_IMA_MODEL_AP1_GOLOMB_PAR, CMP_DEF_IMA_MODEL_AP1_SPILL_PAR,
+				  CMP_DEF_IMA_MODEL_AP2_GOLOMB_PAR, CMP_DEF_IMA_MODEL_AP2_SPILL_PAR);
+		print_cfg(&cfg, add_rdcu_pars);
 		exit(EXIT_SUCCESS);
 	}
 
 	if (print_diff_cfg == 1) {
-		print_cfg(&DEFAULT_CFG_DIFF, print_rdcu_cfg);
+		cfg = rdcu_cfg_create(CMP_DEF_IMA_DIFF_DATA_TYPE, CMP_DEF_IMA_DIFF_CMP_MODE,
+				      CMP_DEF_IMA_DIFF_MODEL_VALUE, CMP_DEF_IMA_DIFF_LOSSY_PAR);
+		rdcu_cfg_buffers(&cfg, NULL, 0, NULL, CMP_DEF_IMA_DIFF_RDCU_DATA_ADR,
+				 CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR, CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR,
+				 CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR, 0);
+		rdcu_cfg_imagette(&cfg,
+				  CMP_DEF_IMA_DIFF_GOLOMB_PAR, CMP_DEF_IMA_DIFF_SPILL_PAR,
+				  CMP_DEF_IMA_DIFF_AP1_GOLOMB_PAR, CMP_DEF_IMA_DIFF_AP1_SPILL_PAR,
+				   CMP_DEF_IMA_DIFF_AP2_GOLOMB_PAR, CMP_DEF_IMA_DIFF_AP2_SPILL_PAR);
+		print_cfg(&cfg, add_rdcu_pars);
 		exit(EXIT_SUCCESS);
 	}
 
 	printf("#########################################################\n");
 	printf("### PLATO Compression/Decompression Tool Version %s ###\n",
-	       VERSION);
+	       CMP_TOOL_VERSION);
 	printf("#########################################################\n");
-	if (!strcmp(VERSION, "0.07") || !strcmp(VERSION, "0.08"))
+	if (!strcmp(CMP_TOOL_VERSION, "0.07") || !strcmp(CMP_TOOL_VERSION, "0.08"))
 		printf("Info: Note that the behaviour of the cmp_tool has changed. From now on, the compressed data will be preceded by a header by default. The old behaviour can be achieved with the --no_header option.\n\n");
 
 	if (!data_file_name) {
@@ -293,6 +311,7 @@ int main(int argc, char **argv)
 
 	if (cmp_operation || guess_operation) {
 		ssize_t size;
+		uint32_t input_size;
 
 		if (cmp_operation) {
 			printf("## Starting the compression ##\n");
@@ -308,21 +327,26 @@ int main(int argc, char **argv)
 		printf("Importing data file %s ... ", data_file_name);
 		/* count the samples in the data file when samples == 0 */
 		if (cfg.samples == 0) {
-			size = read_file16(data_file_name, NULL, 0, 0);
-			if (size <= 0) /* empty file is treated as an error */
+			int samples;
+			size = read_file_data(data_file_name, cfg.data_type, NULL, 0, 0);
+			if (size <= 0 || size > UINT32_MAX) /* empty file is treated as an error */
+				goto fail;
+			samples = cmp_input_size_to_samples(size, cfg.data_type);
+			if (samples < 0)
 				goto fail;
-			cfg.samples = size/size_of_a_sample(cfg.cmp_mode);
+			cfg.samples = (uint32_t)samples;
 			printf("\nNo samples parameter set. Use samples = %u.\n... ", cfg.samples);
 		}
 
-		cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.cmp_mode));
+		input_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
+		cfg.input_buf = malloc(input_size);
 		if (!cfg.input_buf) {
 			fprintf(stderr, "%s: Error allocating memory for input data buffer.\n", PROGRAM_NAME);
 			goto fail;
 		}
 
-		size = read_file16(data_file_name, cfg.input_buf, cfg.samples,
-				   verbose_en);
+		size = read_file_data(data_file_name, cfg.data_type, cfg.input_buf,
+				      input_size, verbose_en);
 		if (size < 0)
 			goto fail;
 		printf("DONE\n");
@@ -330,7 +354,8 @@ int main(int argc, char **argv)
 	} else { /* decompression mode*/
 		printf("## Starting the decompression ##\n");
 		if (info_file_name) {
-			ssize_t size;
+			ssize_t f_size;
+			size_t ent_size;
 			uint32_t cmp_size_byte;
 
 			printf("Importing decompression information file %s ... ", info_file_name);
@@ -341,75 +366,76 @@ int main(int argc, char **argv)
 
 			printf("Importing compressed data file %s ... ", data_file_name);
 			cmp_size_byte = cmp_bit_to_4byte(info.cmp_size);
-			cmp_data_adr = decomp_input_buf = malloc(cmp_size_byte);
-			if (!decomp_input_buf) {
+
+			ent_size = cmp_ent_create(NULL, DATA_TYPE_IMAGETTE, info.cmp_mode_used == CMP_MODE_RAW,
+						  cmp_size_byte);
+			if (!ent_size)
+				goto fail;
+			decomp_entity = malloc(ent_size);
+			if (!decomp_entity) {
 				fprintf(stderr, "%s: Error allocating memory for decompression input buffer.\n", PROGRAM_NAME);
 				goto fail;
 			}
+			ent_size = cmp_ent_create(decomp_entity, DATA_TYPE_IMAGETTE, info.cmp_mode_used == CMP_MODE_RAW,
+						  cmp_size_byte);
+			if (!ent_size)
+				goto fail;
 
-			size = read_file32(data_file_name, decomp_input_buf,
-					   cmp_size_byte/4, verbose_en);
-			if (size < 0)
+			if (info.cmp_mode_used == CMP_MODE_RAW)
+				/* the raw data does not have to be a multiple of 4 bytes */
+				cmp_size_byte = (info.cmp_size+7)/CHAR_BIT;
+
+			f_size = read_file8(data_file_name, cmp_ent_get_data_buf(decomp_entity),
+					    cmp_size_byte, verbose_en);
+			if (f_size < 0)
+				goto fail;
+
+			error = cmp_ent_write_rdcu_cmp_pars(decomp_entity, &info, NULL);
+			if (error)
 				goto fail;
 		} else { /* read in compressed data with header */
 			ssize_t size;
 			size_t buf_size;
-			struct cmp_entity *ent;
 
 			printf("Importing compressed data file %s ... ", data_file_name);
 			buf_size = size = read_file_cmp_entity(data_file_name,
 							       NULL, 0, 0);
-			if (size < 0)
+			if (size < 0 || size > UINT32_MAX)
 				goto fail;
 			/* to be save allocate at least the size of the cmp_entity struct */
 			if (buf_size < sizeof(struct cmp_entity))
 				buf_size = sizeof(struct cmp_entity);
 
-			decomp_input_buf = ent = malloc(buf_size);
-			if (!ent) {
+			decomp_entity = malloc(buf_size);
+			if (!decomp_entity) {
 				fprintf(stderr, "%s: Error allocating memory for the compression entity buffer.\n", PROGRAM_NAME);
 				goto fail;
 			}
-			size = read_file_cmp_entity(data_file_name, ent, size,
-						  verbose_en);
-			if (size < 0)
-				goto fail;
-			printf("DONE\n");
-
-			printf("Parse the compression entity header ... ");
-			error = cmp_ent_read_imagette_header(ent, &info);
-			if (error)
-				goto fail;
-			if (verbose_en)
-				print_cmp_info(&info);
-
-			/* we reuse the entity buffer for the compressed data */
-			cmp_data_adr = (uint32_t *)decomp_input_buf;
-			size = cmp_ent_get_cmp_data(ent, cmp_data_adr, buf_size);
-			ent = NULL;
+			size = read_file_cmp_entity(data_file_name, decomp_entity,
+						    size, verbose_en);
 			if (size < 0)
 				goto fail;
 
 			if (verbose_en) {
-				size_t i;
-				printf("\ncompressed data:\n");
-				for (i = 0; i < size/sizeof(uint32_t); i++) {
-					printf("%08X ", cmp_data_adr[i]);
-					if (i && !((i+1) % 4))
-						printf("\n");
-				}
+				cmp_ent_print(decomp_entity);
 				printf("\n");
 			}
 		}
 		printf("DONE\n");
 	}
 
+	if (model_file_name && !guess_operation &&
+	    ((cmp_operation && !model_mode_is_used(cfg.cmp_mode)) ||
+	     (!cmp_operation && !model_mode_is_used(cmp_ent_get_cmp_mode(decomp_entity)))))
+		printf("Warring: Model file (-m option) specified but no model is used.\n");
+
 	/* read in model */
 	if ((cmp_operation && model_mode_is_used(cfg.cmp_mode)) ||
-	    (!cmp_operation && model_mode_is_used(info.cmp_mode_used)) ||
+	    (!cmp_operation && model_mode_is_used(cmp_ent_get_cmp_mode(decomp_entity))) ||
 	    (guess_operation && model_file_name)) {
 		ssize_t size;
-		uint32_t model_length;
+		uint32_t model_size;
+		enum cmp_data_type data_type;
 
 		printf("Importing model file %s ... ", model_file_name ? model_file_name : "");
 		if (!model_file_name) {
@@ -417,24 +443,28 @@ int main(int argc, char **argv)
 			goto fail;
 		}
 
-		if (cmp_operation || guess_operation)
-			model_length = cfg.samples;
-		else
-			model_length = info.samples_used;
+		if (cmp_operation || guess_operation) {
+			data_type = cfg.data_type;
+			model_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
+		} else {
+			data_type = cmp_ent_get_data_type(decomp_entity);
+			model_size = cmp_ent_get_original_size(decomp_entity);
+		}
 
-		input_model_buf = malloc(model_length * size_of_a_sample(cfg.cmp_mode));
+		input_model_buf = malloc(model_size);
 		if (!input_model_buf) {
 			fprintf(stderr, "%s: Error allocating memory for model buffer.\n", PROGRAM_NAME);
 			goto fail;
 		}
 
-		size = read_file16(model_file_name, input_model_buf,
-				   model_length, verbose_en);
+		size = read_file_data(model_file_name, data_type, input_model_buf,
+				      model_size, verbose_en);
 		if (size < 0)
 			goto fail;
 		printf("DONE\n");
 
 		cfg.model_buf = input_model_buf;
+		cfg.icu_new_model_buf = input_model_buf; /* in-place model update */
 	}
 
 	if (guess_operation) {
@@ -446,7 +476,7 @@ int main(int argc, char **argv)
 		if (error)
 			goto fail;
 	} else {
-		error = decompression(cmp_data_adr, input_model_buf, &info);
+		error = decompression(decomp_entity, input_model_buf);
 		if (error)
 			goto fail;
 	}
@@ -454,17 +484,28 @@ int main(int argc, char **argv)
 	/* write our the updated model for compressed or decompression */
 	if (!guess_operation &&
 	    ((cmp_operation && model_mode_is_used(cfg.cmp_mode)) ||
-	    (!cmp_operation && model_mode_is_used(info.cmp_mode_used)))) {
+	    (!cmp_operation && model_mode_is_used(cmp_ent_get_cmp_mode(decomp_entity))))) {
+		enum cmp_data_type data_type = DATA_TYPE_UNKNOWN;
+		uint32_t model_size;
+
 		printf("Write updated model to file %s_upmodel.dat ... ", output_prefix);
-		error = write_to_file16(input_model_buf, info.samples_used,
-					output_prefix, "_upmodel.dat", verbose_en);
+		if (cmp_operation) {
+			data_type = cfg.data_type;
+			model_size = cmp_cal_size_of_data(cfg.samples, data_type);
+		} else {
+			data_type = cmp_ent_get_data_type(decomp_entity);
+			model_size = cmp_ent_get_original_size(decomp_entity);
+		}
+
+		error = write_input_data_to_file(input_model_buf, model_size, data_type,
+						 output_prefix, "_upmodel.dat", verbose_en);
 		if (error)
 			goto fail;
 		printf("DONE\n");
 	}
 
 	free(cfg.input_buf);
-	free(decomp_input_buf);
+	free(decomp_entity);
 	free(input_model_buf);
 
 	exit(EXIT_SUCCESS);
@@ -473,56 +514,33 @@ fail:
 	printf("FAILED\n");
 
 	free(cfg.input_buf);
-	free(decomp_input_buf);
+	free(decomp_entity);
 	free(input_model_buf);
 
 	exit(EXIT_FAILURE);
 }
 
 
-static enum cmp_ent_data_type cmp_ent_map_cmp_mode_data_type(uint32_t cmp_mode)
-{
-	enum cmp_ent_data_type data_type;
-
-	switch (cmp_mode) {
-	case MODE_RAW:
-	case MODE_MODEL_ZERO:
-	case MODE_DIFF_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_MULTI:
-		if (print_rdcu_cfg)
-			data_type = DATA_TYPE_IMAGETTE_ADAPTIVE;
-		else
-			data_type = DATA_TYPE_IMAGETTE;
-		break;
-	default:
-		printf("No mapping between compression mode and header data type\n!");
-		return DATA_TYPE_UNKOWN;
-	}
-
-	/* set raw bit if needed */
-	if (raw_mode_is_used(cmp_mode))
-		data_type |= 1UL << RAW_BIT_DATA_TYPE_POS;
-
-	return data_type;
-}
-
-
 /* find a good set of compression parameters for a given dataset */
 static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode,
 			  int guess_level)
 {
 	int error;
 	uint32_t cmp_size_bit;
-	float cr;
+	double cr;
 
 	printf("Search for a good set of compression parameters (level: %d) ... ", guess_level);
 	if (!strcmp(guess_cmp_mode, "RDCU")) {
+		if (add_rdcu_pars)
+			cfg->data_type = DATA_TYPE_IMAGETTE_ADAPTIVE;
+		else
+			cfg->data_type = DATA_TYPE_IMAGETTE;
 		if (cfg->model_buf)
 			cfg->cmp_mode = CMP_GUESS_DEF_MODE_MODEL;
 		else
 			cfg->cmp_mode = CMP_GUESS_DEF_MODE_DIFF;
 	} else {
+		cfg->data_type = DATA_TYPE_IMAGETTE; /* TODO*/
 		error = cmp_mode_parse(guess_cmp_mode, &cfg->cmp_mode);
 		if (error) {
 			fprintf(stderr, "%s: Error: unknown compression mode: %s\n", PROGRAM_NAME, guess_cmp_mode);
@@ -540,24 +558,24 @@ static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode,
 
 	if (include_cmp_header)
 		cmp_size_bit = CHAR_BIT * (cmp_bit_to_4byte(cmp_size_bit) +
-			cmp_ent_cal_hdr_size(cmp_ent_map_cmp_mode_data_type(cfg->cmp_mode)));
+			cmp_ent_cal_hdr_size(cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW));
 
 	printf("DONE\n");
 
 	printf("Write the guessed compression configuration to file %s.cfg ... ", output_prefix);
-	error = write_cfg(cfg, output_prefix, print_rdcu_cfg, verbose_en);
+	error = write_cfg(cfg, output_prefix, add_rdcu_pars, verbose_en);
 	if (error)
 		return -1;
 	printf("DONE\n");
 
-	cr = (8.0 * cfg->samples * size_of_a_sample(cfg->cmp_mode))/cmp_size_bit;
+	cr = (8.0 * cmp_cal_size_of_data(cfg->samples, cfg->data_type))/cmp_size_bit;
 	printf("Guessed parameters can compress the data with a CR of %.2f.\n", cr);
 
 	return 0;
 }
 
 
-/* generate packets to setup a RDCU compression */
+/* generate packets to setup an RDCU compression */
 static int gen_rdcu_write_pkts(struct cmp_cfg *cfg)
 {
 	int error;
@@ -594,47 +612,76 @@ static int gen_rdcu_write_pkts(struct cmp_cfg *cfg)
 }
 
 
-/* add a compression entity header in front of the data */
-static int add_cmp_ent_hdr(struct cmp_cfg *cfg, struct cmp_info *info,
-			   uint64_t start_time)
+/**
+ * @brief generate the compression information used based on the compression
+ *	configuration, to emulate the RDCU behaviour
+ *
+ * @param cfg		compression configuration struct
+ * @param cmp_size_bit	length of the bitstream in bits
+ * @param info		compressor information struct to set the used compression
+ *	parameters (can be NULL)
+ *
+ * @note set cmp_size, ap1_cmp_size, ap2_cmp_size will be set to 0
+ *
+ * @returns 0 on success, error otherwise
+ * TODO: set cmp_mode_err, set model_value_err, etc, in error case
+ */
+
+static int cmp_gernate_rdcu_info(const struct cmp_cfg *cfg, int cmp_size_bit,
+				 struct cmp_info *info)
 {
-	int error;
-	uint32_t red_val;
-	uint8_t model_counter = DEFAULT_MODEL_COUNTER;
-	uint16_t model_id = DEFAULT_MODEL_ID;
-	size_t s, cmp_hdr_size;
-	struct cmp_entity *ent;
-	enum cmp_ent_data_type data_type = cmp_ent_map_cmp_mode_data_type(cfg->cmp_mode);
+	if (!cfg)
+		return -1;
 
-	if (model_id_str) {
-		error = atoui32("model_id", model_id_str, &red_val);
-		if (error || red_val > UINT16_MAX)
-			return -1;
-		model_id = red_val;
-	}
-	if (model_counter_str) {
-		error = atoui32("model_counter", model_counter_str, &red_val);
-		if (error || red_val > UINT8_MAX)
-			return -1;
-		model_counter = red_val;
-	} else {
-		if (model_mode_is_used(cfg->cmp_mode))
-			model_counter = DEFAULT_MODEL_COUNTER + 1;
-	}
+	if (cfg->cmp_mode > UINT8_MAX)
+		return -1;
 
-	cmp_hdr_size = cmp_ent_cal_hdr_size(data_type);
-	if (!cmp_hdr_size)
+	if (cfg->round > UINT8_MAX)
 		return -1;
-	memmove((uint8_t *)cfg->icu_output_buf+cmp_hdr_size, cfg->icu_output_buf,
-		cmp_bit_to_4byte(info->cmp_size));
 
-	ent = (struct cmp_entity *)cfg->icu_output_buf;
-	s = cmp_ent_build(ent, data_type, cmp_tool_gen_version_id(VERSION),
-			  start_time, cmp_ent_create_timestamp(NULL), model_id,
-			  model_counter, info, cfg);
-	if (!s) {
-		fprintf(stderr, "%s: error occurred while creating the compression entity header.\n", PROGRAM_NAME);
+	if (cfg->model_value > UINT8_MAX)
 		return -1;
+
+	if (info) {
+		info->cmp_err = 0;
+		info->cmp_mode_used = (uint8_t)cfg->cmp_mode;
+		info->model_value_used = (uint8_t)cfg->model_value;
+		info->round_used = (uint8_t)cfg->round;
+		info->spill_used = cfg->spill;
+		info->golomb_par_used = cfg->golomb_par;
+		info->samples_used = cfg->samples;
+		info->rdcu_new_model_adr_used = cfg->rdcu_new_model_adr;
+		info->rdcu_cmp_adr_used = cfg->rdcu_buffer_adr;
+
+		if (cmp_size_bit == CMP_ERROR_SMALL_BUF)
+			/* the icu_output_buf is to small to store the whole bitstream */
+			info->cmp_err |= 1UL << SMALL_BUFFER_ERR_BIT; /* set small buffer error */
+		if (cmp_size_bit < 0) {
+			info->cmp_size = 0;
+			info->ap1_cmp_size = 0;
+			info->ap2_cmp_size = 0;
+		} else {
+			info->cmp_size = (uint32_t)cmp_size_bit;
+
+			if (add_rdcu_pars) {
+				struct cmp_cfg cfg_cpy = *cfg;
+
+				cfg_cpy.icu_output_buf = NULL;
+				cfg_cpy.icu_new_model_buf = NULL;
+
+				cfg_cpy.golomb_par = cfg_cpy.ap1_golomb_par;
+				cfg_cpy.spill = cfg_cpy.ap1_spill;
+				info->ap1_cmp_size = icu_compress_data(&cfg_cpy);
+				if ((int)info->ap1_cmp_size < 0)
+					info->ap1_cmp_size = 0;
+
+				cfg_cpy.golomb_par = cfg_cpy.ap2_golomb_par;
+				cfg_cpy.spill = cfg_cpy.ap2_spill;
+				info->ap2_cmp_size = icu_compress_data(&cfg_cpy);
+				if ((int)info->ap2_cmp_size < 0)
+					info->ap2_cmp_size = 0;
+			}
+		}
 	}
 	return 0;
 }
@@ -643,12 +690,14 @@ static int add_cmp_ent_hdr(struct cmp_cfg *cfg, struct cmp_info *info,
 /* compress the data and write the results to files */
 static int compression(struct cmp_cfg *cfg, struct cmp_info *info)
 {
-	int error;
-	uint32_t cmp_size_byte;
-	size_t out_buf_size;
+	int cmp_size, error;
+	uint32_t cmp_size_byte, out_buf_size;
+	size_t s;
 	uint64_t start_time = cmp_ent_create_timestamp(NULL);
-
-	cfg->icu_output_buf = NULL;
+	struct cmp_entity *cmp_entity = NULL;
+	uint8_t model_counter = DEFAULT_MODEL_COUNTER;
+	uint16_t model_id = DEFAULT_MODEL_ID;
+	void *data_to_write_to_file;
 
 	if (cfg->buffer_length == 0) {
 		cfg->buffer_length = (cfg->samples+1) * BUFFER_LENGTH_DEF_FAKTOR; /* +1 to prevent malloc(0)*/
@@ -666,30 +715,60 @@ static int compression(struct cmp_cfg *cfg, struct cmp_info *info)
 
 	printf("Compress data ... ");
 	/* round up to a multiple of 4 */
-	out_buf_size = (cmp_cal_size_of_data(cfg->buffer_length, cfg->cmp_mode) + 3) & ~0x3U;
+	out_buf_size = (cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type) + 3) & ~0x3U;
 
-	cfg->icu_output_buf = malloc(out_buf_size + sizeof(struct cmp_entity));
-	if (cfg->icu_output_buf == NULL) {
+	cmp_entity = calloc(1, out_buf_size + sizeof(struct cmp_entity));
+	if (cmp_entity == NULL) {
 		fprintf(stderr, "%s: Error allocating memory for output buffer.\n", PROGRAM_NAME);
 		goto error_cleanup;
 	}
+	s = cmp_ent_create(cmp_entity, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, out_buf_size);
+	if (!s) {
+		fprintf(stderr, "%s: error occurred while creating the compression entity header.\n", PROGRAM_NAME);
+		goto error_cleanup;
+	}
+	cfg->icu_output_buf = cmp_ent_get_data_buf(cmp_entity);
 
-	error = icu_compress_data(cfg, info);
-	if (error || info->cmp_err != 0) {
-		printf("\nCompression error 0x%02X\n... ", info->cmp_err);
-		/* TODO: add a parse cmp error function */
-		/* if ((info->cmp_err >> SMALL_BUFFER_ERR_BIT) & 1U) */
-		/*	fprintf(stderr, "%s: the buffer for the compressed data is too small. Try a larger buffer_length parameter.\n", PROGRAM_NAME); */
+	cmp_size = icu_compress_data(cfg);
+	if (cmp_size < 0)
 		goto error_cleanup;
+
+	if (model_id_str) {
+		uint32_t red_val;
+		error = atoui32("model_id", model_id_str, &red_val);
+		if (error || red_val > UINT16_MAX)
+			return -1;
+		model_id = (uint16_t)red_val;
+	}
+	if (model_counter_str) {
+		uint32_t red_val;
+		error = atoui32("model_counter", model_counter_str, &red_val);
+		if (error || red_val > UINT8_MAX)
+			return -1;
+		model_counter = (uint8_t)red_val;
+	} else {
+		if (model_mode_is_used(cfg->cmp_mode))
+			model_counter = DEFAULT_MODEL_COUNTER + 1;
 	}
 
+	s = cmp_ent_build(cmp_entity,  cmp_tool_gen_version_id(CMP_TOOL_VERSION),
+			  start_time, cmp_ent_create_timestamp(NULL), model_id,
+			  model_counter, cfg, cmp_size);
+	if (!s) {
+		fprintf(stderr, "%s: error occurred while creating the compression entity header.\n", PROGRAM_NAME);
+		goto error_cleanup;
+	}
 	if (include_cmp_header) {
-		error = add_cmp_ent_hdr(cfg, info, start_time);
-		if (error)
-			goto error_cleanup;
-		cmp_size_byte = cmp_ent_get_size((struct cmp_entity *)cfg->icu_output_buf);
+		data_to_write_to_file = cmp_entity;
+		cmp_size_byte = cmp_ent_get_size(cmp_entity);
 	} else {
-		cmp_size_byte = cmp_bit_to_4byte(info->cmp_size);
+		if (cmp_gernate_rdcu_info(cfg, cmp_size, info))
+			goto error_cleanup;
+		data_to_write_to_file = cmp_ent_get_data_buf(cmp_entity);
+		if (cfg->cmp_mode == CMP_MODE_RAW)
+			cmp_size_byte = info->cmp_size/CHAR_BIT;
+		else
+			cmp_size_byte = cmp_bit_to_4byte(info->cmp_size);
 	}
 
 	printf("DONE\n");
@@ -703,7 +782,7 @@ static int compression(struct cmp_cfg *cfg, struct cmp_info *info)
 	}
 
 	printf("Write compressed data to file %s.cmp ... ", output_prefix);
-	error = write_cmp_data_file(cfg->icu_output_buf, cmp_size_byte,
+	error = write_cmp_data_file(data_to_write_to_file, cmp_size_byte,
 				    output_prefix, ".cmp", verbose_en);
 	if (error)
 		goto error_cleanup;
@@ -712,64 +791,68 @@ static int compression(struct cmp_cfg *cfg, struct cmp_info *info)
 	if (!include_cmp_header) {
 		printf("Write decompression information to file %s.info ... ",
 		       output_prefix);
-		error = write_info(info, output_prefix, print_rdcu_cfg);
+		error = write_info(info, output_prefix, add_rdcu_pars);
 		if (error)
 			goto error_cleanup;
 		printf("DONE\n");
-	}
 
-	if (verbose_en) {
-		printf("\n");
-		print_cmp_info(info);
-		printf("\n");
+		if (verbose_en) {
+			printf("\n");
+			print_cmp_info(info);
+			printf("\n");
+		}
 	}
 
-	free(cfg->icu_output_buf);
+	free(cmp_entity);
 	cfg->icu_output_buf = NULL;
 
 	return 0;
 
 error_cleanup:
-	free(cfg->icu_output_buf);
+	free(cmp_entity);
 	cfg->icu_output_buf = NULL;
+
 	return -1;
 }
 
 
 /* decompress the data and write the results in file(s)*/
-static int decompression(uint32_t *cmp_data_adr, uint16_t *input_model_buf,
-			 struct cmp_info *info)
+static int decompression(struct cmp_entity *ent, uint16_t *input_model_buf)
 {
 	int error;
+	int decomp_size;
 	uint16_t *decomp_output;
 
 	printf("Decompress data ... ");
 
-	if (info->samples_used == 0) {
+	decomp_size = decompress_cmp_entiy(ent, input_model_buf, input_model_buf, NULL);
+	if (decomp_size < 0)
+		return -1;
+	if (decomp_size == 0) {
 		printf("\nWarring: No data are decompressed.\n... ");
 		printf("DONE\n");
 		return 0;
 	}
 
-	decomp_output = malloc(cmp_cal_size_of_data(info->samples_used,
-						    info->cmp_mode_used));
+	decomp_output = malloc((size_t)decomp_size);
 	if (decomp_output == NULL) {
 		fprintf(stderr, "%s: Error allocating memory for decompressed data.\n", PROGRAM_NAME);
 		return -1;
 	}
 
-	error = decompress_data(cmp_data_adr, input_model_buf, info,
-				decomp_output);
-	if (error) {
+	decomp_size = decompress_cmp_entiy(ent, input_model_buf, input_model_buf, decomp_output);
+	if (decomp_size <= 0) {
 		free(decomp_output);
 		return -1;
 	}
+
 	printf("DONE\n");
 
 	printf("Write decompressed data to file %s.dat ... ", output_prefix);
 
-	error = write_to_file16(decomp_output, info->samples_used,
-				output_prefix, ".dat", verbose_en);
+	error = write_input_data_to_file(decomp_output, (uint32_t)decomp_size, cmp_ent_get_data_type(ent),
+					 output_prefix, ".dat", verbose_en);
+
 	free(decomp_output);
 	if (error)
 		return -1;
diff --git a/doc/PLATO-UVIE-PL-UM-0001_0r6.pdf b/doc/PLATO-UVIE-PL-UM-0001_1r0.pdf
similarity index 71%
rename from doc/PLATO-UVIE-PL-UM-0001_0r6.pdf
rename to doc/PLATO-UVIE-PL-UM-0001_1r0.pdf
index 581a47061c76f787b75e04ccf88a5064f370704e..bc2bb546c36edbf8fcfa043a9735e321cf0597e4 100644
Binary files a/doc/PLATO-UVIE-PL-UM-0001_0r6.pdf and b/doc/PLATO-UVIE-PL-UM-0001_1r0.pdf differ
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
new file mode 100644
index 0000000000000000000000000000000000000000..5bcc6daebd49549c8f68764627e5b1331513975f
--- /dev/null
+++ b/doc/doxygen/Doxyfile
@@ -0,0 +1,2658 @@
+# Doxyfile 1.9.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "PLATO cmp_tool"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = 0.09 #TODO
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "PLATO Compression/Decompression Tool"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE        = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    = "/bin/sh -c 'git log --pretty=\"format:%ci, author:%aN <%aE>, commit:%h\" -1 \"${1}\" || echo no git'"
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = YES
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = ../
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.l \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            = header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            = footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = customdoxygen.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL         =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR           = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS       = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION        = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html
+# #tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           = ../include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
+# The default value is: YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH    = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/Doxyfile.in b/doc/doxygen/Doxyfile.in
new file mode 100644
index 0000000000000000000000000000000000000000..08f1e393dfc96d96f6300a1754b7ab66993be9ee
--- /dev/null
+++ b/doc/doxygen/Doxyfile.in
@@ -0,0 +1,2660 @@
+# Doxyfile 1.9.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "PLATO cmp_tool"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "PLATO Compression/Decompression Tool"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = YES
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = YES
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE        = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    = "/bin/sh -c 'git log --pretty=\"format:%ci, author:%aN <%aE>, commit:%h\" -1 \"${1}\" || echo no git'"
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            = @DOXYDIR@/DoxygenLayout.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @SRCDIR@
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.l \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f18 \
+                         *.f \
+                         *.for \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf \
+                         *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = @BUILDDIR@
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             = images #TODO
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = YES
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            = @DOXYDIR@/header.html
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            = @DOXYDIR@/footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  = @DOXYDIR@/customdoxygen.css
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       = @DOXYDIR@/bootstrap.min.css \
+                         @DOXYDIR@/bootstrap.min.js \
+                         @DOXYDIR@/doxy-boot.js
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL         =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR           = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS       = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE      =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION        = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html
+# #tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           = @SRCDIR@/include @BUILDDIR@/include
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT               = @HAVE_DOT@
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
+# The default value is: YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = YES
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH    = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP            = YES
diff --git a/doc/doxygen/DoxygenLayout.xml b/doc/doxygen/DoxygenLayout.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7479687ef34ccb9d265a30c64f63b44943fceee6
--- /dev/null
+++ b/doc/doxygen/DoxygenLayout.xml
@@ -0,0 +1,194 @@
+<doxygenlayout version="1.0">
+  <!-- Generated by doxygen 1.8.11 -->
+  <!-- Navigation index tabs for HTML output -->
+  <navindex>
+    <tab type="mainpage" visible="yes" title=""/>
+    <tab type="pages" visible="yes" title="" intro=""/>
+    <tab type="modules" visible="yes" title="" intro=""/>
+    <tab type="namespaces" visible="yes" title="">
+      <tab type="namespacelist" visible="yes" title="" intro=""/>
+      <tab type="namespacemembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="classes" visible="yes" title="">
+      <tab type="classlist" visible="yes" title="" intro=""/>
+      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
+      <tab type="hierarchy" visible="yes" title="" intro=""/>
+      <tab type="classmembers" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="files" visible="yes" title="">
+      <tab type="filelist" visible="yes" title="" intro=""/>
+      <tab type="globals" visible="yes" title="" intro=""/>
+    </tab>
+    <tab type="examples" visible="yes" title="" intro=""/>  
+  </navindex>
+
+  <!-- Layout definition for a class page -->
+  <class>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <inheritancegraph visible="$CLASS_GRAPH"/>
+    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+    <detaileddescription title=""/>
+    <memberdecl>
+      <nestedclasses visible="yes" title=""/>
+      <publictypes title=""/>
+      <services title=""/>
+      <interfaces title=""/>
+      <publicslots title=""/>
+      <signals title=""/>
+      <publicmethods title=""/>
+      <publicstaticmethods title=""/>
+      <publicattributes title=""/>
+      <publicstaticattributes title=""/>
+      <protectedtypes title=""/>
+      <protectedslots title=""/>
+      <protectedmethods title=""/>
+      <protectedstaticmethods title=""/>
+      <protectedattributes title=""/>
+      <protectedstaticattributes title=""/>
+      <packagetypes title=""/>
+      <packagemethods title=""/>
+      <packagestaticmethods title=""/>
+      <packageattributes title=""/>
+      <packagestaticattributes title=""/>
+      <properties title=""/>
+      <events title=""/>
+      <privatetypes title=""/>
+      <privateslots title=""/>
+      <privatemethods title=""/>
+      <privatestaticmethods title=""/>
+      <privateattributes title=""/>
+      <privatestaticattributes title=""/>
+      <friends title=""/>
+      <related title="" subtitle=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <services title=""/>
+      <interfaces title=""/>
+      <constructors title=""/>
+      <functions title=""/>
+      <related title=""/>
+      <variables title=""/>
+      <properties title=""/>
+      <events title=""/>
+    </memberdef>
+    <allmemberslink visible="yes"/>
+    <usedfiles visible="$SHOW_USED_FILES"/>
+    <authorsection visible="yes"/>
+  </class>
+
+  <!-- Layout definition for a namespace page -->
+  <namespace>
+    <briefdescription visible="yes"/>
+    <detaileddescription title=""/>
+    <memberdecl>
+      <nestednamespaces visible="yes" title=""/>
+      <constantgroups visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <memberdef>
+      <inlineclasses title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </namespace>
+
+  <!-- Layout definition for a file page -->
+  <file>
+    <briefdescription visible="yes"/>
+    <includes visible="$SHOW_INCLUDE_FILES"/>
+    <includegraph visible="$INCLUDE_GRAPH"/>
+    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+    <sourcelink visible="yes"/>
+    <detaileddescription title=""/>
+    <memberdecl>
+      <classes visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <constantgroups visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <memberdef>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <functions title=""/>
+      <variables title=""/>
+    </memberdef>
+    <authorsection/>
+  </file>
+
+  <!-- Layout definition for a group page -->
+  <group>
+    <briefdescription visible="yes"/>
+    <groupgraph visible="$GROUP_GRAPHS"/>
+    <detaileddescription title=""/>
+    <memberdecl>
+      <nestedgroups visible="yes" title=""/>
+      <dirs visible="yes" title=""/>
+      <files visible="yes" title=""/>
+      <namespaces visible="yes" title=""/>
+      <classes visible="yes" title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+      <membergroups visible="yes"/>
+    </memberdecl>
+    <memberdef>
+      <pagedocs/>
+      <inlineclasses title=""/>
+      <defines title=""/>
+      <typedefs title=""/>
+      <enums title=""/>
+      <enumvalues title=""/>
+      <functions title=""/>
+      <variables title=""/>
+      <signals title=""/>
+      <publicslots title=""/>
+      <protectedslots title=""/>
+      <privateslots title=""/>
+      <events title=""/>
+      <properties title=""/>
+      <friends title=""/>
+    </memberdef>
+    <authorsection visible="yes"/>
+  </group>
+
+  <!-- Layout definition for a directory page -->
+  <directory>
+    <briefdescription visible="yes"/>
+    <directorygraph visible="yes"/>
+    <memberdecl>
+      <dirs visible="yes"/>
+      <files visible="yes"/>
+    </memberdecl>
+    <detaileddescription title=""/>
+  </directory>
+</doxygenlayout>
diff --git a/doc/doxygen/bootstrap.min.css b/doc/doxygen/bootstrap.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..4cf729e4342a51d8b300e8d43f2f78b0a6faf403
--- /dev/null
+++ b/doc/doxygen/bootstrap.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}
+/*# sourceMappingURL=bootstrap.min.css.map */
\ No newline at end of file
diff --git a/doc/doxygen/bootstrap.min.js b/doc/doxygen/bootstrap.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..e79c065134f2cfcf3e44a59cffcb5f090232f98f
--- /dev/null
+++ b/doc/doxygen/bootstrap.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v3.3.6 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");
+d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
diff --git a/doc/doxygen/customdoxygen.css b/doc/doxygen/customdoxygen.css
new file mode 100644
index 0000000000000000000000000000000000000000..6a32ca7cc14ef237589954afbe62418891459d9e
--- /dev/null
+++ b/doc/doxygen/customdoxygen.css
@@ -0,0 +1,306 @@
+/*
+h1, .h1, h2, .h2, h3, .h3{
+    font-weight: 200 !important;
+}
+*/
+
+h1,.h1 {
+  font-size: 24px;
+}
+
+h2,.h2 {
+  font-size: 20px;
+}
+
+h3,.h3 {
+  font-size: 16px;
+}
+
+h4,.h4 {
+  font-size: 14px;
+}
+
+h5,.h5 {
+  font-size: 12px;
+}
+
+h6,.h6 {
+  font-size: 10px;
+}
+
+
+
+#navrow1, #navrow2, #navrow3, #navrow4, #navrow5{
+    border-bottom: 1px solid #706d6e;
+}
+
+.adjust-right {
+margin-left: 30px !important;
+font-size: 1.15em !important;
+}
+.navbar{
+ border: 0px solid #222 !important;
+}
+
+
+/* Sticky footer styles
+-------------------------------------------------- */
+html,
+body {
+    height: 100%;
+    /* The html and body elements cannot have any padding or margin. */
+}
+
+img {
+max-width:100%;
+max-height:100%;
+}
+
+/* Wrapper for page content to push down footer */
+#wrap {
+    min-height: 100%;
+    height: auto;
+    /* Negative indent footer by its height */
+    margin: 0 auto -60px;
+    /* Pad bottom by footer height */
+    padding: 0 0 60px;
+}
+
+/* Set the fixed height of the footer here */
+#footer {
+    font-size: 0.9em;
+    padding: 8px 0px;
+    background-color: #f5f5f5;
+}
+
+.footer-row {
+    line-height: 44px;
+}
+
+#footer > .container {
+    padding-left: 15px;
+    padding-right: 15px;
+}
+
+.footer-follow-icon {
+    margin-left: 3px;
+    text-decoration: none !important;
+}
+
+.footer-follow-icon img {
+    width: 20px;
+}
+
+.footer-link {
+    padding-top: 5px;
+    display: inline-block;
+    color: #999999;
+    text-decoration: none;
+}
+
+.footer-copyright {
+    text-align: center;
+}
+
+
+@media (min-width: 992px) {
+    .footer-row {
+        text-align: left;
+    }
+
+    .footer-icons {
+        text-align: right;
+    }
+}
+@media (max-width: 991px) {
+    .footer-row {
+        text-align: center;
+    }
+
+    .footer-icons {
+        text-align: center;
+    }
+}
+
+/* DOXYGEN Code Styles
+----------------------------------- */
+
+	
+div.ingroups {
+    font-size: 16pt;
+    width: 50%;
+    text-align: left;
+    padding-top: 10px;
+}
+
+a.qindex {
+    font-size:  8pt;
+}
+
+a.qindexHL {
+    font-size:  9pt;
+    font-weight: bold;
+    background-color: #9CAFD4;
+    color: #ffffff;
+    border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+    color: #ffffff;
+}
+
+a.code, a.code:visited, a.line, a.line:visited {
+    color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
+    color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+    margin-left: -1cm;
+}
+
+pre.fragment {
+    border: 1px solid #C4CFE5;
+    background-color: #FBFCFD;
+    padding: 4px 6px;
+    margin: 4px 8px 4px 2px;
+    overflow: auto;
+    word-wrap: break-word;
+    font-size:  8pt;
+    line-height: 125%;
+    font-family: monospace, fixed;
+}
+
+div.navtab {
+    text-align: left;
+    padding-left: 5px;
+    margin-right: 5px;
+}
+
+div.fragment {
+    padding: 4px 6px;
+    margin: 4px 8px 4px 2px;
+    border: 1px solid #C4CFE5;
+}
+
+div.line {
+    font-family: monospace, fixed;
+    font-size: 13px;
+    min-height: 13px;
+    line-height: 1.0;
+    text-wrap: unrestricted;
+    white-space: -moz-pre-wrap; /* Moz */
+    white-space: -pre-wrap;     /* Opera 4-6 */
+    white-space: -o-pre-wrap;   /* Opera 7 */
+    white-space: pre-wrap;      /* CSS3  */
+    word-wrap: break-word;      /* IE 5.5+ */
+    text-indent: -53px;
+    padding-left: 53px;
+    padding-bottom: 0px;
+    margin: 0px;
+    -webkit-transition-property: background-color, box-shadow;
+    -webkit-transition-duration: 0.5s;
+    -moz-transition-property: background-color, box-shadow;
+    -moz-transition-duration: 0.5s;
+    -ms-transition-property: background-color, box-shadow;
+    -ms-transition-duration: 0.5s;
+    -o-transition-property: background-color, box-shadow;
+    -o-transition-duration: 0.5s;
+    transition-property: background-color, box-shadow;
+    transition-duration: 0.5s;
+}
+
+div.line.glow {
+    background-color: cyan;
+    box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+    padding-right: 4px;
+    text-align: right;
+    border-right: 2px solid #0F0;
+    background-color: #E8E8E8;
+    white-space: pre;
+}
+span.lineno a {
+    background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+    background-color: #C8C8C8;
+}
+
+div.groupHeader {
+    margin-left: 16px;
+    margin-top: 12px;
+    font-weight: bold;
+}
+
+div.groupText {
+    margin-left: 16px;
+    font-style: italic;
+}
+
+.caption {
+	font-weight: bold;
+	padding-top: 10px;
+	padding-bottom: 20px;
+}
+/* @group Code Colorization */
+
+span.keyword {
+    color: #008000
+}
+
+span.keywordtype {
+    color: #604020
+}
+
+span.keywordflow {
+    color: #e08000
+}
+
+span.comment {
+    color: #800000
+}
+
+span.preprocessor {
+    color: #806020
+}
+
+span.stringliteral {
+    color: #002080
+}
+
+span.charliteral {
+    color: #008080
+}
+
+span.vhdldigit {
+    color: #ff00ff
+}
+
+span.vhdlchar {
+    color: #000000
+}
+
+span.vhdlkeyword {
+    color: #700070
+}
+
+span.vhdllogic {
+    color: #ff0000
+}
+
+blockquote {
+    background-color: #F7F8FB;
+    border-left: 2px solid #9CAFD4;
+    margin: 0 24px 0 4px;
+    padding: 0 12px 0 16px;
+}
+
diff --git a/doc/doxygen/doxy-boot.js b/doc/doxygen/doxy-boot.js
new file mode 100644
index 0000000000000000000000000000000000000000..f045d16f2b2aa6bded9165c8ad19f1a04eb3c9da
--- /dev/null
+++ b/doc/doxygen/doxy-boot.js
@@ -0,0 +1,121 @@
+$( document ).ready(function() {
+
+    $("div.headertitle").addClass("page-header");
+    $("div.title").addClass("h1");
+
+    $('li > a[href="index.html"] > span').before("<i class='fa fa-cog'></i> ");
+    $('li > a[href="index.html"] > span').text("CHEOPS IBSW");
+    $('li > a[href="modules.html"] > span').before("<i class='fa fa-square'></i> ");
+    $('li > a[href="namespaces.html"] > span').before("<i class='fa fa-bars'></i> ");
+    $('li > a[href="annotated.html"] > span').before("<i class='fa fa-list-ul'></i> ");
+    $('li > a[href="classes.html"] > span').before("<i class='fa fa-book'></i> ");
+    $('li > a[href="inherits.html"] > span').before("<i class='fa fa-sitemap'></i> ");
+    $('li > a[href="functions.html"] > span').before("<i class='fa fa-list'></i> ");
+    $('li > a[href="functions_func.html"] > span').before("<i class='fa fa-list'></i> ");
+    $('li > a[href="functions_vars.html"] > span').before("<i class='fa fa-list'></i> ");
+    $('li > a[href="functions_enum.html"] > span').before("<i class='fa fa-list'></i> ");
+    $('li > a[href="functions_eval.html"] > span').before("<i class='fa fa-list'></i> ");
+    $('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
+    $('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
+
+    $("ul.tablist").addClass("nav nav-pills nav-justified");
+    $("ul.tablist").css("margin-top", "0.5em");
+    $("ul.tablist").css("margin-bottom", "0.5em");
+    $("li.current").addClass("active");
+    $("iframe").attr("scrolling", "yes");
+
+    $("#nav-path > ul").addClass("breadcrumb");
+
+    $("table.params").addClass("table");
+    $("div.ingroups").wrapInner("<small></small>");
+    $("div.levels").css("margin", "0.5em");
+    $("div.levels > span").addClass("btn btn-default btn-xs");
+    $("div.levels > span").css("margin-right", "0.25em");
+
+    $("table.directory").addClass("table table-striped");
+    $("div.summary > a").addClass("btn btn-default btn-xs");
+    $("table.fieldtable").addClass("table");
+    $(".fragment").addClass("well");
+    $(".memitem").addClass("panel panel-default");
+    $(".memproto").addClass("panel-heading");
+    $(".memdoc").addClass("panel-body");
+    $("span.mlabel").addClass("label label-info");
+
+    $("table.memberdecls").addClass("table");
+    $("[class^=memitem]").addClass("active");
+
+    $("div.ah").addClass("btn btn-default");
+    $("span.mlabels").addClass("pull-right");
+    $("table.mlabels").css("width", "100%")
+    $("td.mlabels-right").addClass("pull-right");
+
+    $("div.ttc").addClass("panel panel-primary");
+    $("div.ttname").addClass("panel-heading");
+    $("div.ttname a").css("color", 'white');
+    $("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
+
+    $('#MSearchBox').parent().remove();
+
+    $('div.fragment.well div.line:first').css('margin-top', '15px');
+    $('div.fragment.well div.line:last').css('margin-bottom', '15px');
+	
+	$('table.doxtable').removeClass('doxtable').addClass('table table-striped table-bordered').each(function(){
+		$(this).prepend('<thead></thead>');
+		$(this).find('tbody > tr:first').prependTo($(this).find('thead'));
+		
+		$(this).find('td > span.success').parent().addClass('success');
+		$(this).find('td > span.warning').parent().addClass('warning');
+		$(this).find('td > span.danger').parent().addClass('danger');
+	});
+	
+	
+
+    if($('div.fragment.well div.ttc').length > 0)
+    {
+        $('div.fragment.well div.line:first').parent().removeClass('fragment well');
+    }
+
+    $('table.memberdecls').find('.memItemRight').each(function(){
+        $(this).contents().appendTo($(this).siblings('.memItemLeft'));
+        $(this).siblings('.memItemLeft').attr('align', 'left');
+    });
+	
+	function getOriginalWidthOfImg(img_element) {
+		var t = new Image();
+		t.src = (img_element.getAttribute ? img_element.getAttribute("src") : false) || img_element.src;
+		return t.width;
+	}
+	
+	$('div.dyncontent').find('img').each(function(){
+		if(getOriginalWidthOfImg($(this)[0]) > $('#content>div.container').width())
+			$(this).css('width', '100%');
+	});
+	
+	$(".memitem").removeClass('memitem');
+    $(".memproto").removeClass('memproto');
+    $(".memdoc").removeClass('memdoc');
+	$("span.mlabel").removeClass('mlabel');
+	$("table.memberdecls").removeClass('memberdecls');
+    $("[class^=memitem]").removeClass('memitem');
+    $("span.mlabels").removeClass('mlabels');
+    $("table.mlabels").removeClass('mlabels');
+    $("td.mlabels-right").removeClass('mlabels-right');
+	$(".navpath").removeClass('navpath');
+	$("li.navelem").removeClass('navelem');
+	$("a.el").removeClass('el');
+	$("div.ah").removeClass('ah');
+	$("div.header").removeClass("header");
+	
+	$('.mdescLeft').each(function(){
+		if($(this).html()=="&nbsp;") {
+			$(this).siblings('.mdescRight').attr('colspan', 2);
+			$(this).remove();
+		}
+	});
+	$('td.memItemLeft').each(function(){
+		if($(this).siblings('.memItemRight').html()=="") {
+			$(this).attr('colspan', 2);
+			$(this).siblings('.memItemRight').remove();
+		}
+	});
+});
diff --git a/doc/doxygen/footer.html b/doc/doxygen/footer.html
new file mode 100644
index 0000000000000000000000000000000000000000..f2fa20497a366600145ea79809f6250cf08f2704
--- /dev/null
+++ b/doc/doxygen/footer.html
@@ -0,0 +1,26 @@
+<!-- HTML footer for doxygen 1.8.8-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+  <ul>
+    $navpath
+    <li class="footer">$generatedby
+    <a href="http://www.doxygen.org/index.html">
+    <img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+  </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+</div>
+</div>
+</div>
+</div>
+</div>
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby &#160;<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/doc/doxygen/header.html b/doc/doxygen/header.html
new file mode 100644
index 0000000000000000000000000000000000000000..d4b85eb86c9df8e6cc1f10c931e7e3626d0e4cf1
--- /dev/null
+++ b/doc/doxygen/header.html
@@ -0,0 +1,47 @@
+<!-- HTML header for doxygen 1.8.8-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+    <head>
+        <meta http-equiv="X-UA-Compatible" content="IE=edge">
+        <!-- For Mobile Devices -->
+        <meta name="viewport" content="width=device-width, initial-scale=1">
+
+        <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+        <meta name="generator" content="Doxygen $doxygenversion"/>
+
+        <script type="text/javascript" src="jquery.js"></script>
+
+        <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+        <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+        <!--<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>-->
+        <script type="text/javascript" src="$relpath^dynsections.js"></script>
+        $treeview
+        $search
+        $mathjax
+        <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+
+	<link rel="stylesheet" href="$relpath^bootstrap.min.css">
+
+	$extrastylesheet
+
+        <script src="$relpath^bootstrap.min.js"></script>
+        <script type="text/javascript" src="$relpath^doxy-boot.js"></script>
+    </head>
+    <body>
+
+        <nav class="navbar navbar-default" role="navigation">
+            <div class="container">
+                <div class="navbar-header">
+			<a class="navbar-brand">
+				<img alt="Logo" align="left" style="margin-right: 1em;" src=$projectlogo/>
+				$projectname $projectnumber</a>
+                </div>
+            </div>
+        </nav>
+        <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+            <div class="content" id="content">
+                <div class="container">
+                    <div class="row">
+                        <div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
+                            <div style="margin-bottom: 15px;">
+<!-- end header part -->
diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..f7facf3ce893be7c518ec203750ea43434a88f51
--- /dev/null
+++ b/doc/doxygen/meson.build
@@ -0,0 +1,42 @@
+doc_layout_files = files([
+  'DoxygenLayout.xml',
+  'bootstrap.min.css',
+  'customdoxygen.css',
+  'bootstrap.min.js',
+  'doxy-boot.js',
+  'header.html',
+  'footer.html'
+])
+
+
+#Build a Doxyfile based on Doxyfile.in
+cdata_doc = configuration_data()
+cdata_doc.set('VERSION', meson.project_version())
+cdata_doc.set('SRCDIR', meson.project_source_root())
+cdata_doc.set('DOXYDIR', meson.current_source_dir())
+cdata_doc.set('BUILDDIR', meson.project_build_root())
+if find_program('dot', required : false).found()
+  cdata_doc.set('HAVE_DOT', 'YES')
+else
+  cdata_doc.set('HAVE_DOT', 'NO')
+endif
+
+doxygen = find_program('doxygen', required : false)
+
+if doxygen.found()
+  doxy_file = configure_file(
+    input : 'Doxyfile.in',
+    output : 'Doxyfile',
+    configuration : cdata_doc,
+    install : false,
+  )
+
+  custom_target('doc',
+    input : doxy_file,
+    output : 'html',
+    depend_files : [doc_layout_files, main, cmplib_sources],
+    command : [doxygen, '@INPUT@'],
+    build_by_default : false,
+    console : true,
+  )
+endif
diff --git a/include/cmp_data_types.h b/include/cmp_data_types.h
index 345c0ae185cb488cd877daaaf6236d0b332b5d8e..41a39f7b7464a0704223408429fcec1b8eef0c78 100644
--- a/include/cmp_data_types.h
+++ b/include/cmp_data_types.h
@@ -14,17 +14,20 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
+ * @see for N-DPU packed definition: PLATO-LESIA-PL-RP-0031 Issue: 1.9 (N-DPU->ICU data rate)
+ * @see for calculation of the max used bits: PLATO-LESIA-PDC-TN-0054 Issue: 1.7
  *
- * Three data rates:
+ * Three data rates (for N-DPU):
  * fast cadence (nominally 25s)
  * short cadence (nominally 50s)
  * long cadence (nominally 600s)
  *
  * The science products are identified as this:
- * FX = normal light flux
- * NCOB = normal center of brightness
- * EFX = extended flux
- * ECOB = extended center of brightness
+ * exp_flags = selected exposure flags
+ * fx = normal light flux
+ * ncob = normal center of brightness
+ * efx = extended flux
+ * ecob = extended center of brightness
  * The prefixes F, S and L stand for Fast, Short and Long cadence
  */
 
@@ -33,158 +36,245 @@
 
 #include <stdint.h>
 
-#define MODE_RAW_S_FX           100
-#define MODE_MODEL_ZERO_S_FX	101
-#define MODE_DIFF_ZERO_S_FX	102
-#define MODE_MODEL_MULTI_S_FX	103
-#define MODE_DIFF_MULTI_S_FX	104
-
-#define MODE_MODEL_ZERO_S_FX_EFX	110
-#define MODE_DIFF_ZERO_S_FX_EFX		111
-#define MODE_MODEL_MULTI_S_FX_EFX	112
-#define MODE_DIFF_MULTI_S_FX_EFX	113
-
-#define MODE_MODEL_ZERO_S_FX_NCOB	120
-#define MODE_DIFF_ZERO_S_FX_NCOB	121
-#define MODE_MODEL_MULTI_S_FX_NCOB	122
-#define MODE_DIFF_MULTI_S_FX_NCOB	123
-
-#define MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB	130
-#define MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB	131
-#define MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB	132
-#define MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB	133
-
-#define MODE_MODEL_ZERO_F_FX	140
-#define MODE_DIFF_ZERO_F_FX	141
-#define MODE_MODEL_MULTI_F_FX	142
-#define MODE_DIFF_MULTI_F_FX	143
-
-#define MODE_MODEL_ZERO_F_FX_EFX	150
-#define MODE_DIFF_ZERO_F_FX_EFX		151
-#define MODE_MODEL_MULTI_F_FX_EFX	152
-#define MODE_DIFF_MULTI_F_FX_EFX	153
-
-#define MODE_MODEL_ZERO_F_FX_NCOB	160
-#define MODE_DIFF_ZERO_F_FX_NCOB	161
-#define MODE_MODEL_MULTI_F_FX_NCOB	162
-#define MODE_DIFF_MULTI_F_FX_NCOB	163
-
-#define MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB	170
-#define MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB	171
-#define MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB	172
-#define MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB	173
-
-#define MODE_RAW_32		200
-#define MODE_DIFF_ZERO_32	201
-#define MODE_DIFF_MULTI_32	202
-#define MODE_MODEL_ZERO_32	203
-#define MODE_MODEL_MULTI_32	204
-
-int lossy_rounding_16(uint16_t *data_buf, unsigned int samples, unsigned int
-		      round);
-int de_lossy_rounding_16(uint16_t *data_buf, uint32_t samples_used, uint32_t
-			 round_used);
-
-int lossy_rounding_32(uint32_t *data_buf, unsigned int samples, unsigned int
-		      round);
-int de_lossy_rounding_32(uint32_t *data_buf, uint32_t samples_used, uint32_t
-			 round_used);
-
-/* @see PLATO-LESIA-PL-RP-0031 Issue: 1.9 (N-DPU->ICU data rate) */
-struct __attribute__((packed)) S_FX {
-	uint8_t EXPOSURE_FLAGS;
-	uint32_t FX;
+#include <compiler.h>
+#include <cmp_support.h>
+
+#define MAX_USED_NC_IMAGETTE_BITS		16
+#define MAX_USED_SATURATED_IMAGETTE_BITS	16 /* TBC */
+#define MAX_USED_FC_IMAGETTE_BITS		16 /* TBC */
+
+#define MAX_USED_F_FX_BITS	21 /* max exp. int value: (1.078*10^5)/0.1 = 1,078,000 -> 21 bits */
+#define MAX_USED_F_EFX_BITS	MAX_USED_F_FX_BITS /* we use the same as f_fx */
+#define MAX_USED_F_NCOB_BITS	20 /* max exp. int value: 6/10^−5 = 6*10^5 -> 20 bits */
+#define MAX_USED_F_ECOB_BITS	32 /* TBC */
+
+#define MAX_USED_S_FX_EXPOSURE_FLAGS_BITS	2 /* 2 flags + 6 spare bits */
+#define MAX_USED_S_FX_BITS			24 /* max exp. int value: (1.078*10^5-34.71)/0.01 = 10,780,000-> 24 bits */
+#define MAX_USED_S_EFX_BITS			MAX_USED_S_FX_BITS /* we use the same as s_fx */
+#define MAX_USED_S_NCOB_BITS			MAX_USED_F_NCOB_BITS
+#define MAX_USED_S_ECOB_BITS			32 /* TBC */
+
+#define MAX_USED_L_FX_EXPOSURE_FLAGS_BITS	24 /* 24 flags */
+#define MAX_USED_L_FX_BITS			MAX_USED_S_FX_BITS
+#define MAX_USED_L_FX_VARIANCE_BITS		32 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */
+#define MAX_USED_L_EFX_BITS			MAX_USED_L_FX_BITS /* we use the same as l_fx */
+#define MAX_USED_L_NCOB_BITS			MAX_USED_F_NCOB_BITS
+#define MAX_USED_L_ECOB_BITS			32 /* TBC */
+#define MAX_USED_L_COB_VARIANCE_BITS		25 /* max exp int value: 0.1739/10^−8 = 17390000 -> 25 bits */
+
+#define MAX_USED_NC_OFFSET_MEAN_BITS		2 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */
+#define MAX_USED_NC_OFFSET_VARIANCE_BITS	10 /* max exp. int value: 9.31/0.01 = 931 -> 10 bits */
+
+#define MAX_USED_NC_BACKGROUND_MEAN_BITS		16 /* max exp. int value: (391.8-(-50))/0.01 = 44,180 -> 16 bits */
+#define MAX_USED_NC_BACKGROUND_VARIANCE_BITS		16 /* max exp. int value: 6471/0.1 = 64710 -> 16 bit */
+#define MAX_USED_NC_BACKGROUND_OUTLIER_PIXELS_BITS	5 /* maximum = 16 -> 5 bits */
+
+#define MAX_USED_SMEARING_MEAN_BITS		15 /* max exp. int value: (219.9 - -50)/0.01 = 26.990 */
+#define MAX_USED_SMEARING_VARIANCE_MEAN_BITS	16 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */
+#define MAX_USED_SMEARING_OUTLIER_PIXELS_BITS	11 /* maximum = 1200 -> 11 bits */
+
+#define MAX_USED_FC_OFFSET_MEAN_BITS		32 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */
+#define MAX_USED_FC_OFFSET_VARIANCE_BITS	9  /* max exp. int value: 342/1 = 342 -> 9 bits */
+#define MAX_USED_FC_OFFSET_PIXEL_IN_ERROR_BITS	16 /* TBC */
+
+#define MAX_USED_FC_BACKGROUND_MEAN_BITS		10 /* max exp. int value: (35.76-(-50))/0.1 = 858 -> 10 bits*/
+#define MAX_USED_FC_BACKGROUND_VARIANCE_BITS		6 /* max exp. int value: 53.9/1 = 54 -> 6 bits */
+#define MAX_USED_FC_BACKGROUND_OUTLIER_PIXELS_BITS	16 /* TBC */
+
+
+/* struct holding the maximum length of the different data products types in bits */
+struct cmp_max_used_bits {
+	uint8_t version;
+	unsigned int s_exp_flags;
+	unsigned int s_fx;
+	unsigned int s_efx;
+	unsigned int s_ncob; /* s_ncob_x and s_ncob_y */
+	unsigned int s_ecob; /* s_ecob_x and s_ncob_y */
+	unsigned int f_fx;
+	unsigned int f_efx;
+	unsigned int f_ncob; /* f_ncob_x and f_ncob_y */
+	unsigned int f_ecob; /* f_ecob_x and f_ncob_y */
+	unsigned int l_exp_flags;
+	unsigned int l_fx;
+	unsigned int l_fx_variance;
+	unsigned int l_efx;
+	unsigned int l_ncob; /* l_ncob_x and l_ncob_y */
+	unsigned int l_ecob; /* l_ecob_x and l_ncob_y */
+	unsigned int l_cob_variance; /* l_cob_x_variance and l_cob_y_variance */
+	unsigned int nc_imagette;
+	unsigned int saturated_imagette;
+	unsigned int nc_offset_mean;
+	unsigned int nc_offset_variance;
+	unsigned int nc_background_mean;
+	unsigned int nc_background_variance;
+	unsigned int nc_background_outlier_pixels;
+	unsigned int smearing_mean;
+	unsigned int smearing_variance_mean;
+	unsigned int smearing_outlier_pixels;
+	unsigned int fc_imagette;
+	unsigned int fc_offset_mean;
+	unsigned int fc_offset_variance;
+	unsigned int fc_offset_pixel_in_error;
+	unsigned int fc_background_mean;
+	unsigned int fc_background_variance;
+	unsigned int fc_background_outlier_pixels;
 };
 
-struct S_FX sub_S_FX(struct S_FX a, struct S_FX b);
-struct S_FX add_S_FX(struct S_FX a, struct S_FX b);
-int lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples,
-			       unsigned int round);
-int de_lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples_used,
-			   unsigned int round_used);
-struct S_FX cal_up_model_S_FX(struct S_FX data_buf, struct S_FX model_buf,
-			      unsigned int model_value);
-
-
-struct S_FX_EFX {
-	uint8_t EXPOSURE_FLAGS;
-	uint32_t FX;
-	uint32_t EFX;
-}__attribute__((packed));
-
-struct S_FX_EFX sub_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b);
-struct S_FX_EFX add_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b);
-int lossy_rounding_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples,
-				   unsigned int round);
-int de_lossy_rounding_S_FX_EFX(struct S_FX_EFX *data_buf, unsigned int
-			       samples_used, unsigned int round_used);
-struct S_FX_EFX cal_up_model_S_FX_EFX(struct S_FX_EFX data_buf, struct S_FX_EFX
-				      model_buf, unsigned int model_value);
-
-
-struct S_FX_NCOB {
-	uint8_t EXPOSURE_FLAGS;
-	uint32_t FX;
-	uint32_t NCOB_X;
-	uint32_t NCOB_Y;
-}__attribute__((packed));
-
-struct S_FX_NCOB sub_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b);
-struct S_FX_NCOB add_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b);
-int lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int samples,
-			     unsigned int round);
-int de_lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int
-				samples_used, unsigned int round_used);
-struct S_FX_NCOB cal_up_model_S_FX_NCOB(struct S_FX_NCOB data_buf, struct
-					S_FX_NCOB model_buf, unsigned int
-					model_value);
-
-
-struct S_FX_EFX_NCOB_ECOB {
-	uint8_t EXPOSURE_FLAGS;
-	uint32_t FX;
-	uint32_t NCOB_X;
-	uint32_t NCOB_Y;
-	uint32_t EFX;
-	uint32_t ECOB_X;
-	uint32_t ECOB_Y;
-}__attribute__((packed));
-
-struct S_FX_EFX_NCOB_ECOB sub_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a,
-						 struct S_FX_EFX_NCOB_ECOB b);
-struct S_FX_EFX_NCOB_ECOB add_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a,
-						 struct S_FX_EFX_NCOB_ECOB b);
-int lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-				      unsigned int samples, unsigned int round);
-int de_lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-					 unsigned int samples,
-					 unsigned int round);
-
-struct F_FX {
-	uint32_t FX;
-}__attribute__((packed));
-
-
-struct F_FX_EFX {
-	uint32_t FX;
-	uint32_t EFX;
-}__attribute__((packed));
-
-
-struct F_FX_NCOB {
-	uint32_t FX;
-	uint32_t NCOB_X;
-	uint32_t NCOB_Y;
-}__attribute__((packed));
-
-
-struct F_FX_EFX_NCOB_ECOB {
-	uint32_t FX;
-	uint32_t NCOB_X;
-	uint32_t NCOB_Y;
-	uint32_t EFX;
-	uint32_t ECOB_X;
-	uint32_t ECOB_Y;
-}__attribute__((packed));
+
+/* Set and read the max_used_bits, which specify how many bits are needed to
+ * represent the highest possible value.
+ */
+void cmp_set_max_used_bits(const struct cmp_max_used_bits *set_max_used_bits);
+struct cmp_max_used_bits cmp_get_max_used_bits(void);
+
+uint8_t cmp_get_max_used_bits_version(void);
+
+
+/* Source data header structure for multi entry packet */
+#define MULTI_ENTRY_HDR_SIZE 12
+compile_time_assert(MULTI_ENTRY_HDR_SIZE % sizeof(uint32_t) == 0, N_DPU_ICU_MULTI_ENTRY_HDR_NOT_4_BYTE_ALLIED);
+
+__extension__
+struct multi_entry_hdr {
+	uint32_t timestamp_coarse;
+	uint16_t timestamp_fine;
+	uint16_t configuration_id;
+	uint16_t collection_id;
+	uint16_t collection_length;
+	uint8_t  entry[];
+} __attribute__((packed));
+compile_time_assert(sizeof(struct multi_entry_hdr) == MULTI_ENTRY_HDR_SIZE, N_DPU_ICU_MULTI_ENTRY_HDR_SIZE_IS_NOT_CORRECT);
+
+
+struct s_fx {
+	uint8_t exp_flags; /* selected exposure flags (2 flags + 6 spare bits) */
+	uint32_t fx;       /* normal light flux */
+} __attribute__((packed));
+
+
+struct s_fx_efx {
+	uint8_t exp_flags;
+	uint32_t fx;
+	uint32_t efx;
+} __attribute__((packed));
+
+
+struct s_fx_ncob {
+	uint8_t exp_flags;
+	uint32_t fx;
+	uint32_t ncob_x;
+	uint32_t ncob_y;
+} __attribute__((packed));
+
+
+struct s_fx_efx_ncob_ecob {
+	uint8_t exp_flags;
+	uint32_t fx;
+	uint32_t ncob_x;
+	uint32_t ncob_y;
+	uint32_t efx;
+	uint32_t ecob_x;
+	uint32_t ecob_y;
+} __attribute__((packed));
+
+
+struct f_fx {
+	uint32_t fx;
+} __attribute__((packed));
+
+
+struct f_fx_efx {
+	uint32_t fx;
+	uint32_t efx;
+} __attribute__((packed));
+
+
+struct f_fx_ncob {
+	uint32_t fx;
+	uint32_t ncob_x;
+	uint32_t ncob_y;
+} __attribute__((packed));
+
+
+struct f_fx_efx_ncob_ecob {
+	uint32_t fx;
+	uint32_t ncob_x;
+	uint32_t ncob_y;
+	uint32_t efx;
+	uint32_t ecob_x;
+	uint32_t ecob_y;
+} __attribute__((packed));
+
+
+__extension__
+struct l_fx {
+	uint32_t exp_flags:24; /* selected exposure flags (24 flags) */
+	uint32_t fx;
+	uint32_t fx_variance;
+} __attribute__((packed));
+
+
+__extension__
+struct l_fx_efx {
+	uint32_t exp_flags:24; /* selected exposure flags (24 flags) */
+	uint32_t fx;
+	uint32_t efx;
+	uint32_t fx_variance;
+} __attribute__((packed));
+
+
+__extension__
+struct l_fx_ncob {
+	uint32_t exp_flags:24; /* selected exposure flags (24 flags) */
+	uint32_t fx;
+	uint32_t ncob_x;
+	uint32_t ncob_y;
+	uint32_t fx_variance;
+	uint32_t cob_x_variance;
+	uint32_t cob_y_variance;
+} __attribute__((packed));
+
+
+__extension__
+struct l_fx_efx_ncob_ecob {
+	uint32_t exp_flags:24; /* selected exposure flags (24 flags) */
+	uint32_t fx;
+	uint32_t ncob_x;
+	uint32_t ncob_y;
+	uint32_t efx;
+	uint32_t ecob_x;
+	uint32_t ecob_y;
+	uint32_t fx_variance;
+	uint32_t cob_x_variance;
+	uint32_t cob_y_variance;
+} __attribute__((packed));
+
+
+struct nc_offset {
+	uint32_t mean;
+	uint32_t variance;
+} __attribute__((packed));
+
+
+struct nc_background {
+	uint32_t mean;
+	uint32_t variance;
+	uint16_t outlier_pixels;
+} __attribute__((packed));
+
+
+struct smearing {
+	uint32_t mean;
+	uint16_t variance_mean;
+	uint16_t outlier_pixels;
+} __attribute__((packed));
+
+
+size_t size_of_a_sample(enum cmp_data_type data_type);
+unsigned int cmp_cal_size_of_data(unsigned int samples, enum cmp_data_type data_type);
+int cmp_input_size_to_samples(unsigned int size, enum cmp_data_type data_type);
+
+int cmp_input_big_to_cpu_endianness(void *data, uint32_t data_size_byte,
+				    enum cmp_data_type data_type);
 
 #endif /* CMP_DATA_TYPE_H */
diff --git a/include/cmp_entity.h b/include/cmp_entity.h
index 2d6bf542f1ec5b0c25f63fd257a2c3fbb325f78d..c56cef5dd37705ac618266443e0a329f01175308 100644
--- a/include/cmp_entity.h
+++ b/include/cmp_entity.h
@@ -29,37 +29,9 @@
 
 #include <stdint.h>
 
-#include "compiler.h"
-#include "cmp_support.h"
-
-
-/* Defined Compression Data Product Types */
-enum cmp_ent_data_type {
-	DATA_TYPE_IMAGETTE = 1,
-	DATA_TYPE_IMAGETTE_ADAPTIVE,
-	DATA_TYPE_SAT_IMAGETTE,
-	DATA_TYPE_SAT_IMAGETTE_ADAPTIVE,
-	DATA_TYPE_OFFSET,
-	DATA_TYPE_BACKGROUND,
-	DATA_TYPE_SMEARING,
-	DATA_TYPE_S_FX,
-	DATA_TYPE_S_FX_DFX,
-	DATA_TYPE_S_FX_NCOB,
-	DATA_TYPE_S_FX_DFX_NCOB_ECOB,
-	DATA_TYPE_L_FX,
-	DATA_TYPE_L_FX_DFX,
-	DATA_TYPE_L_FX_NCOB,
-	DATA_TYPE_L_FX_DFX_NCOB_ECOB,
-	DATA_TYPE_F_FX,
-	DATA_TYPE_F_FX_DFX,
-	DATA_TYPE_F_FX_NCOB,
-	DATA_TYPE_F_FX_DFX_NCOB_ECOB,
-	DATA_TYPE_F_CAM_IMAGETTE,
-	DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE,
-	DATA_TYPE_F_CAM_OFFSET,
-	DATA_TYPE_F_CAM_BACKGROUND,
-	DATA_TYPE_UNKOWN = 0x7FFF,
-};
+#include <compiler.h>
+#include <cmp_support.h>
+
 
 #define GENERIC_HEADER_SIZE 32
 #define SPECIFIC_IMAGETTE_HEADER_SIZE		4
@@ -144,7 +116,7 @@ struct cmp_entity {
 	uint8_t  model_value_used;		/* used Model Updating Weighing Value */
 	uint16_t model_id;			/* Model ID */
 	uint8_t  model_counter;			/* Model Counter */
-	uint8_t  spare;
+	uint8_t  max_used_bits_version;
 	uint16_t lossy_cmp_par_used;		/* used Lossy Compression Parameters */
 	union {	/* specific Compression Entity Header for the different Data Product Types */
 		struct imagette_header ima;
@@ -155,21 +127,31 @@ compile_time_assert(sizeof(struct cmp_entity) == NON_IMAGETTE_HEADER_SIZE, CMP_E
 
 
 
-/* brief create a compression entity by setting the size of the
- * compression entity and the data product type in the entity header
+/* create a compression entity by setting the size of the compression entity and
+ * the data product type in the entity header
  */
-size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
-		      uint32_t cmp_size_byte);
+uint32_t cmp_ent_create(struct cmp_entity *ent, enum cmp_data_type data_type,
+			int raw_mode_flag, uint32_t cmp_size_byte);
 
 /* create a compression entity and set the header fields */
-size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
-		     uint32_t version_id, uint64_t start_time,
-		     uint64_t end_time, uint16_t model_id, uint8_t model_counter,
-		     struct cmp_info *info, struct cmp_cfg *cfg);
+size_t cmp_ent_build(struct cmp_entity *ent, uint32_t version_id,
+		     uint64_t start_time, uint64_t end_time, uint16_t model_id,
+		     uint8_t model_counter, struct cmp_cfg *cfg, int cmp_size_bits);
+
+/* read in a compression entity header */
+int cmp_ent_read_header(struct cmp_entity *ent, struct cmp_cfg *cfg);
 
-/* read in a imagette compression entity header to a info struct */
-int cmp_ent_read_imagette_header(struct cmp_entity *ent, struct cmp_info *info);
+/* write the compression parameters from a compression configuration into the
+ * compression entity header
+ */
+int cmp_ent_write_cmp_pars(struct cmp_entity *ent, const struct cmp_cfg *cfg,
+			   int cmp_size_bits);
 
+/* write the parameters from the RDCU decompression information structure in the
+ * compression entity header
+ */
+int cmp_ent_write_rdcu_cmp_pars(struct cmp_entity *ent, const struct cmp_info *info,
+				const struct cmp_cfg *cfg);
 
 
 /* set functions for generic compression entity header */
@@ -187,12 +169,12 @@ int cmp_ent_set_coarse_end_time(struct cmp_entity *ent, uint32_t coarse_time);
 int cmp_ent_set_fine_end_time(struct cmp_entity *ent, uint16_t fine_time);
 
 int cmp_ent_set_data_type(struct cmp_entity *ent,
-			  enum cmp_ent_data_type data_type);
-int cmp_ent_data_type_valid(enum cmp_ent_data_type data_type);
+			  enum cmp_data_type data_type, int raw_mode);
 int cmp_ent_set_cmp_mode(struct cmp_entity *ent, uint32_t cmp_mode_used);
 int cmp_ent_set_model_value(struct cmp_entity *ent, uint32_t model_value_used);
 int cmp_ent_set_model_id(struct cmp_entity *ent, uint32_t model_id);
 int cmp_ent_set_model_counter(struct cmp_entity *ent, uint32_t model_counter);
+int cmp_ent_set_max_used_bits_version(struct cmp_entity *ent, uint8_t max_used_bits_version);
 int cmp_ent_set_lossy_cmp_par(struct cmp_entity *ent, uint32_t lossy_cmp_par_used);
 
 
@@ -247,13 +229,14 @@ uint64_t cmp_ent_get_end_timestamp(struct cmp_entity *ent);
 uint32_t cmp_ent_get_coarse_end_time(struct cmp_entity *ent);
 uint16_t cmp_ent_get_fine_end_time(struct cmp_entity *ent);
 
-enum cmp_ent_data_type cmp_ent_get_data_type(struct cmp_entity *ent);
+enum cmp_data_type cmp_ent_get_data_type(struct cmp_entity *ent);
 int cmp_ent_get_data_type_raw_bit(struct cmp_entity *ent);
 uint8_t cmp_ent_get_cmp_mode(struct cmp_entity *ent);
 uint8_t cmp_ent_get_model_value_used(struct cmp_entity *ent);
 
 uint16_t cmp_ent_get_model_id(struct cmp_entity *ent);
 uint8_t cmp_ent_get_model_counter(struct cmp_entity *ent);
+uint8_t cmp_ent_get_max_used_bits_version(struct cmp_entity *ent);
 uint16_t cmp_ent_get_lossy_cmp_par(struct cmp_entity *ent);
 
 
@@ -301,14 +284,16 @@ ssize_t cmp_ent_get_cmp_data(struct cmp_entity *ent, uint32_t *data_buf,
 			     size_t data_buf_size);
 
 /* calculate the size of the compression entity header */
-uint32_t cmp_ent_cal_hdr_size(enum cmp_ent_data_type data_type);
+uint32_t cmp_ent_cal_hdr_size(enum cmp_data_type data_type, int raw_mode);
 
 
-#if __has_include(<time.h>)
-#include <time.h>
+#if defined __has_include
+#  if __has_include(<time.h>)
+#    include <time.h>
 /* create a timestamp for the compression header */
 extern const struct tm EPOCH_DATE;
 uint64_t cmp_ent_create_timestamp(const struct timespec *ts);
+#  endif
 #endif
 
 /* print and parse functions */
diff --git a/include/cmp_guess.h b/include/cmp_guess.h
index fe2ed0989a6b8ab188c92a33cb0b43a3ba2414e1..4b26e9cae965aa0aceea4e12fce0cf0549607939 100644
--- a/include/cmp_guess.h
+++ b/include/cmp_guess.h
@@ -20,19 +20,24 @@
 #ifndef CMP_GUESS_H
 #define CMP_GUESS_H
 
-#include "cmp_support.h"
+#include <cmp_support.h>
+
 
 #define DEFAULT_GUESS_LEVEL 2
 
-#define CMP_GUESS_DEF_MODE_DIFF		MODE_DIFF_ZERO
-#define CMP_GUESS_DEF_MODE_MODEL	MODE_MODEL_MULTI
+#define CMP_GUESS_DEF_MODE_DIFF		CMP_MODE_DIFF_ZERO
+#define CMP_GUESS_DEF_MODE_MODEL	CMP_MODE_MODEL_MULTI
 
+/* good guess for the spill parameter using the MODE_DIFF_MULTI */
+#define CMP_GOOD_SPILL_DIFF_MULTI 2U
 /* how often the model is updated before it is reset default value */
 #define CMP_GUESS_N_MODEL_UPDATE_DEF	8
 
 uint32_t cmp_guess(struct cmp_cfg *cfg, int level);
 void cmp_guess_set_model_updates(int n_model_updates);
 
+uint32_t cmp_rdcu_get_good_spill(unsigned int golomb_par, enum cmp_mode cmp_mode);
+
 uint16_t cmp_guess_model_value(int n_model_updates);
 
 #endif /* CMP_GUESS_H */
diff --git a/include/cmp_icu.h b/include/cmp_icu.h
index cd7f193e10ba3e6b89a863c1f259d948f7c0ce8f..743e7d1014b93b162f8d216da25435047e97069a 100644
--- a/include/cmp_icu.h
+++ b/include/cmp_icu.h
@@ -13,7 +13,6 @@
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
- *
  * @brief software compression library
  * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
  */
@@ -21,13 +20,37 @@
 #ifndef _CMP_ICU_H_
 #define _CMP_ICU_H_
 
-#include "../include/cmp_support.h"
+#include <cmp_support.h>
+
+#define CMP_PAR_UNUSED 0
+
+/* create and setup a compression configuration */
+struct cmp_cfg cmp_cfg_icu_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode,
+				  uint32_t model_value, uint32_t lossy_par);
+
+uint32_t cmp_cfg_icu_buffers(struct cmp_cfg *cfg, void *data_to_compress,
+			     uint32_t data_samples, void *model_of_data,
+			     void *updated_model, uint32_t *compressed_data,
+			     uint32_t compressed_data_len_samples);
+
+int cmp_cfg_icu_imagette(struct cmp_cfg *cfg, uint32_t cmp_par,
+			 uint32_t spillover_par);
+
+int cmp_cfg_fx_cob(struct cmp_cfg *cfg,
+		   uint32_t cmp_par_exp_flags, uint32_t spillover_exp_flags,
+		   uint32_t cmp_par_fx, uint32_t spillover_fx,
+		   uint32_t cmp_par_ncob, uint32_t spillover_ncob,
+		   uint32_t cmp_par_efx, uint32_t spillover_efx,
+		   uint32_t cmp_par_ecob, uint32_t spillover_ecob,
+		   uint32_t cmp_par_fx_cob_variance, uint32_t spillover_fx_cob_variance);
 
-int icu_compress_data(struct cmp_cfg *cfg, struct cmp_info *info);
+int cmp_cfg_aux(struct cmp_cfg *cfg,
+		uint32_t cmp_par_mean, uint32_t spillover_mean,
+		uint32_t cmp_par_variance, uint32_t spillover_variance,
+		uint32_t cmp_par_pixels_error, uint32_t spillover_pixels_error);
 
 
-int cmp_pre_process(struct cmp_cfg *cfg);
-int cmp_map_to_pos(struct cmp_cfg *cfg);
-uint32_t cmp_encode_data(struct cmp_cfg *cfg);
+/* start the compression */
+int icu_compress_data(const struct cmp_cfg *cfg);
 
 #endif /* _CMP_ICU_H_ */
diff --git a/include/cmp_io.h b/include/cmp_io.h
index 77dce35b4f571b485267a8fae2ed74b726c38f2b..873bf91652f6c03fa049d9db16b6642eca63640c 100644
--- a/include/cmp_io.h
+++ b/include/cmp_io.h
@@ -17,10 +17,9 @@
 
 #include <string.h>
 
-#include "cmp_support.h"
-#include "cmp_entity.h"
+#include <cmp_support.h>
+#include <cmp_entity.h>
 
-#define PROGRAM_NAME "cmp_tool"
 #define MAX_CONFIG_LINE 256
 
 #define DEFAULT_OUTPUT_PREFIX "OUTPUT"
@@ -32,21 +31,21 @@ void print_help(const char *program_name);
 int read_cmp_cfg(const char *file_name, struct cmp_cfg *cfg, int verbose_en);
 int read_cmp_info(const char *file_name, struct cmp_info *info, int verbose_en);
 
-ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word,
+ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size,
 		   int verbose_en);
-ssize_t read_file16(const char *file_name, uint16_t *buf, uint32_t samples,
-		    int verbose_en);
-ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t samples,
-		    int verbose_en);
+ssize_t read_file_data(const char *file_name, enum cmp_data_type data_type,
+		       void *buf, uint32_t buf_size, int verbose_en);
 ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent,
-			   uint32_t ent_size, int verbose_en);
+			     uint32_t ent_size, int verbose_en);
+ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t buf_size,
+		    int verbose_en);
 
 uint32_t cmp_tool_gen_version_id(const char *version);
 
 int write_cmp_data_file(const void *buf, uint32_t buf_size, const char
 			*output_prefix, const char *name_extension, int verbose);
-int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char
-		    *output_prefix, const char *name_extension, int verbose);
+int write_input_data_to_file(void *data, uint32_t data_size, enum cmp_data_type data_type,
+			     const char *output_prefix, const char *name_extension, int verbose);
 int write_info(const struct cmp_info *info, const char *output_prefix,
 	       int rdcu_cfg);
 int write_cfg(const struct cmp_cfg *cfg, const char *output_prefix, int rdcu_cfg,
@@ -55,3 +54,6 @@ void print_cfg(const struct cmp_cfg *cfg, int rdcu_cfg);
 
 int atoui32(const char *dep_str, const char *val_str, uint32_t *red_val);
 int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode);
+
+enum cmp_data_type string2data_type(const char *data_type_str);
+const char *data_type2string(enum cmp_data_type data_type);
diff --git a/include/cmp_rdcu.h b/include/cmp_rdcu.h
index ee5cffb908fe59d8df033b4d44abbdc20815276b..93da3d06a62f51cac7eee52a4c665d4fdc964b0f 100644
--- a/include/cmp_rdcu.h
+++ b/include/cmp_rdcu.h
@@ -21,23 +21,47 @@
 #ifndef _CMP_RDCU_H_
 #define _CMP_RDCU_H_
 
-#include <stdint.h>
-#include "../include/cmp_support.h"
+#include <cmp_support.h>
 
 
+/* Compression Error Register bits definition, see RDCU-FRS-FN-0952 */
+#define SMALL_BUFFER_ERR_BIT	0x00 /* The length for the compressed data buffer is too small */
+#define CMP_MODE_ERR_BIT	0x01 /* The cmp_mode parameter is not set correctly */
+#define MODEL_VALUE_ERR_BIT	0x02 /* The model_value parameter is not set correctly */
+#define CMP_PAR_ERR_BIT		0x03 /* The spill, golomb_par combination is not set correctly */
+#define AP1_CMP_PAR_ERR_BIT	0x04 /* The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression) */
+#define AP2_CMP_PAR_ERR_BIT	0x05 /* The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression) */
+#define MB_ERR_BIT		0x06 /* Multi bit error detected by the memory controller (only HW compression) */
+#define SLAVE_BUSY_ERR_BIT	0x07 /* The bus master has received the "slave busy" status (only HW compression) */
+
+
+struct cmp_cfg rdcu_cfg_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode,
+			       uint32_t model_value, uint32_t lossy_par);
+int rdcu_cfg_buffers(struct cmp_cfg *cfg, uint16_t *data_to_compress,
+		     uint32_t data_samples, uint16_t *model_of_data,
+		     uint32_t rdcu_data_adr, uint32_t rdcu_model_adr,
+		     uint32_t rdcu_new_model_adr, uint32_t rdcu_buffer_adr,
+		     uint32_t rdcu_buffer_lenght);
+int rdcu_cfg_imagette(struct cmp_cfg *cfg,
+		      uint32_t golomb_par, uint32_t spillover_par,
+		      uint32_t ap1_golomb_par, uint32_t ap1_spillover_par,
+		      uint32_t ap2_golomb_par, uint32_t ap2_spillover_par);
+
 int rdcu_compress_data(const struct cmp_cfg *cfg);
 
 int rdcu_read_cmp_status(struct cmp_status *status);
 
 int rdcu_read_cmp_info(struct cmp_info *info);
 
-int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf);
+int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *compressed_data);
 
-int rdcu_read_model(const struct cmp_info *info, void *model_buf);
+int rdcu_read_model(const struct cmp_info *info, void *updated_model);
 
 int rdcu_interrupt_compression(void);
 
 void rdcu_enable_interrput_signal(void);
 void rdcu_disable_interrput_signal(void);
 
+int rdcu_cmp_cfg_is_invalid(const struct cmp_cfg *cfg);
+
 #endif /* _CMP_RDCU_H_ */
diff --git a/include/cmp_rdcu_extended.h b/include/cmp_rdcu_extended.h
index a4f33e030549419ca1e120bcc4a2a77b2d092532..7ab229b5fd1df7519651916d55f1192cae877788 100644
--- a/include/cmp_rdcu_extended.h
+++ b/include/cmp_rdcu_extended.h
@@ -18,7 +18,7 @@
 #ifndef _CMP_RDCU_EXTENDED_H_
 #define _CMP_RDCU_EXTENDED_H_
 
-#include "../include/cmp_rdcu.h"
+#include <cmp_rdcu.h>
 
 int rdcu_start_compression(void);
 
diff --git a/include/cmp_support.h b/include/cmp_support.h
index 0c1c90f6288c733d6c9db4c51f99b0b5e09d4c26..be598aaff62471c10e5aa595a8c3725e48432a74 100644
--- a/include/cmp_support.h
+++ b/include/cmp_support.h
@@ -23,97 +23,175 @@
 #include <stddef.h>
 
 
-#define GOLOMB_PAR_EXPOSURE_FLAGS 1
-
-/* Compression Error Register bits definition, see RDCU-FRS-FN-0952 */
-#define SMALL_BUFFER_ERR_BIT	0x00 /* The length for the compressed data buffer is too small */
-#define CMP_MODE_ERR_BIT	0x01 /* The cmp_mode parameter is not set correctly */
-#define MODEL_VALUE_ERR_BIT	0x02 /* The model_value parameter is not set correctly */
-#define CMP_PAR_ERR_BIT		0x03 /* The spill, golomb_par combination is not set correctly */
-#define AP1_CMP_PAR_ERR_BIT	0x04 /* The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression) */
-#define AP2_CMP_PAR_ERR_BIT	0x05 /* The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression) */
-#define MB_ERR_BIT		0x06 /* Multi bit error detected by the memory controller (only HW compression) */
-#define SLAVE_BUSY_ERR_BIT	0x07 /* The bus master has received the "slave busy" status (only HW compression) */
-
-#define MODE_RAW 0
-#define MODE_MODEL_ZERO 1
-#define MODE_DIFF_ZERO 2
-#define MODE_MODEL_MULTI 3
-#define MODE_DIFF_MULTI 4
+/* return code if the bitstream buffer is too small to store the whole bitstream */
+#define CMP_ERROR_SMALL_BUF -2
+
+/* return code if the value or the model is bigger than the max_used_bits
+ * parameter allows
+ */
+#define CMP_ERROR_HIGH_VALUE -3
+
+#define CMP_LOSSLESS	0
+#define CMP_PAR_UNUNSED	0
+
 
 #define MAX_MODEL_VALUE                                                        \
-	16UL /* the maximal model values used in the update equation for the new model */
+	16U /* the maximal model values used in the update equation for the new model */
 
-/* valid compression parameter ranges for RDCU compression according to PLATO-UVIE-PL-UM-0001 */
-#define MAX_RDCU_CMP_MODE	4UL
-#define MIN_RDCU_GOLOMB_PAR	1UL
-#define MAX_RDCU_GOLOMB_PAR	63UL
-#define MIN_RDCU_SPILL		2UL
-#define MAX_RDCU_ROUND		2UL
-/* for maximum spill value look at get_max_spill function */
+/* valid compression parameter ranges for RDCU/ICU imagette compression according to PLATO-UVIE-PL-UM-0001 */
+#define MAX_RDCU_CMP_MODE	4U
+#define MIN_IMA_GOLOMB_PAR	1U
+#define MAX_IMA_GOLOMB_PAR	63U
+#define MIN_IMA_SPILL		2U
+#define MAX_RDCU_ROUND		2U
+/* for maximum spill value look at cmp_rdcu_max_spill function */
 
 /* valid compression parameter ranges for ICU compression */
-#define MIN_ICU_GOLOMB_PAR	1UL
-#define MAX_ICU_GOLOMB_PAR	UINT32_MAX
-#define MIN_ICU_SPILL		2UL
-/* for maximum spill value look at get_max_spill function */
-#define MAX_ICU_ROUND		3UL
+#define MIN_ICU_GOLOMB_PAR	1U
+#define MAX_ICU_GOLOMB_PAR	UINT16_MAX /* the compression entity dos not allow larger values */
+#define MIN_ICU_SPILL		2U
+/* for maximum spill value look at cmp_icu_max_spill function */
+#define MAX_ICU_ROUND		3U
+#define MAX_STUFF_CMP_PAR	32U
+
+
+/* default imagette RDCU compression parameters for model compression */
+#define CMP_DEF_IMA_MODEL_DATA_TYPE		DATA_TYPE_IMAGETTE
+#define CMP_DEF_IMA_MODEL_CMP_MODE		CMP_MODE_MODEL_MULTI
+#define CMP_DEF_IMA_MODEL_MODEL_VALUE		8
+#define CMP_DEF_IMA_MODEL_LOSSY_PAR		0
+
+#define CMP_DEF_IMA_MODEL_GOLOMB_PAR		4
+#define CMP_DEF_IMA_MODEL_SPILL_PAR		48
+#define CMP_DEF_IMA_MODEL_AP1_GOLOMB_PAR	3
+#define CMP_DEF_IMA_MODEL_AP1_SPILL_PAR		35
+#define CMP_DEF_IMA_MODEL_AP2_GOLOMB_PAR	5
+#define CMP_DEF_IMA_MODEL_AP2_SPILL_PAR		60
+
+#define CMP_DEF_IMA_MODEL_RDCU_DATA_ADR		0x000000
+#define CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR	0x200000
+#define CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR	0x400000
+#define CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR	0x600000
+
+/* default imagette RDCU compression parameters for 1d-differencing compression */
+#define CMP_DEF_IMA_DIFF_DATA_TYPE		DATA_TYPE_IMAGETTE
+#define CMP_DEF_IMA_DIFF_CMP_MODE		CMP_MODE_DIFF_ZERO
+#define CMP_DEF_IMA_DIFF_MODEL_VALUE		8 /* not needed for 1d-differencing cmp_mode */
+#define CMP_DEF_IMA_DIFF_LOSSY_PAR		0
+
+#define CMP_DEF_IMA_DIFF_GOLOMB_PAR		7
+#define CMP_DEF_IMA_DIFF_SPILL_PAR		60
+#define CMP_DEF_IMA_DIFF_AP1_GOLOMB_PAR		6
+#define CMP_DEF_IMA_DIFF_AP1_SPILL_PAR		48
+#define CMP_DEF_IMA_DIFF_AP2_GOLOMB_PAR		8
+#define CMP_DEF_IMA_DIFF_AP2_SPILL_PAR		72
+
+#define CMP_DEF_IMA_DIFF_RDCU_DATA_ADR		0x000000
+#define CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR		0x000000 /* not needed for 1d-differencing cmp_mode */
+#define CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR	0x000000 /* not needed for 1d-differencing cmp_mode */
+#define CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR	0x600000
+
+enum {ICU_CHECK, RDCU_CHECK}; /* option for the cmp_cfg_imagette_is_invalid() function */
 
-#define SAM2BYT                                                                \
-	2 /* sample to byte conversion factor; one samples has 16 bits (2 bytes) */
 
-#define CMP_GOOD_SPILL_DIFF_MULTI 2 /* good guess for the spill parameter using the MODE_DIFF_MULTI */
+/* defined compression data product types */
+enum cmp_data_type {
+	DATA_TYPE_UNKNOWN,
+	DATA_TYPE_IMAGETTE,
+	DATA_TYPE_IMAGETTE_ADAPTIVE,
+	DATA_TYPE_SAT_IMAGETTE,
+	DATA_TYPE_SAT_IMAGETTE_ADAPTIVE,
+	DATA_TYPE_OFFSET,
+	DATA_TYPE_BACKGROUND,
+	DATA_TYPE_SMEARING,
+	DATA_TYPE_S_FX,
+	DATA_TYPE_S_FX_EFX,
+	DATA_TYPE_S_FX_NCOB,
+	DATA_TYPE_S_FX_EFX_NCOB_ECOB,
+	DATA_TYPE_L_FX,
+	DATA_TYPE_L_FX_EFX,
+	DATA_TYPE_L_FX_NCOB,
+	DATA_TYPE_L_FX_EFX_NCOB_ECOB,
+	DATA_TYPE_F_FX,
+	DATA_TYPE_F_FX_EFX,
+	DATA_TYPE_F_FX_NCOB,
+	DATA_TYPE_F_FX_EFX_NCOB_ECOB,
+	DATA_TYPE_F_CAM_IMAGETTE,
+	DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE,
+	DATA_TYPE_F_CAM_OFFSET,
+	DATA_TYPE_F_CAM_BACKGROUND
+};
+
+
+/* defined compression mode */
+enum cmp_mode {
+	CMP_MODE_RAW,
+	CMP_MODE_MODEL_ZERO,
+	CMP_MODE_DIFF_ZERO,
+	CMP_MODE_MODEL_MULTI,
+	CMP_MODE_DIFF_MULTI,
+	CMP_MODE_STUFF
+};
+
 
 /**
  * @brief The cmp_cfg structure can contain the complete configuration of the HW as
  *      well as the SW compressor.
- * @note when using the 1d-differentiating mode or the raw mode (cmp_error =
- *	0,2,4), the model parameters (model_value, model_buf, rdcu_model_adr,
- *	rdcu_new_model_adr) are ignored
  * @note the icu_output_buf will not be used for HW compression
  * @note the rdcu_***_adr parameters are ignored for SW compression
- * @note semi adaptive compression not supported for SW compression;
- *		configuration parameters ap1\_golomb\_par, ap2\_golomb\_par, ap1\_spill,
- *		ap2\_spill will be ignored;
  */
 
 struct cmp_cfg {
-	uint32_t cmp_mode;          /* 0: raw mode
+	void *input_buf;            /* Pointer to the data to compress buffer */
+	void *model_buf;            /* Pointer to the model buffer */
+	void *icu_new_model_buf;    /* Pointer to the updated model buffer (not used for RDCU compression )*/
+	uint32_t *icu_output_buf;   /* Pointer to the compressed data buffer (not used for RDCU compression) */
+	uint32_t samples;           /* Number of samples to compress, length of the data and model buffer
+				     * (including the multi entity header by non-imagette data)
+				     */
+	uint32_t buffer_length;     /* Length of the compressed data buffer in number of samples */
+	uint32_t rdcu_data_adr;     /* RDCU data to compress start address, the first data address in the RDCU SRAM; HW only */
+	uint32_t rdcu_model_adr;    /* RDCU model start address, the first model address in the RDCU SRAM */
+	uint32_t rdcu_new_model_adr;/* RDCU updated model start address, the address in the RDCU SRAM where the updated model is stored */
+	uint32_t rdcu_buffer_adr;   /* RDCU compressed data start address, the first output data address in the RDCU SRAM */
+	enum cmp_data_type data_type; /* Compression Data Product Types */
+	enum cmp_mode cmp_mode;     /* 0: raw mode
 				     * 1: model mode with zero escape symbol mechanism
 				     * 2: 1d differencing mode without input model with zero escape symbol mechanism
 				     * 3: model mode with multi escape symbol mechanism
 				     * 4: 1d differencing mode without input model multi escape symbol mechanism
 				     */
-	uint32_t golomb_par;        /* Golomb parameter for dictionary selection */
-	uint32_t spill;             /* Spillover threshold for encoding outliers */
 	uint32_t model_value;       /* Model weighting parameter */
-	uint32_t round;             /* Number of noise bits to be rounded */
-	uint32_t ap1_golomb_par;    /* Adaptive 1 spillover threshold; HW only */
-	uint32_t ap1_spill;         /* Adaptive 1 Golomb parameter; HW only */
-	uint32_t ap2_golomb_par;    /* Adaptive 2 spillover threshold; HW only */
+	uint32_t round;             /* lossy compression parameter */
+	uint32_t golomb_par;        /* Golomb parameter for imagette data compression */
+	uint32_t spill;             /* Spillover threshold parameter for imagette compression */
+	uint32_t ap1_golomb_par;    /* Adaptive 1 spillover threshold for imagette data; HW only */
+	uint32_t ap1_spill;         /* Adaptive 1 Golomb parameter for imagette data; HW only */
+	uint32_t ap2_golomb_par;    /* Adaptive 2 spillover threshold for imagette data; HW only */
 	uint32_t ap2_spill;         /* Adaptive 2 Golomb parameter; HW only */
-	void *input_buf;            /* Pointer to the data to compress buffer */
-	uint32_t rdcu_data_adr;     /* RDCU data to compress start address, the first data address in the RDCU SRAM; HW only */
-	void *model_buf;            /* Pointer to the model buffer */
-	uint32_t rdcu_model_adr;    /* RDCU model start address, the first model address in the RDCU SRAM */
-	void *icu_new_model_buf;    /* Pointer to the updated model buffer */
-	uint32_t rdcu_new_model_adr;/* RDCU updated model start address, the address in the RDCU SRAM where the updated model is stored*/
-	uint32_t samples;           /* Number of samples (16 bit value) to compress, length of the data and model buffer */
-	uint32_t *icu_output_buf;   /* Pointer to the compressed data buffer (not used for RDCU compression) */
-	uint32_t rdcu_buffer_adr;   /* RDCU compressed data start address, the first output data address in the RDCU SRAM */
-	uint32_t buffer_length;     /* Length of the compressed data buffer in number of samples (16 bit values)*/
+	uint32_t cmp_par_exp_flags; /* Compression parameter for exposure flags compression */
+	uint32_t spill_exp_flags;   /* Spillover threshold parameter for exposure flags compression */
+	uint32_t cmp_par_fx;	    /* Compression parameter for normal flux compression */
+	uint32_t spill_fx;          /* Spillover threshold parameter for normal flux compression */
+	uint32_t cmp_par_ncob;      /* Compression parameter for normal center of brightness compression */
+	uint32_t spill_ncob;        /* Spillover threshold parameter for normal center of brightness compression */
+	uint32_t cmp_par_efx;       /* Compression parameter for extended flux compression */
+	uint32_t spill_efx;         /* Spillover threshold parameter for extended flux compression */
+	uint32_t cmp_par_ecob;      /* Compression parameter for executed center of brightness compression */
+	uint32_t spill_ecob;        /* Spillover threshold parameter for executed center of brightness compression */
+	uint32_t cmp_par_fx_cob_variance; /* Compression parameter for flux/COB variance compression */
+	uint32_t spill_fx_cob_variance; /* Spillover threshold parameter for flux/COB variance compression */
+	uint32_t cmp_par_mean;      /* Compression parameter for auxiliary science mean compression */
+	uint32_t spill_mean;        /* Spillover threshold parameter for auxiliary science mean compression */
+	uint32_t cmp_par_variance;  /* Compression parameter for auxiliary science variance compression */
+	uint32_t spill_variance;    /* Spillover threshold parameter for auxiliary science variance compression */
+	uint32_t cmp_par_pixels_error; /* Compression parameter for auxiliary science outlier pixels number compression */
+	uint32_t spill_pixels_error; /* Spillover threshold parameter for auxiliary science outlier pixels number compression */
 };
 
 
-extern const struct cmp_cfg DEFAULT_CFG_MODEL;
-
-extern const struct cmp_cfg DEFAULT_CFG_DIFF;
-
-
-/**
- * @brief The cmp_status structure can contain the information of the
- *      compressor status register from the RDCU, see RDCU-FRS-FN-0632,
- *      but can also be used for the SW compression.
+/* The cmp_status structure can contain the information of the compressor status
+ * register from the RDCU, see RDCU-FRS-FN-0632.
  */
 
 struct cmp_status {
@@ -125,18 +203,12 @@ struct cmp_status {
 };
 
 
-/**
- * @brief The cmp_info structure can contain the information and metadata of an
- *      executed compression of the HW as well as the SW compressor.
- *
- * @note if SW compression is used the parameters rdcu_model_adr_used, rdcu_cmp_adr_used,
- *      ap1_cmp_size, ap2_cmp_size are not used and are therefore set to zero
+/* The cmp_info structure can contain the information and metadata of an
+ * executed RDCU compression.
  */
 
 struct cmp_info {
 	uint32_t cmp_mode_used;       /* Compression mode used */
-	uint8_t  model_value_used;    /* Model weighting parameter used */
-	uint8_t  round_used;          /* Number of noise bits to be rounded used */
 	uint32_t spill_used;          /* Spillover threshold used */
 	uint32_t golomb_par_used;     /* Golomb parameter used */
 	uint32_t samples_used;        /* Number of samples (16 bit value) to be stored */
@@ -145,6 +217,8 @@ struct cmp_info {
 	uint32_t ap2_cmp_size;        /* Adaptive compressed data size 2; measured in bits */
 	uint32_t rdcu_new_model_adr_used; /* Updated model start  address used */
 	uint32_t rdcu_cmp_adr_used;   /* Compressed data start address */
+	uint8_t  model_value_used;    /* Model weighting parameter used */
+	uint8_t  round_used;          /* Number of noise bits to be rounded used */
 	uint16_t cmp_err;             /* Compressor errors
 				       * [bit 0] small_buffer_err; The length for the compressed data buffer is too small
 				       * [bit 1] cmp_mode_err; The cmp_mode parameter is not set correctly
@@ -155,32 +229,44 @@ struct cmp_info {
 				       * [bit 6] mb_err; Multi bit error detected by the memory controller (only HW compression)
 				       * [bit 7] slave_busy_err; The bus master has received the "slave busy" status (only HW compression)
 				       * [bit 8] slave_blocked_err; The bus master has received the “slave blocked” status (only HW compression)
-				       * [bit 9] invalid address_err; The bus master has received the “invalid address” status (only HW compression) */
+				       * [bit 9] invalid address_err; The bus master has received the “invalid address” status (only HW compression)
+				       */
 };
 
+
 int is_a_pow_of_2(unsigned int v);
 int ilog_2(uint32_t x);
 
-int model_mode_is_used(unsigned int cmp_mode);
-int diff_mode_is_used(unsigned int cmp_mode);
-int raw_mode_is_used(unsigned int cmp_mode);
-int rdcu_supported_mode_is_used(unsigned int cmp_mode);
-int cmp_mode_available(unsigned int cmp_mode);
+unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit);
 
-int zero_escape_mech_is_used(unsigned int cmp_mode);
-int multi_escape_mech_is_used(unsigned int cmp_mode);
+int cmp_cfg_is_invalid(const struct cmp_cfg *cfg);
+int cmp_cfg_icu_gen_par_is_invalid(const struct cmp_cfg *cfg);
+int cmp_cfg_icu_buffers_is_invalid(const struct cmp_cfg *cfg);
+int cmp_cfg_imagette_is_invalid(const struct cmp_cfg *cfg, int rdcu_check);
+int cmp_cfg_fx_cob_is_invalid(const struct cmp_cfg *cfg);
+int cmp_cfg_aux_is_invalid(const struct cmp_cfg *cfg);
+uint32_t cmp_ima_max_spill(unsigned int golomb_par);
+uint32_t cmp_icu_max_spill(unsigned int cmp_par);
 
-unsigned int round_fwd(unsigned int value, unsigned int round);
-unsigned int round_inv(unsigned int value, unsigned int round);
-unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int
-			  model_value);
+int cmp_data_type_valid(enum cmp_data_type data_type);
+int rdcu_supported_data_type_is_used(enum cmp_data_type data_type);
+int cmp_imagette_data_type_is_used(enum cmp_data_type data_type);
+int cmp_ap_imagette_data_type_is_used(enum cmp_data_type data_type);
+int cmp_fx_cob_data_type_is_used(enum cmp_data_type data_type);
+int cmp_aux_data_type_is_used(enum cmp_data_type data_type);
 
-uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode);
-uint32_t cmp_get_good_spill(unsigned int golomb_par, unsigned int cmp_mode);
+int cmp_mode_is_supported(enum cmp_mode cmp_mode);
+int model_mode_is_used(enum cmp_mode cmp_mode);
+int diff_mode_is_used(enum cmp_mode cmp_mode);
+int raw_mode_is_used(enum cmp_mode cmp_mode);
+int rdcu_supported_cmp_mode_is_used(enum cmp_mode cmp_mode);
+int zero_escape_mech_is_used(enum cmp_mode cmp_mode);
+int multi_escape_mech_is_used(enum cmp_mode cmp_mode);
 
-size_t size_of_a_sample(unsigned int cmp_mode);
-unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit);
-unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode);
+unsigned int round_fwd(unsigned int value, unsigned int round);
+unsigned int round_inv(unsigned int value, unsigned int round);
+unsigned int cmp_up_model(unsigned int data, unsigned int model,
+			  unsigned int model_value, unsigned int round);
 
 
 void print_cmp_cfg(const struct cmp_cfg *cfg);
diff --git a/include/decmp.h b/include/decmp.h
index 139273f1f0bd27c838a0c9f1f6b2b6a93d43550a..826eb89804f8d5388e9aee8a77b05f405da6ae7c 100644
--- a/include/decmp.h
+++ b/include/decmp.h
@@ -19,13 +19,14 @@
 #ifndef DECMP_H_
 #define DECMP_H_
 
-#include "../include/cmp_support.h"
+#include <cmp_entity.h>
+#include <cmp_support.h>
 
-void *malloc_decompressed_data(const struct cmp_info *info);
+int decompress_cmp_entiy(struct cmp_entity *ent, void *model_of_data,
+			 void *up_model_buf, void *decompressed_data);
 
-int decompress_data(const void *compressed_data, void *de_model_buf,
-		    const struct cmp_info *info, void *decompressed_data);
-
-double get_compression_ratio(const struct cmp_info *info);
+int decompress_rdcu_data(uint32_t *compressed_data, const struct cmp_info *info,
+			 uint16_t *model_of_data, uint16_t *up_model_buf,
+			 uint16_t *decompressed_data);
 
 #endif /* DECMP_H_ */
diff --git a/include/meson.build b/include/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..491eef5ecebc527e3df0fb677d7e81907bcb9895
--- /dev/null
+++ b/include/meson.build
@@ -0,0 +1,13 @@
+# generate the configuration file
+cdata = configuration_data()
+cdata.set_quoted('PROGRAM_NAME', 'cmp_tool')
+cdata.set_quoted('CMP_TOOL_VERSION', meson.project_version())
+if get_option('argument_input_mode')
+  cdata.set('ARGUMENT_INPUT_MODE', '')
+endif
+
+configure_file(
+  output : 'cmp_tool-config.h',
+  configuration : cdata)
+
+incdir = include_directories('.')
diff --git a/include/rdcu_ctrl.h b/include/rdcu_ctrl.h
index ec5b9a2c919621c318fc3550a4a444c2155f63a8..ac3f03f9b0788e3f63977b017beaf946c803378c 100644
--- a/include/rdcu_ctrl.h
+++ b/include/rdcu_ctrl.h
@@ -245,11 +245,14 @@ uint32_t rdcu_get_golomb_param(void);
 
 uint32_t rdcu_get_compr_data_start_addr(void);
 
-uint32_t rdcu_get_compr_data_size(void);
+uint32_t rdcu_get_compr_data_size_bit(void);
+uint32_t rdcu_get_compr_data_size_byte(void);
 
-uint32_t rdcu_get_compr_data_adaptive_1_size(void);
+uint32_t rdcu_get_compr_data_adaptive_1_size_bit(void);
+uint32_t rdcu_get_compr_data_adaptive_1_size_byte(void);
 
-uint32_t rdcu_get_compr_data_adaptive_2_size(void);
+uint32_t rdcu_get_compr_data_adaptive_2_size_bit(void);
+uint32_t rdcu_get_compr_data_adaptive_2_size_byte(void);
 
 uint16_t rdcu_get_compr_error(void);
 
diff --git a/include/rdcu_pkt_to_file.h b/include/rdcu_pkt_to_file.h
index 87c3d4b72fbf0189e2fb5ee193eca092ffcfb8b9..b0f055880bcfbe25ccdc76aa0eb5c29507553516 100644
--- a/include/rdcu_pkt_to_file.h
+++ b/include/rdcu_pkt_to_file.h
@@ -18,7 +18,7 @@
 #ifndef _RDCU_PKT_TO_FILE_H_
 #define _RDCU_PKT_TO_FILE_H_
 
-#include "cmp_support.h"
+#include <cmp_support.h>
 
 /* directory where the tc files are stored, when --rdcu_pkt option is set */
 #define TC_DIR "TC_FILES"
@@ -27,6 +27,11 @@
 
 #define MAX_TC_FOLDER_DIR_LEN 256
 
+/* default values when no .rdcu_pkt_mode_cfg file is available */
+#define DEF_ICU_ADDR 0xA7
+#define DEF_RDCU_ADDR 0xFE
+#define DEF_MTU 4224
+
 int init_rmap_pkt_to_file(void);
 
 void set_tc_folder_dir(const char *dir_name);
diff --git a/include/rmap.h b/include/rmap.h
index 5156679c0c37bd7c805eec3fb9fa0e3eb82dbb6e..c5815750e7f5e99eb219ea0efe391ce0e92fd1a0 100644
--- a/include/rmap.h
+++ b/include/rmap.h
@@ -20,6 +20,7 @@
 #define RMAP_H
 
 #include <stdint.h>
+#include <compiler.h>
 
 /**
  * valid RMAP command codes, see Table 5-1 of ECSS‐E‐ST‐50‐52C
@@ -149,11 +150,9 @@ struct rmap_instruction {
 #else
 #error "Unknown byte order"
 #endif
-}__attribute__((packed));
-#if 0
-compile_time_assert((sizeof(struct rmap_instruction) == sizeof(uint8_t),
-		    RMAP_INSTRUCTION_STRUCT_WRONG_SIZE));
-#endif
+} __attribute__((packed));
+
+compile_time_assert(sizeof(struct rmap_instruction) == sizeof(uint8_t), RMAP_INSTRUCTION_STRUCT_WRONG_SIZE);
 
 
 /**
diff --git a/lib/cmp_data_types.c b/lib/cmp_data_types.c
index 1df363cb274aa698815432ef3e9ed51557c88d5b..ed7d5e678f6393e9e55a35abd34d911c6453fd51 100644
--- a/lib/cmp_data_types.c
+++ b/lib/cmp_data_types.c
@@ -17,624 +17,527 @@
  */
 
 
-#include "../include/cmp_data_types.h"
-#include "../include/cmp_support.h"
-#include "../include/cmp_debug.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <limits.h>
+
+
+#include <cmp_data_types.h>
+#include <cmp_debug.h>
+#include <byteorder.h>
+
+
+/* the maximum length of the different data products types in bits */
+struct cmp_max_used_bits max_used_bits = {
+	0, /* default version */
+	MAX_USED_S_FX_EXPOSURE_FLAGS_BITS, /* s_fx_exp_flags */
+	MAX_USED_S_FX_BITS, /* s_fx */
+	MAX_USED_S_EFX_BITS, /* s_efx */
+	MAX_USED_S_NCOB_BITS, /* s_ncob_x and s_ncob_y */
+	MAX_USED_S_ECOB_BITS, /* s_ecob_x and s_ncob_y */
+	MAX_USED_F_FX_BITS, /* f_fx */
+	MAX_USED_F_EFX_BITS, /* f_efx */
+	MAX_USED_F_NCOB_BITS, /* f_ncob_x and f_ncob_y */
+	MAX_USED_F_ECOB_BITS, /* f_ecob_x and f_ncob_y */
+	MAX_USED_L_FX_EXPOSURE_FLAGS_BITS, /* l_fx_exp_flags */
+	MAX_USED_L_FX_BITS, /* l_fx */
+	MAX_USED_L_FX_VARIANCE_BITS, /* l_fx_variance */
+	MAX_USED_L_EFX_BITS, /* l_efx */
+	MAX_USED_L_NCOB_BITS, /* l_ncob_x and l_ncob_y */
+	MAX_USED_L_ECOB_BITS, /* l_ecob_x and l_ncob_y */
+	MAX_USED_L_COB_VARIANCE_BITS, /* l_cob_x_variance and l_cob_y_variance */
+	MAX_USED_NC_IMAGETTE_BITS, /* nc_imagette */
+	MAX_USED_SATURATED_IMAGETTE_BITS, /* saturated_imagette */
+	MAX_USED_NC_OFFSET_MEAN_BITS, /* nc_offset_mean */
+	MAX_USED_NC_OFFSET_VARIANCE_BITS, /* nc_offset_variance */
+	MAX_USED_NC_BACKGROUND_MEAN_BITS, /* nc_background_mean */
+	MAX_USED_NC_BACKGROUND_VARIANCE_BITS, /* nc_background_variance */
+	MAX_USED_NC_BACKGROUND_OUTLIER_PIXELS_BITS, /* nc_background_outlier_pixels */
+	MAX_USED_SMEARING_MEAN_BITS, /* smearing_mean */
+	MAX_USED_SMEARING_VARIANCE_MEAN_BITS, /* smearing_variance_mean */
+	MAX_USED_SMEARING_OUTLIER_PIXELS_BITS, /* smearing_outlier_pixels */
+	MAX_USED_FC_IMAGETTE_BITS, /* fc_imagette */
+	MAX_USED_FC_OFFSET_MEAN_BITS, /* fc_offset_mean */
+	MAX_USED_FC_OFFSET_VARIANCE_BITS, /* fc_offset_variance */
+	MAX_USED_FC_OFFSET_PIXEL_IN_ERROR_BITS, /* fc_offset_pixel_in_error */
+	MAX_USED_FC_BACKGROUND_MEAN_BITS, /* fc_background_mean */
+	MAX_USED_FC_BACKGROUND_VARIANCE_BITS, /* fc_background_variance */
+	MAX_USED_FC_BACKGROUND_OUTLIER_PIXELS_BITS /* fc_background_outlier_pixels */
+};
 
 
 /**
- * @brief rounding down the least significant digits of a uint16_t data buffer
+ * @brief sets the maximum length of the different data products types
  *
- * @note this step involves data loss (if round > 0)
- * @note change the data buffer in-place
- *
- * @param  data_buf	uint16_t formatted data buffer
- * @param  samples	the size of the data buffer measured in uint16_t samples
- * @param  round	number of bits to round; if zero no rounding takes place
- *
- * @returns 0 on success, error otherwise
+ * @param set_max_used_bits	pointer to a structure with the maximum length
+ *				of the different data products types in bits
  */
 
-int lossy_rounding_16(uint16_t *data_buf, unsigned int samples, unsigned int
-		      round)
+void cmp_set_max_used_bits(const struct cmp_max_used_bits *set_max_used_bits)
 {
-	size_t i;
-
-	if (!samples)
-		return 0;
-
-	if (!data_buf)
-		return -1;
+	if (set_max_used_bits)
+		max_used_bits = *set_max_used_bits;
+}
 
-	/* round 0 means loss less compression, no further processing is
-	 * necessary */
-	if (round == 0)
-		return 0;
 
-	for (i = 0; i < samples; i++)
-		data_buf[i] = round_fwd(data_buf[i], round);  /* this is the lossy step */
+/**
+ * @brief get the maximum length of the different data products types
+ *
+ * @returns a structure with the used maximum length of the different data
+ *	products types in bits
+ */
 
-	return 0;
+struct cmp_max_used_bits cmp_get_max_used_bits(void)
+{
+	return max_used_bits;
 }
 
 
 /**
- * @brief rounding back the least significant digits of the data buffer
- *
- * @param data_buf	pointer to the data to process
- * @param samples_used	the size of the data and model buffer in 16 bit units
- * @param round_used	used number of bits to round; if zero no rounding takes place
+ * @brief get the version record form the max used bits registry
  *
- * @returns 0 on success, error otherwise
+ * @returns version of the max used bits registry
  */
 
-int de_lossy_rounding_16(uint16_t *data_buf, uint32_t samples_used, uint32_t
-			 round_used)
+uint8_t cmp_get_max_used_bits_version(void)
 {
-	size_t i;
-
-	if (!samples_used)
-		return 0;
+	return max_used_bits.version;
+}
 
-	if (!data_buf)
-		return -1;
 
-	/* round 0 means loss less compression, no further processing is necessary */
-	if (round_used == 0)
-		return 0;
+/**
+ * @brief calculate the size of a sample for the different compression data type
+ *
+ * @param data_type	compression data_type
+ *
+ * @returns the size of a data sample in bytes for the selected compression
+ *	data type; zero on unknown data type
+ */
 
-	for (i = 0; i < samples_used; i++) {
-		/* check if data are not to big for a overflow */
-		uint16_t mask = (uint16_t)(~0U << (16-round_used));
-		if (data_buf[i] & mask) {
-			debug_print("de_lossy_rounding_16 failed!\n");
-			return -1;
-		}
-		data_buf[i] = round_inv(data_buf[i], round_used);
+size_t size_of_a_sample(enum cmp_data_type data_type)
+{
+	size_t sample_size = 0;
+
+	switch (data_type) {
+	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+		sample_size = sizeof(uint16_t);
+		break;
+	case DATA_TYPE_OFFSET:
+		sample_size = sizeof(struct nc_offset);
+		break;
+	case DATA_TYPE_BACKGROUND:
+		sample_size = sizeof(struct nc_background);
+		break;
+	case DATA_TYPE_SMEARING:
+		sample_size = sizeof(struct smearing);
+		break;
+	case DATA_TYPE_S_FX:
+		sample_size = sizeof(struct s_fx);
+		break;
+	case DATA_TYPE_S_FX_EFX:
+		sample_size = sizeof(struct s_fx_efx);
+		break;
+	case DATA_TYPE_S_FX_NCOB:
+		sample_size = sizeof(struct s_fx_ncob);
+		break;
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+		sample_size = sizeof(struct s_fx_efx_ncob_ecob);
+		break;
+	case DATA_TYPE_L_FX:
+		sample_size = sizeof(struct l_fx);
+		break;
+	case DATA_TYPE_L_FX_EFX:
+		sample_size = sizeof(struct l_fx_efx);
+		break;
+	case DATA_TYPE_L_FX_NCOB:
+		sample_size = sizeof(struct l_fx_ncob);
+		break;
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+		sample_size = sizeof(struct l_fx_efx_ncob_ecob);
+		break;
+	case DATA_TYPE_F_FX:
+		sample_size = sizeof(struct f_fx);
+		break;
+	case DATA_TYPE_F_FX_EFX:
+		sample_size = sizeof(struct f_fx_efx);
+		break;
+	case DATA_TYPE_F_FX_NCOB:
+		sample_size = sizeof(struct f_fx_ncob);
+		break;
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		sample_size = sizeof(struct f_fx_efx_ncob_ecob);
+		break;
+	case DATA_TYPE_F_CAM_OFFSET:
+	case DATA_TYPE_F_CAM_BACKGROUND:
+	case DATA_TYPE_UNKNOWN:
+	default:
+		debug_print("Error: Compression data type is not supported.\n");
+		break;
 	}
-	return 0;
+	return sample_size;
 }
 
 
 /**
- * @brief rounding down the least significant digits of a uint32_t data buffer
+ * @brief calculate the need bytes for the data
  *
- * @note this step involves data loss (if round > 0)
- * @note change the data buffer in-place
+ * @param samples	number of data samples
+ * @param data_type	compression data_type
  *
- * @param  data_buf	a uint32_t formatted data buffer
- * @param  samples	the size of the data buffer measured in uint16_t samples
- * @param  round	number of bits to round; if zero no rounding takes place
+ * @note for non-imagette data program types the multi entry header size is added
  *
- * @returns 0 on success, error otherwise
+ * @returns the size in bytes to store the data sample; zero on failure
  */
 
-int lossy_rounding_32(uint32_t *data_buf, unsigned int samples, unsigned int
-		      round)
+unsigned int cmp_cal_size_of_data(unsigned int samples, enum cmp_data_type data_type)
 {
-	size_t i;
+	size_t s = size_of_a_sample(data_type);
+	uint64_t x; /* use 64 bit to catch overflow */
 
-	if (!samples)
+	if (!s)
 		return 0;
 
-	if (!data_buf)
-		return -1;
+	x = (uint64_t)s*samples;
 
-	/* round 0 means loss less compression, no further processing is
-	 * necessary */
-	if (round == 0)
-		return 0;
-
-	for (i = 0; i < samples; i++)
-		data_buf[i] = round_fwd(data_buf[i], round);  /* this is the lossy step */
-
-	return 0;
-}
+	if (!rdcu_supported_data_type_is_used(data_type))
+		x += MULTI_ENTRY_HDR_SIZE;
 
-
-int de_lossy_rounding_32(uint32_t *data_buf, uint32_t samples_used, uint32_t
-			 round_used)
-{
-	size_t i;
-
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
-		return -1;
-
-	/* round 0 means loss less compression, no further processing is necessary */
-	if (round_used == 0)
+	if (x > UINT_MAX) /* catch overflow */
 		return 0;
 
-	for (i = 0; i < samples_used; i++) {
-		/* check if data are not to big for a overflow */
-		uint32_t mask = (uint32_t)(~0U << (32-round_used));
-		if (data_buf[i] & mask) {
-			debug_print("de_lossy_rounding_32 failed!\n");
-			return -1;
-		}
-		data_buf[i] = round_inv(data_buf[i], round_used);
-	}
-	return 0;
-}
-
-
-struct S_FX sub_S_FX(struct S_FX a, struct S_FX b)
-{
-	struct S_FX result;
-
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS;
-	result.FX = a.FX - b.FX;
-
-	return result;
-}
-
-
-struct S_FX add_S_FX(struct S_FX a, struct S_FX b)
-{
-	struct S_FX result;
-
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS;
-	result.FX = a.FX + b.FX;
-
-	return result;
+	return (unsigned int)x;
 }
 
 
 /**
- * @brief rounding down the least significant digits of a S_FX data buffer
- *
- * @note this step involves data loss (if round > 0)
- * @note change the data buffer in-place
- * @note the exposure_flags are not rounded
+ * @brief calculates the number of samples for a given data size for the
+ *	different compression modes
  *
- * @param  data_buf	a S_FX formatted data buffer
- * @param  samples	the size of the data buffer measured in S_FX samples
- * @param  round	number of bits to round; if zero no rounding takes place
+ * @param size		size of the data in bytes
+ * @param data_type	compression data type
  *
- * @returns 0 on success, error otherwise
+ * @returns the number samples for the given compression mode; negative on error
  */
 
-int lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples, unsigned
-			int round)
+int cmp_input_size_to_samples(unsigned int size, enum cmp_data_type data_type)
 {
-	size_t i;
+	uint32_t samples_size = size_of_a_sample(data_type);
 
-	if (!samples)
-		return 0;
-
-	if (!data_buf)
+	if (!samples_size)
 		return -1;
 
-	/* round 0 means loss less compression, no further processing is
-	 * necessary */
-	if (round == 0)
-		return 0;
+	if (!rdcu_supported_data_type_is_used(data_type)) {
+		if (size < MULTI_ENTRY_HDR_SIZE)
+			return -1;
+		size -= MULTI_ENTRY_HDR_SIZE;
+	}
 
-	for (i = 0; i < samples; i++)
-		data_buf[i].FX = round_fwd(data_buf[i].FX, round);
+	if (size % samples_size)
+		return -1;
 
-	return 0;
+	return (int)(size/samples_size);
 }
 
 
-int de_lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples_used,
-			   unsigned int round_used)
+static uint32_t be24_to_cpu(uint32_t a)
 {
-	size_t i;
+	return be32_to_cpu(a) >> 8;
+}
 
-	if (!samples_used)
-		return 0;
 
-	if (!data_buf)
-		return -1;
+static void be_to_cpus_16(uint16_t *a, int samples)
+{
+	int i;
 
-	if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */
-		return 0;
+	for (i = 0; i < samples; ++i)
+		be16_to_cpus(&a[i]);
+}
 
-	for (i = 0; i < samples_used; i++) {
-		uint32_t mask = (~0U << (32-round_used));
 
-		if (data_buf[i].FX & mask) {
-			debug_print("Errolr: de_lossy_rounding_S_FX failed\n");
-			return -1;
-		}
+static void be_to_cpus_nc_offset(struct nc_offset *a, int samples)
+{
+	int i;
 
-		data_buf[i].FX = round_inv(data_buf[i].FX, round_used);
+	for (i = 0; i < samples; ++i) {
+		a[i].mean = be32_to_cpu(a[i].mean);
+		a[i].variance = be32_to_cpu(a[i].variance);
 	}
-	return 0;
 }
 
 
-struct S_FX cal_up_model_S_FX(struct S_FX data_buf, struct S_FX model_buf,
-			      unsigned int model_value)
+static void be_to_cpus_nc_background(struct nc_background *a, int samples)
 {
-	struct S_FX result;
-
-	result.EXPOSURE_FLAGS = (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS,
-						      model_buf.EXPOSURE_FLAGS,
-						      model_value);
-	result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value);
+	int i;
 
-	return result;
+	for (i = 0; i < samples; ++i) {
+		a[i].mean = be32_to_cpu(a[i].mean);
+		a[i].variance = be32_to_cpu(a[i].variance);
+		a[i].outlier_pixels = be16_to_cpu(a[i].outlier_pixels);
+	}
 }
 
 
-struct S_FX_EFX sub_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b)
+static void be_to_cpus_smearing(struct smearing *a, int samples)
 {
-	struct S_FX_EFX result;
-
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS;
-	result.FX = a.FX - b.FX;
-	result.EFX = a.EFX - b.EFX;
+	int i;
 
-	return result;
+	for (i = 0; i < samples; ++i) {
+		a[i].mean = be32_to_cpu(a[i].mean);
+		a[i].variance_mean = be16_to_cpu(a[i].variance_mean);
+		a[i].outlier_pixels = be16_to_cpu(a[i].outlier_pixels);
+	}
 }
 
 
-struct S_FX_EFX add_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b)
+static void be_to_cpus_s_fx(struct s_fx *a, int samples)
 {
-	struct S_FX_EFX result;
-
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS;
-	result.FX = a.FX + b.FX;
-	result.EFX = a.EFX + b.EFX;
+	int i;
 
-	return result;
+	for (i = 0; i < samples; ++i)
+		a[i].fx = be32_to_cpu(a[i].fx);
 }
 
 
-/**
- * @brief rounding down the least significant digits of a S_FX_EFX data buffer
- *
- * @note this step involves data loss (if round > 0)
- * @note change the data buffer in-place
- * @note the exposure_flags are not rounded
- *
- * @param  data		S_FX_EFX formatted data buffer
- * @param  samples	the size of the data buffer measured in S_FX_EFX samples
- * @param  round	number of bits to round; if zero no rounding takes place
- *
- * @returns 0 on success, error otherwise
- */
-
-int lossy_rounding_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples,
-			    unsigned int round)
+static void be_to_cpus_s_fx_efx(struct s_fx_efx *a, int samples)
 {
-	size_t i;
-
-	if (!samples)
-		return 0;
+	int i;
 
-	if (!data)
-		return -1;
-
-	/* round 0 means loss less compression, no further processing is
-	 * necessary */
-	if (round == 0)
-		return 0;
-
-	for (i = 0; i < samples; i++) {
-		data[i].FX = round_fwd(data[i].FX, round);
-		data[i].EFX = round_fwd(data[i].EFX, round);
+	for (i = 0; i < samples; ++i) {
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].efx = be32_to_cpu(a[i].efx);
 	}
-	return 0;
 }
 
 
-int de_lossy_rounding_S_FX_EFX(struct S_FX_EFX *data_buf, unsigned int
-			       samples_used, unsigned int round_used)
+static void be_to_cpus_s_fx_ncob(struct s_fx_ncob *a, int samples)
 {
-	size_t i;
-
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
-		return -1;
-
-	if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */
-		return 0;
+	int i;
 
-	for (i = 0; i < samples_used; i++) {
-		uint32_t mask = (~0U << (32-round_used));
-
-		if (data_buf[i].FX & mask) {
-			debug_print("de_lossy_rounding_S_FX failed!\n");
-			return -1;
-		}
-		if (data_buf[i].EFX & mask) {
-			debug_print("de_lossy_rounding_S_FX failed!\n");
-			return -1;
-		}
-
-		data_buf[i].FX = round_inv(data_buf[i].FX, round_used);
-		data_buf[i].EFX = round_inv(data_buf[i].EFX, round_used);
+	for (i = 0; i < samples; ++i) {
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].ncob_x = be32_to_cpu(a[i].ncob_x);
+		a[i].ncob_y = be32_to_cpu(a[i].ncob_y);
 	}
-	return 0;
 }
 
 
-struct S_FX_EFX cal_up_model_S_FX_EFX(struct S_FX_EFX data_buf, struct S_FX_EFX
-				      model_buf, unsigned int model_value)
+static void be_to_cpus_s_fx_efx_ncob_ecob(struct s_fx_efx_ncob_ecob *a, int samples)
 {
-	struct S_FX_EFX result;
-
-	result.EXPOSURE_FLAGS =
-		(uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS,
-				      model_buf.EXPOSURE_FLAGS, model_value);
-	result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value);
-	result.EFX = cal_up_model(data_buf.EFX, model_buf.FX, model_value);
-
-	return result;
+	int i;
+
+	for (i = 0; i < samples; ++i) {
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].ncob_x = be32_to_cpu(a[i].ncob_x);
+		a[i].ncob_y = be32_to_cpu(a[i].ncob_y);
+		a[i].efx = be32_to_cpu(a[i].efx);
+		a[i].ecob_x = be32_to_cpu(a[i].ecob_x);
+		a[i].ecob_y = be32_to_cpu(a[i].ecob_y);
+	}
 }
 
 
-struct S_FX_NCOB sub_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b)
+static void be_to_cpus_l_fx(struct l_fx *a, int samples)
 {
-	struct S_FX_NCOB result;
+	int i;
 
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS;
-	result.FX = a.FX - b.FX;
-	result.NCOB_X = a.NCOB_X - b.NCOB_X;
-	result.NCOB_Y = a.NCOB_Y - b.NCOB_Y;
-
-	return result;
+	for (i = 0; i < samples; ++i) {
+		a[i].exp_flags = be24_to_cpu(a[i].exp_flags);
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].fx_variance = be32_to_cpu(a[i].fx_variance);
+	}
 }
 
 
-struct S_FX_NCOB add_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b)
+static void be_to_cpus_l_fx_efx(struct l_fx_efx *a, int samples)
 {
-	struct S_FX_NCOB result;
+	int i;
 
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS;
-	result.FX = a.FX + b.FX;
-	result.NCOB_X = a.NCOB_X + b.NCOB_X;
-	result.NCOB_Y = a.NCOB_Y + b.NCOB_Y;
-
-	return result;
+	for (i = 0; i < samples; ++i) {
+		a[i].exp_flags = be24_to_cpu(a[i].exp_flags);
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].efx = be32_to_cpu(a[i].efx);
+		a[i].fx_variance = be32_to_cpu(a[i].fx_variance);
+	}
 }
 
 
-/**
- * @brief rounding down the least significant digits of a S_FX_NCOB data buffer
- *
- * @note this step involves data loss (if round > 0)
- * @note change the data buffer in-place
- * @note the exposure_flags are not rounded
- *
- * @param  data_buf	a S_FX_NCOB formatted data buffer
- * @param  samples	the size of the data buffer measured in S_FX_NCOB samples
- * @param  round		number of bits to round; if zero no rounding takes place
- *
- * @returns 0 on success, error otherwise
- */
-
-int lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int samples,
-			     unsigned int round)
+static void be_to_cpus_l_fx_ncob(struct l_fx_ncob *a, int samples)
 {
-	size_t i;
-
-	if (!samples)
-		return 0;
-
-	if (!data_buf)
-		return -1;
-
-	/* round 0 means loss less compression, no further processing is
-	 * necessary */
-	if (round == 0)
-		return 0;
-
-	for (i = 0; i < samples; i++) {
-		data_buf[i].FX = round_fwd(data_buf[i].FX, round);
-		data_buf[i].NCOB_X = round_fwd(data_buf[i].NCOB_X, round);
-		data_buf[i].NCOB_Y = round_fwd(data_buf[i].NCOB_Y, round);
+	int i;
+
+	for (i = 0; i < samples; ++i) {
+		a[i].exp_flags = be24_to_cpu(a[i].exp_flags);
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].ncob_x = be32_to_cpu(a[i].ncob_x);
+		a[i].ncob_y = be32_to_cpu(a[i].ncob_y);
+		a[i].fx_variance = be32_to_cpu(a[i].fx_variance);
+		a[i].cob_x_variance = be32_to_cpu(a[i].cob_x_variance);
+		a[i].cob_y_variance = be32_to_cpu(a[i].cob_y_variance);
 	}
-	return 0;
 }
 
 
-int de_lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int
-				samples_used, unsigned int round_used)
+static void be_to_cpus_l_fx_efx_ncob_ecob(struct l_fx_efx_ncob_ecob *a, int samples)
 {
-	size_t i;
-
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
-		return -1;
-
-	if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */
-		return 0;
-
-	for (i = 0; i < samples_used; i++) {
-		uint32_t mask = (~0U << (32-round_used));
-
-		if (data_buf[i].FX & mask) {
-			debug_print("de_lossy_rounding_S_FX_NCOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].NCOB_X & mask) {
-			debug_print("de_lossy_rounding_S_FX_NCOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].NCOB_Y & mask) {
-			debug_print("de_lossy_rounding_S_FX_NCOB failed!\n");
-			return -1;
-		}
-
-		data_buf[i].FX = round_inv(data_buf[i].FX, round_used);
-		data_buf[i].NCOB_X = round_inv(data_buf[i].NCOB_X, round_used);
-		data_buf[i].NCOB_Y = round_inv(data_buf[i].NCOB_Y, round_used);
+	int i;
+
+	for (i = 0; i < samples; ++i) {
+		a[i].exp_flags = be24_to_cpu(a[i].exp_flags);
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].ncob_x = be32_to_cpu(a[i].ncob_x);
+		a[i].ncob_y = be32_to_cpu(a[i].ncob_y);
+		a[i].efx = be32_to_cpu(a[i].efx);
+		a[i].ecob_x = be32_to_cpu(a[i].ecob_x);
+		a[i].ecob_y = be32_to_cpu(a[i].ecob_y);
+		a[i].fx_variance = be32_to_cpu(a[i].fx_variance);
+		a[i].cob_x_variance = be32_to_cpu(a[i].cob_x_variance);
+		a[i].cob_y_variance = be32_to_cpu(a[i].cob_y_variance);
 	}
-	return 0;
 }
 
 
-struct S_FX_NCOB cal_up_model_S_FX_NCOB(struct S_FX_NCOB data_buf, struct S_FX_NCOB
-					model_buf, unsigned int model_value)
+static void be_to_cpus_f_fx(struct f_fx *a, int samples)
 {
-	struct S_FX_NCOB result;
-
-	result.EXPOSURE_FLAGS =
-		(uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS,
-				      model_buf.EXPOSURE_FLAGS, model_value);
-	result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value);
-	result.NCOB_X = cal_up_model(data_buf.NCOB_X, model_buf.NCOB_X, model_value);
-	result.NCOB_Y = cal_up_model(data_buf.NCOB_Y, model_buf.NCOB_Y, model_value);
+	int i;
 
-	return result;
+	for (i = 0; i < samples; ++i)
+		a[i].fx = be32_to_cpu(a[i].fx);
 }
 
 
-struct S_FX_EFX_NCOB_ECOB sub_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a,
-						 struct S_FX_EFX_NCOB_ECOB b)
+static void be_to_cpus_f_fx_efx(struct f_fx_efx *a, int samples)
 {
-	struct S_FX_EFX_NCOB_ECOB result;
+	int i;
 
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS;
-	result.FX = a.FX - b.FX;
-	result.NCOB_X = a.NCOB_X - b.NCOB_X;
-	result.NCOB_Y = a.NCOB_Y - b.NCOB_Y;
-	result.EFX = a.EFX - b.EFX;
-	result.ECOB_X = a.ECOB_X - b.ECOB_X;
-	result.ECOB_Y = a.ECOB_Y - b.ECOB_Y;
-
-	return result;
+	for (i = 0; i < samples; ++i) {
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].efx = be32_to_cpu(a[i].efx);
+	}
 }
 
 
-struct S_FX_EFX_NCOB_ECOB add_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a,
-						 struct S_FX_EFX_NCOB_ECOB b)
+static void be_to_cpus_f_fx_ncob(struct f_fx_ncob *a, int samples)
 {
-	struct S_FX_EFX_NCOB_ECOB result;
+	int i;
+
+	for (i = 0; i < samples; ++i) {
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].ncob_x = be32_to_cpu(a[i].ncob_x);
+		a[i].ncob_y = be32_to_cpu(a[i].ncob_y);
+	}
+}
 
-	result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS;
-	result.FX = a.FX + b.FX;
-	result.NCOB_X = a.NCOB_X + b.NCOB_X;
-	result.NCOB_Y = a.NCOB_Y + b.NCOB_Y;
-	result.EFX = a.EFX + b.EFX;
-	result.ECOB_X = a.ECOB_X + b.ECOB_X;
-	result.ECOB_Y = a.ECOB_Y + b.ECOB_Y;
 
-	return result;
+static void be_to_cpus_f_fx_efx_ncob_ecob(struct f_fx_efx_ncob_ecob *a, int samples)
+{
+	int i;
+
+	for (i = 0; i < samples; ++i) {
+		a[i].fx = be32_to_cpu(a[i].fx);
+		a[i].ncob_x = be32_to_cpu(a[i].ncob_x);
+		a[i].ncob_y = be32_to_cpu(a[i].ncob_y);
+		a[i].efx = be32_to_cpu(a[i].efx);
+		a[i].ecob_x = be32_to_cpu(a[i].ecob_x);
+		a[i].ecob_y = be32_to_cpu(a[i].ecob_y);
+	}
 }
 
 
 /**
- * @brief rounding down the least significant digits of a S_FX_EFX_NCOB_ECOB data
- *	buffer
+ * @brief swap the endianness of uncompressed data form big endian to the cpu
+ *	endianness (or the other way around) in place
  *
- * @note this step involves data loss (if round > 0)
- * @note change the data buffer in-place
- * @note the exposure_flags are not rounded
+ * @param data			pointer to a data sample
+ * @param data_size_byte	size of the data in bytes
+ * @param data_type		compression data type
  *
- * @param  data_buf	a S_FX_EFX_NCOB_ECOB formatted data buffer
- * @param  samples	the size of the data buffer measured in
- *	S_FX_EFX_NCOB_ECOB samples
- * @param  round		number of bits to round; if zero no rounding takes place
- *
- * @returns 0 on success, error otherwise
+ * @returns 0 on success; non-zero on failure
  */
 
-int lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-				      unsigned int samples, unsigned int round)
+int cmp_input_big_to_cpu_endianness(void *data, uint32_t data_size_byte,
+				    enum cmp_data_type data_type)
 {
-	size_t i;
+	int samples = cmp_input_size_to_samples(data_size_byte, data_type);
 
-	if (!samples)
+	if (!data) /* nothing to do */
 		return 0;
 
-	if (!data_buf)
+	if (samples < 0) {
+		debug_print("Error: Can not convert data size in samples.\n");
 		return -1;
-
-	if (round == 0) /* round 0 means loss less compression, no further processing is necessary */
-		return 0;
-
-	for (i = 0; i < samples; i++) {
-		data_buf[i].FX = round_fwd(data_buf[i].FX, round);
-		data_buf[i].NCOB_X = round_fwd(data_buf[i].NCOB_X, round);
-		data_buf[i].NCOB_Y = round_fwd(data_buf[i].NCOB_Y, round);
-		data_buf[i].EFX = round_fwd(data_buf[i].EFX, round);
-		data_buf[i].ECOB_X = round_fwd(data_buf[i].ECOB_X, round);
-		data_buf[i].ECOB_Y = round_fwd(data_buf[i].ECOB_Y, round);
 	}
-	return 0;
-}
-
-
-int de_lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-					 unsigned int samples_used,
-					 unsigned int round_used)
-{
-	size_t i;
-
-	if (!samples_used)
-		return 0;
 
-	if (!data_buf)
+	/* we do not convert the endianness of the multi entry header */
+	if (!rdcu_supported_data_type_is_used(data_type))
+		data = (uint8_t *)data + MULTI_ENTRY_HDR_SIZE;
+
+	switch (data_type) {
+	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+		be_to_cpus_16(data, samples);
+		break;
+	case DATA_TYPE_OFFSET:
+		be_to_cpus_nc_offset(data, samples);
+		break;
+	case DATA_TYPE_BACKGROUND:
+		be_to_cpus_nc_background(data, samples);
+		break;
+	case DATA_TYPE_SMEARING:
+		be_to_cpus_smearing(data, samples);
+		break;
+	case DATA_TYPE_S_FX:
+		be_to_cpus_s_fx(data, samples);
+		break;
+	case DATA_TYPE_S_FX_EFX:
+		be_to_cpus_s_fx_efx(data, samples);
+		break;
+	case DATA_TYPE_S_FX_NCOB:
+		be_to_cpus_s_fx_ncob(data, samples);
+		break;
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+		be_to_cpus_s_fx_efx_ncob_ecob(data, samples);
+		break;
+	case DATA_TYPE_L_FX:
+		be_to_cpus_l_fx(data, samples);
+		break;
+	case DATA_TYPE_L_FX_EFX:
+		be_to_cpus_l_fx_efx(data, samples);
+		break;
+	case DATA_TYPE_L_FX_NCOB:
+		be_to_cpus_l_fx_ncob(data, samples);
+		break;
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+		be_to_cpus_l_fx_efx_ncob_ecob(data, samples);
+		break;
+	case DATA_TYPE_F_FX:
+		be_to_cpus_f_fx(data, samples);
+		break;
+	case DATA_TYPE_F_FX_EFX:
+		be_to_cpus_f_fx_efx(data, samples);
+		break;
+	case DATA_TYPE_F_FX_NCOB:
+		be_to_cpus_f_fx_ncob(data, samples);
+		break;
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		be_to_cpus_f_fx_efx_ncob_ecob(data, samples);
+		break;
+	/* TODO: implement F_CAM conversion */
+	case DATA_TYPE_F_CAM_OFFSET:
+	case DATA_TYPE_F_CAM_BACKGROUND:
+	case DATA_TYPE_UNKNOWN:
+	default:
+		debug_print("Error: Can not swap endianness for this compression data type.\n");
 		return -1;
-
-	if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */
-		return 0;
-
-	for (i = 0; i < samples_used; i++) {
-		uint32_t mask = (~0U << (32-round_used));
-
-		if (data_buf[i].FX & mask) {
-			debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].NCOB_X & mask) {
-			debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].NCOB_Y & mask) {
-			debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].EFX & mask) {
-			debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].ECOB_X & mask) {
-			debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n");
-			return -1;
-		}
-		if (data_buf[i].ECOB_Y & mask) {
-			debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n");
-			return -1;
-		}
-
-		data_buf[i].FX = round_inv(data_buf[i].FX, round_used);
-		data_buf[i].NCOB_X = round_inv(data_buf[i].NCOB_X, round_used);
-		data_buf[i].NCOB_Y = round_inv(data_buf[i].NCOB_Y, round_used);
-		data_buf[i].EFX = round_inv(data_buf[i].EFX, round_used);
-		data_buf[i].ECOB_X = round_inv(data_buf[i].ECOB_X, round_used);
-		data_buf[i].ECOB_Y = round_inv(data_buf[i].ECOB_Y, round_used);
 	}
-	return 0;
-}
-
 
-struct S_FX_EFX_NCOB_ECOB cal_up_model_S_FX_EFX_NCOB_ECOB
-	(struct S_FX_EFX_NCOB_ECOB data_buf, struct S_FX_EFX_NCOB_ECOB
-	 model_buf, unsigned int model_value)
-{
-	struct S_FX_EFX_NCOB_ECOB result;
-
-	result.EXPOSURE_FLAGS =
-		(uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS,
-				      model_buf.EXPOSURE_FLAGS, model_value);
-	result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value);
-	result.NCOB_X = cal_up_model(data_buf.NCOB_X, model_buf.NCOB_X, model_value);
-	result.NCOB_Y = cal_up_model(data_buf.NCOB_Y, model_buf.NCOB_Y, model_value);
-	result.EFX = cal_up_model(data_buf.EFX, model_buf.EFX, model_value);
-	result.ECOB_X = cal_up_model(data_buf.ECOB_X, model_buf.ECOB_X, model_value);
-	result.ECOB_Y = cal_up_model(data_buf.ECOB_Y, model_buf.ECOB_Y, model_value);
-
-	return result;
+	return 0;
 }
diff --git a/lib/cmp_entity.c b/lib/cmp_entity.c
index 84f784d0993f62f12336966ce398ec7ff33f3e1d..daa1e11917a0565378ec00738c7787b7ae3c152e 100644
--- a/lib/cmp_entity.c
+++ b/lib/cmp_entity.c
@@ -17,24 +17,30 @@
  * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
  */
 
+
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 #include <limits.h>
-#if __has_include(<time.h>)
-	#include <time.h>
-	#include <stdlib.h>
+#if defined __has_include
+#  if __has_include(<time.h>)
+#    include <time.h>
+#    include <stdlib.h>
+#    define HAS_TIME_H 1
+#  endif
 #endif
 
-#include "../include/cmp_entity.h"
-#include "../include/cmp_support.h"
-#include "../include/byteorder.h"
+#include <byteorder.h>
+#include <cmp_debug.h>
+#include <cmp_support.h>
+#include <cmp_data_types.h>
+#include <cmp_entity.h>
 
 
-#if __has_include(<time.h>)
+#ifdef HAS_TIME_H
 /* Used as epoch Wed Jan  1 00:00:00 2020 */
 #  if defined(_WIN32) || defined(_WIN64)
-const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0, };
+const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0 };
 #  else
 const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0, 0, NULL };
 #  endif /* _WIN */
@@ -42,69 +48,61 @@ const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0, 0, NULL };
 
 
 /**
- * @brief calculate the size of the compression entity header based of the data
+ * @brief calculate the size of the compression entity header based on the data
  *	product type
  *
  * @param data_type	compression entity data product type
+ * @param raw_mode_flag	set this flag if the raw compression mode (CMP_MODE_RAW) is used
  *
  * @returns size of the compression entity header in bytes, 0 on unknown data
  *	type
  */
 
-uint32_t cmp_ent_cal_hdr_size(enum cmp_ent_data_type data_type)
-{
-	switch (data_type) {
-	case DATA_TYPE_IMAGETTE:
-	case DATA_TYPE_F_CAM_IMAGETTE:
-		return IMAGETTE_HEADER_SIZE;
-	case DATA_TYPE_IMAGETTE_ADAPTIVE:
-	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
-		return IMAGETTE_ADAPTIVE_HEADER_SIZE;
-	case DATA_TYPE_SAT_IMAGETTE:
-	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
-	case DATA_TYPE_OFFSET:
-	case DATA_TYPE_BACKGROUND:
-	case DATA_TYPE_SMEARING:
-	case DATA_TYPE_S_FX:
-	case DATA_TYPE_S_FX_DFX:
-	case DATA_TYPE_S_FX_NCOB:
-	case DATA_TYPE_S_FX_DFX_NCOB_ECOB:
-	case DATA_TYPE_L_FX:
-	case DATA_TYPE_L_FX_DFX:
-	case DATA_TYPE_L_FX_NCOB:
-	case DATA_TYPE_L_FX_DFX_NCOB_ECOB:
-	case DATA_TYPE_F_FX:
-	case DATA_TYPE_F_FX_DFX:
-	case DATA_TYPE_F_FX_NCOB:
-	case DATA_TYPE_F_FX_DFX_NCOB_ECOB:
-	case DATA_TYPE_F_CAM_OFFSET:
-	case DATA_TYPE_F_CAM_BACKGROUND:
-		return NON_IMAGETTE_HEADER_SIZE;
-	case DATA_TYPE_UNKOWN:
-		return 0;
+uint32_t cmp_ent_cal_hdr_size(enum cmp_data_type data_type, int raw_mode_flag)
+{
+	uint32_t size = 0;
+
+	if (raw_mode_flag) {
+		if (cmp_data_type_valid(data_type))
+			/* for raw data we do not need a specific header */
+			size = GENERIC_HEADER_SIZE;
+	} else {
+		switch (data_type) {
+		case DATA_TYPE_IMAGETTE:
+		case DATA_TYPE_SAT_IMAGETTE:
+		case DATA_TYPE_F_CAM_IMAGETTE:
+			size = IMAGETTE_HEADER_SIZE;
+			break;
+		case DATA_TYPE_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+			size = IMAGETTE_ADAPTIVE_HEADER_SIZE;
+			break;
+		case DATA_TYPE_OFFSET:
+		case DATA_TYPE_BACKGROUND:
+		case DATA_TYPE_SMEARING:
+		case DATA_TYPE_S_FX:
+		case DATA_TYPE_S_FX_EFX:
+		case DATA_TYPE_S_FX_NCOB:
+		case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+		case DATA_TYPE_L_FX:
+		case DATA_TYPE_L_FX_EFX:
+		case DATA_TYPE_L_FX_NCOB:
+		case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+		case DATA_TYPE_F_FX:
+		case DATA_TYPE_F_FX_EFX:
+		case DATA_TYPE_F_FX_NCOB:
+		case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		case DATA_TYPE_F_CAM_OFFSET:
+		case DATA_TYPE_F_CAM_BACKGROUND:
+			size = NON_IMAGETTE_HEADER_SIZE;
+			break;
+		case DATA_TYPE_UNKNOWN:
+			size = 0;
+			break;
+		}
 	}
-
-	if ((data_type >> RAW_BIT_DATA_TYPE_POS) & 1U)
-		return GENERIC_HEADER_SIZE;
-
-	return 0;
-}
-
-
-/**
- * @brief check if the compression entity data product type is supported
- *
- * @param data_type	compression entity data product type to check
- *
- * @returns zero if data_type is invalid; non-zero if data_type is valid
- */
-
-int cmp_ent_data_type_valid(enum cmp_ent_data_type data_type)
-{
-	if (cmp_ent_cal_hdr_size(data_type))
-		return 1;
-	else
-		return 0;
+	return size;
 }
 
 
@@ -326,19 +324,23 @@ int cmp_ent_set_fine_end_time(struct cmp_entity *ent, uint16_t fine_time)
 /**
  * @brief set the data product type in the compression entity header
  *
- * @param ent		pointer to a compression entity (including the
- *	uncompressed data bit)
+ * @param ent		pointer to a compression entity
  * @param data_type	compression entity data product type
+ * @param raw_mode_flag	set this flag if the raw compression mode (CMP_MODE_RAW) is used
  *
  * @returns 0 on success, otherwise error
  */
 
 int cmp_ent_set_data_type(struct cmp_entity *ent,
-			  enum cmp_ent_data_type data_type)
+			  enum cmp_data_type data_type,
+			  int raw_mode_flag)
 {
 	if (!ent)
 		return -1;
 
+	if (raw_mode_flag)
+		data_type |= 1U << RAW_BIT_DATA_TYPE_POS;
+
 	if (data_type > UINT16_MAX)
 		return -1;
 
@@ -440,6 +442,27 @@ int cmp_ent_set_model_counter(struct cmp_entity *ent, uint32_t model_counter)
 }
 
 
+/**
+ * @brief set version identifier for the max. used bits registry in the
+ *	compression entity header
+ *
+ * @param ent			pointer to a compression entity
+ * @param max_used_bits_version	the identifier for the max. used bits registry
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int cmp_ent_set_max_used_bits_version(struct cmp_entity *ent, uint8_t max_used_bits_version)
+{
+	if (!ent)
+		return -1;
+
+	ent->max_used_bits_version = max_used_bits_version;
+
+	return 0;
+}
+
+
 /**
  * @brief set the used lossy compression parameter in the compression entity
  *	header
@@ -932,7 +955,7 @@ int cmp_ent_set_non_ima_cmp_par6(struct cmp_entity *ent, uint32_t cmp_par_6_used
 
 
 /**
- * @brief get the ASW version identifier form the compression entity header
+ * @brief get the ASW version identifier from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -949,7 +972,7 @@ uint32_t cmp_ent_get_version_id(struct cmp_entity *ent)
 
 
 /**
- * @brief get the size of the compression entity form the compression entity header
+ * @brief get the size of the compression entity from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -970,7 +993,7 @@ uint32_t cmp_ent_get_size(struct cmp_entity *ent)
 
 
 /**
- * @brief get the original data size form the compression entity header
+ * @brief get the original data size from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -991,7 +1014,7 @@ uint32_t cmp_ent_get_original_size(struct cmp_entity *ent)
 
 
 /**
- * @brief get the compression start timestamp form the compression entity header
+ * @brief get the compression start timestamp from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -1012,7 +1035,7 @@ uint64_t cmp_ent_get_start_timestamp(struct cmp_entity *ent)
 
 
 /**
- * @brief get the coarse time form the compression start timestamp in the
+ * @brief get the coarse time from the compression start timestamp in the
  *	compression entity header
  *
  * @returns the coarse part of the compression start timestamp on success, 0 on
@@ -1029,7 +1052,7 @@ uint32_t cmp_ent_get_coarse_start_time(struct cmp_entity *ent)
 
 
 /**
- * @brief get the fine time form the compression start timestamp in the
+ * @brief get the fine time from the compression start timestamp in the
  *	compression entity header
  *
  * @returns the fine part of the compression start timestamp on success, 0 on
@@ -1046,7 +1069,7 @@ uint16_t cmp_ent_get_fine_start_time(struct cmp_entity *ent)
 
 
 /**
- * @brief get the compression end timestamp form the compression entity header
+ * @brief get the compression end timestamp from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -1067,7 +1090,7 @@ uint64_t cmp_ent_get_end_timestamp(struct cmp_entity *ent)
 
 
 /**
- * @brief get the coarse time form the compression end timestamp in the
+ * @brief get the coarse time from the compression end timestamp in the
  *	compression entity header
  *
  * @returns the coarse part of the compression end timestamp on success, 0 on
@@ -1084,7 +1107,7 @@ uint32_t cmp_ent_get_coarse_end_time(struct cmp_entity *ent)
 
 
 /**
- * @brief get the fine time form the compression end timestamp in the
+ * @brief get the fine time from the compression end timestamp in the
  *	compression entity header
  *
  * @returns the fine part of the compression end timestamp on success, 0 on
@@ -1101,30 +1124,33 @@ uint16_t cmp_ent_get_fine_end_time(struct cmp_entity *ent)
 
 
 /**
- * @brief get data_type form the compression entity header
+ * @brief get data_type from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
- * @returns the data_type (including the uncompressed data bit) on success,
- *	DATA_TYPE_UNKOWN on error
+ * @returns the data_type NOT including the uncompressed data bit on success,
+ *	DATA_TYPE_UNKNOWN on error
  */
 
-enum cmp_ent_data_type cmp_ent_get_data_type(struct cmp_entity *ent)
+enum cmp_data_type cmp_ent_get_data_type(struct cmp_entity *ent)
 {
+	enum cmp_data_type data_type;
+
 	if (!ent)
-		return DATA_TYPE_UNKOWN;
+		return DATA_TYPE_UNKNOWN;
 
-	enum cmp_ent_data_type data_type = be16_to_cpu(ent->data_type);
+	data_type = be16_to_cpu(ent->data_type);
+	data_type &= (1U << RAW_BIT_DATA_TYPE_POS)-1; /* remove uncompressed data flag */
 
-	if (cmp_ent_data_type_valid(data_type))
-		return data_type;
-	else
-		return DATA_TYPE_UNKOWN;
+	if (!cmp_data_type_valid(data_type))
+		data_type = DATA_TYPE_UNKNOWN;
+
+	return data_type;
 }
 
 
 /**
- * @brief get raw bit form the data_type field of the compression entity header
+ * @brief get the raw bit from the data_type field of the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -1176,7 +1202,7 @@ uint8_t cmp_ent_get_model_value_used(struct cmp_entity *ent)
 
 
 /**
- * @brief get model id form the compression entity header
+ * @brief get model id from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -1210,7 +1236,26 @@ uint8_t cmp_ent_get_model_counter(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used lossy compression parameter form the compression entity header
+ * @brief get the version identifier for the max. used bits registry from the
+ *	compression entity header
+ *
+ * @param ent	pointer to a compression entity
+ *
+ * @returns the version identifier for the max. used bits registry on success,
+ *	0 on error
+ */
+
+uint8_t cmp_ent_get_max_use_bits_version(struct cmp_entity *ent)
+{
+	if (!ent)
+		return 0;
+
+	return ent->max_used_bits_version;
+}
+
+
+/**
+ * @brief get the used lossy compression parameter from the compression entity header
  *
  * @param ent	pointer to a compression entity
  *
@@ -1227,7 +1272,7 @@ uint16_t cmp_ent_get_lossy_cmp_par(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold parameter form the (adaptive)
+ * @brief get the used spillover threshold parameter from the (adaptive)
  *	imagette specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1245,7 +1290,7 @@ uint16_t cmp_ent_get_ima_spill(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used Golomb parameter form the (adaptive) imagette specific
+ * @brief get the used Golomb parameter from the (adaptive) imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1263,7 +1308,7 @@ uint8_t cmp_ent_get_ima_golomb_par(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used adaptive 1 spillover threshold parameter form the
+ * @brief get the used adaptive 1 spillover threshold parameter from the
  *	adaptive imagette specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1281,7 +1326,7 @@ uint16_t cmp_ent_get_ima_ap1_spill(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used adaptive 1 Golomb parameter form adaptive imagette
+ * @brief get the used adaptive 1 Golomb parameter from adaptive imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1299,7 +1344,7 @@ uint8_t cmp_ent_get_ima_ap1_golomb_par(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used adaptive 2 spillover threshold parameter form the
+ * @brief get the used adaptive 2 spillover threshold parameter from the
  *	adaptive imagette specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1317,7 +1362,7 @@ uint16_t cmp_ent_get_ima_ap2_spill(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used adaptive 2 spillover threshold parameter form the
+ * @brief get the used adaptive 2 spillover threshold parameter from the
  *	adaptive imagette specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1335,7 +1380,7 @@ uint8_t cmp_ent_get_ima_ap2_golomb_par(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold 1 parameter form the non-imagette
+ * @brief get the used spillover threshold 1 parameter from the non-imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1357,7 +1402,7 @@ uint32_t cmp_ent_get_non_ima_spill1(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used compression parameter 1 form the non-imagette specific
+ * @brief get the used compression parameter 1 from the non-imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1375,7 +1420,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par1(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold 2 parameter form the non-imagette
+ * @brief get the used spillover threshold 2 parameter from the non-imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1397,7 +1442,7 @@ uint32_t cmp_ent_get_non_ima_spill2(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used compression parameter 2 form the non-imagette specific
+ * @brief get the used compression parameter 2 from the non-imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1415,7 +1460,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par2(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold 3 parameter form the non-imagette
+ * @brief get the used spillover threshold 3 parameter from the non-imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1437,7 +1482,7 @@ uint32_t cmp_ent_get_non_ima_spill3(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used compression parameter 3 form the non-imagette specific
+ * @brief get the used compression parameter 3 from the non-imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1455,7 +1500,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par3(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold 4 parameter form the non-imagette
+ * @brief get the used spillover threshold 4 parameter from the non-imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1477,7 +1522,7 @@ uint32_t cmp_ent_get_non_ima_spill4(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used compression parameter 4 form the non-imagette specific
+ * @brief get the used compression parameter 4 from the non-imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1495,7 +1540,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par4(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold 5 parameter form the non-imagette
+ * @brief get the used spillover threshold 5 parameter from the non-imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1517,7 +1562,7 @@ uint32_t cmp_ent_get_non_ima_spill5(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used compression parameter 5 form the non-imagette specific
+ * @brief get the used compression parameter 5 from the non-imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1535,7 +1580,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par5(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used spillover threshold 6 parameter form the non-imagette
+ * @brief get the used spillover threshold 6 parameter from the non-imagette
  *	specific compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1557,7 +1602,7 @@ uint32_t cmp_ent_get_non_ima_spill6(struct cmp_entity *ent)
 
 
 /**
- * @brief get the used compression parameter 6 form the non-imagette specific
+ * @brief get the used compression parameter 6 from the non-imagette specific
  *	compression entity header
  *
  * @param ent	pointer to a compression entity
@@ -1588,44 +1633,50 @@ uint16_t cmp_ent_get_non_ima_cmp_par6(struct cmp_entity *ent)
 
 void *cmp_ent_get_data_buf(struct cmp_entity *ent)
 {
-	enum cmp_ent_data_type data_type;
+	enum cmp_data_type data_type;
 
 	if (!ent)
 		return NULL;
 
+	data_type = cmp_ent_get_data_type(ent);
+	if (!cmp_data_type_valid(data_type)) {
+		debug_print("Error: Compression data type not supported.\n");
+		return NULL;
+	}
+
 	if (cmp_ent_get_data_type_raw_bit(ent))
 		return (uint8_t *)ent + GENERIC_HEADER_SIZE;
 
-	data_type = cmp_ent_get_data_type(ent);
 
 	switch (data_type) {
 	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE:
 	case DATA_TYPE_F_CAM_IMAGETTE:
 		return ent->ima.ima_cmp_dat;
 	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
 	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
 		return ent->ima.ap_ima_cmp_data;
-	case DATA_TYPE_SAT_IMAGETTE:
-	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
 	case DATA_TYPE_OFFSET:
 	case DATA_TYPE_BACKGROUND:
 	case DATA_TYPE_SMEARING:
 	case DATA_TYPE_S_FX:
-	case DATA_TYPE_S_FX_DFX:
+	case DATA_TYPE_S_FX_EFX:
 	case DATA_TYPE_S_FX_NCOB:
-	case DATA_TYPE_S_FX_DFX_NCOB_ECOB:
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
 	case DATA_TYPE_L_FX:
-	case DATA_TYPE_L_FX_DFX:
+	case DATA_TYPE_L_FX_EFX:
 	case DATA_TYPE_L_FX_NCOB:
-	case DATA_TYPE_L_FX_DFX_NCOB_ECOB:
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
 	case DATA_TYPE_F_FX:
-	case DATA_TYPE_F_FX_DFX:
+	case DATA_TYPE_F_FX_EFX:
 	case DATA_TYPE_F_FX_NCOB:
-	case DATA_TYPE_F_FX_DFX_NCOB_ECOB:
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
 	case DATA_TYPE_F_CAM_OFFSET:
 	case DATA_TYPE_F_CAM_BACKGROUND:
 		return ent->non_ima.cmp_data;
-	case DATA_TYPE_UNKOWN:
+	case DATA_TYPE_UNKNOWN:
+	default:
 		return NULL;
 	}
 
@@ -1634,15 +1685,14 @@ void *cmp_ent_get_data_buf(struct cmp_entity *ent)
 
 
 /**
- * @brief copy the data form a compression entity to a buffer
+ * @brief copy the data from a compression entity to a buffer
  *
  * @param ent		pointer to the compression entity containing the compressed data
  * @param data_buf	pointer where the destination data buffer where the
  *	compressed data is copied to (can be NULL)
  * @param data_buf_size	size of the destination data buffer
- * @param verbose_en	print verbose output if not zero
  *
- * @returns the size in bytes to store the compressed data; negative on error
+ * @returns the size in bytes to store the compressed data; -1 on error
  *
  * @note the destination and source buffer can overlap
  * @note converts the data to the correct endianness
@@ -1700,7 +1750,8 @@ ssize_t cmp_ent_get_cmp_data(struct cmp_entity *ent, uint32_t *data_buf,
 
 static uint32_t cmp_ent_get_hdr_size(struct cmp_entity *ent)
 {
-	return cmp_ent_cal_hdr_size(cmp_ent_get_data_type(ent));
+	return cmp_ent_cal_hdr_size(cmp_ent_get_data_type(ent),
+				    cmp_ent_get_data_type_raw_bit(ent));
 }
 
 
@@ -1728,77 +1779,195 @@ uint32_t cmp_ent_get_cmp_data_size(struct cmp_entity *ent)
 
 
 /**
- * @brief set the parameters in the non-imagette specific compression
- *	entity header
- *
- * @param ent	pointer to a compression entity
- * @param info	decompression information structure
+ * @brief write the compression parameters from a compression configuration
+ *	into the compression entity header
+ * @note no compressed data are put into the entity and no change of the entity
+ *	size
  *
- * @returns 0 on success, otherwise error
+ * @param ent		pointer to a compression entity
+ * @param cfg		pointer to a compression configuration
+ * @param cmp_size_bits	size of the compressed data in bits
  *
- * @warning this functions is not implemented jet
+ * @returns 0 on success, negative on error
  */
 
-static int cmp_ent_write_non_ima_parameters(struct cmp_entity *ent, struct cmp_info *info)
+int cmp_ent_write_cmp_pars(struct cmp_entity *ent, const struct cmp_cfg *cfg,
+			   int cmp_size_bits)
 {
-	if (!info)
-		return -1;
-	(void)ent;
+	uint32_t ent_cmp_data_size;
 
-	printf("not implemented jet!\n");
-	return -1;
-#if 0
-	if (cmp_ent_set_non_ima_spill1(ent, info->))
-		return -1;
-	if (cmp_ent_set_non_ima_cmp_par1(ent, info->))
+	if (!cfg)
 		return -1;
 
-	if (cmp_ent_set_non_ima_spill2(ent, info->))
-		return -1;
-	if (cmp_ent_set_non_ima_cmp_par2(ent, info->))
+	if (cmp_size_bits < 0)
 		return -1;
 
-	if (cmp_ent_set_non_ima_spill3(ent, info->))
-		return -1;
-	if (cmp_ent_set_non_ima_cmp_par3(ent, info->))
+	if (cfg->data_type != cmp_ent_get_data_type(ent)) {
+		debug_print("Error: The entity data product type dos not match the configuration data product type.\n");
 		return -1;
+	}
+
+	ent_cmp_data_size = cmp_ent_get_cmp_data_size(ent);
+
+	/* check if the entity can hold the compressed data */
+	if (ent_cmp_data_size < cmp_bit_to_4byte((unsigned int)cmp_size_bits)) {
+		debug_print("Error: The entity size is to small to hold the compressed data.\n");
+		return -2;
+	}
 
-	if (cmp_ent_set_non_ima_spill4(ent, info->))
+	/* set compression parameter fields in the generic entity header */
+	if (cmp_ent_set_original_size(ent, cmp_cal_size_of_data(cfg->samples,
+								cfg->data_type)))
 		return -1;
-	if (cmp_ent_set_non_ima_cmp_par4(ent, info->))
+	if (cmp_ent_set_cmp_mode(ent, cfg->cmp_mode))
 		return -1;
-
-	if (cmp_ent_set_non_ima_spill5(ent, info->))
+	if (cmp_ent_set_model_value(ent, cfg->model_value))
 		return -1;
-	if (cmp_ent_set_non_ima_cmp_par5(ent, info->))
+	if (cmp_ent_set_max_used_bits_version(ent, cmp_get_max_used_bits_version()))
 		return -1;
-
-	if (cmp_ent_set_non_ima_spill6(ent, info->))
+	if (cmp_ent_set_lossy_cmp_par(ent, cfg->round))
 		return -1;
-	if (cmp_ent_set_non_ima_cmp_par6(ent, info->))
+
+	if (cfg->cmp_mode == CMP_MODE_RAW) {
+		/* check the raw data bit */
+		if (!cmp_ent_get_data_type_raw_bit(ent)) {
+			debug_print("Error: The entity's raw data bit is not set, but the configuration contains raw data.\n");
+			return -1;
+		}
+		/* no specific header is used for raw data we are done */
+		return 0;
+	}
+
+	switch (cmp_ent_get_data_type(ent)) {
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+		if (cmp_ent_set_ima_ap1_spill(ent, cfg->ap1_spill))
+			return -1;
+		if (cmp_ent_set_ima_ap1_golomb_par(ent, cfg->ap1_golomb_par))
+			return -1;
+		if (cmp_ent_set_ima_ap2_spill(ent, cfg->ap2_spill))
+			return -1;
+		if (cmp_ent_set_ima_ap2_golomb_par(ent, cfg->ap2_golomb_par))
+			return -1;
+		/* fall through */
+	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
+		if (cmp_ent_set_ima_spill(ent, cfg->spill))
+			return -1;
+		if (cmp_ent_set_ima_golomb_par(ent, cfg->golomb_par))
+			return -1;
+		break;
+	case DATA_TYPE_OFFSET:
+	case DATA_TYPE_BACKGROUND:
+	case DATA_TYPE_SMEARING:
+		if (cmp_ent_set_non_ima_cmp_par1(ent, cfg->cmp_par_mean))
+			return -1;
+		if (cmp_ent_set_non_ima_spill1(ent, cfg->spill_mean))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par2(ent, cfg->cmp_par_variance))
+			return -1;
+		if (cmp_ent_set_non_ima_spill2(ent, cfg->spill_variance))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par3(ent, cfg->cmp_par_pixels_error))
+			return -1;
+		if (cmp_ent_set_non_ima_spill3(ent, cfg->spill_pixels_error))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par4(ent, 0))
+			return -1;
+		if (cmp_ent_set_non_ima_spill4(ent, 0))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par5(ent, 0))
+			return -1;
+		if (cmp_ent_set_non_ima_spill5(ent, 0))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par6(ent, 0))
+			return -1;
+		if (cmp_ent_set_non_ima_spill6(ent, 0))
+			return -1;
+		break;
+	case DATA_TYPE_S_FX:
+	case DATA_TYPE_S_FX_EFX:
+	case DATA_TYPE_S_FX_NCOB:
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+	case DATA_TYPE_L_FX:
+	case DATA_TYPE_L_FX_EFX:
+	case DATA_TYPE_L_FX_NCOB:
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+	case DATA_TYPE_F_FX:
+	case DATA_TYPE_F_FX_EFX:
+	case DATA_TYPE_F_FX_NCOB:
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		if (cmp_ent_set_non_ima_cmp_par1(ent, cfg->cmp_par_exp_flags))
+			return -1;
+		if (cmp_ent_set_non_ima_spill1(ent, cfg->spill_exp_flags))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par2(ent, cfg->cmp_par_fx))
+			return -1;
+		if (cmp_ent_set_non_ima_spill2(ent, cfg->spill_fx))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par3(ent, cfg->cmp_par_ncob))
+			return -1;
+		if (cmp_ent_set_non_ima_spill3(ent, cfg->spill_ncob))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par4(ent, cfg->cmp_par_efx))
+			return -1;
+		if (cmp_ent_set_non_ima_spill4(ent, cfg->spill_efx))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par5(ent, cfg->cmp_par_ecob))
+			return -1;
+		if (cmp_ent_set_non_ima_spill5(ent, cfg->spill_ecob))
+			return -1;
+
+		if (cmp_ent_set_non_ima_cmp_par6(ent, cfg->cmp_par_fx_cob_variance))
+			return -1;
+		if (cmp_ent_set_non_ima_spill6(ent, cfg->spill_fx_cob_variance))
+			return -1;
+
+		break;
+	case DATA_TYPE_F_CAM_OFFSET:
+	case DATA_TYPE_F_CAM_BACKGROUND:
+		/* TODO: fix this*/
+			return -1;
+		break;
+	case DATA_TYPE_UNKNOWN:
+	default:
 		return -1;
+	}
+
 	return 0;
-#endif
 }
 
 
 /**
- * @brief write the compression parameters in the entity header based on the data
- *	product type set in the entity and the provided decompression information
- *	struct
+ * @brief write the parameters from the RDCU decompression information structure
+ *	in the compression entity header
+ * @note no compressed data are put into the entity and no change of the entity
+ *	size
  *
  * @param ent	pointer to a compression entity
- * @param info	decompression information structure
- * @param cfg	compression configuration structure for adaptive compression
- *	parameters (can be NULL)
+ * @param info	pointer to a decompression information structure
+ * @param cfg	pointer to a compression configuration structure for adaptive
+ *	compression parameters (can be NULL if non adaptive data_type is used)
  *
  * @returns 0 on success, negative on error
  */
 
-static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info,
-				struct cmp_cfg *cfg)
+int cmp_ent_write_rdcu_cmp_pars(struct cmp_entity *ent, const struct cmp_info *info,
+				const struct cmp_cfg *cfg)
 {
 	uint32_t ent_cmp_data_size;
+	enum cmp_data_type data_type = cmp_ent_get_data_type(ent);
 
 	if (!info)
 		return -1;
@@ -1806,12 +1975,18 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info,
 	ent_cmp_data_size = cmp_ent_get_cmp_data_size(ent);
 
 	/* check if the entity can hold the compressed data */
-	if (ent_cmp_data_size < cmp_bit_to_4byte(info->cmp_size))
+	if (ent_cmp_data_size < cmp_bit_to_4byte(info->cmp_size)) {
+		debug_print("Error: The entity size is to small to hold the compressed data.\n");
 		return -2;
+	}
+
+	if (!rdcu_supported_data_type_is_used(data_type)) {
+		debug_print("Error: The compression data type is not one of the types supported by the RDCU.\n");
+		return -1;
+	}
 
 	/* set compression parameter fields in the generic entity header */
-	if (cmp_ent_set_original_size(ent, cmp_cal_size_of_data(info->samples_used,
-								info->cmp_mode_used)))
+	if (cmp_ent_set_original_size(ent, cmp_cal_size_of_data(info->samples_used, DATA_TYPE_IMAGETTE)))
 		return -1;
 	if (cmp_ent_set_cmp_mode(ent, info->cmp_mode_used))
 		return -1;
@@ -1820,16 +1995,27 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info,
 	if (cmp_ent_set_lossy_cmp_par(ent, info->round_used))
 		return -1;
 
-	if (cmp_ent_get_data_type_raw_bit(ent))
+	if (cmp_ent_get_data_type_raw_bit(ent) != raw_mode_is_used(info->cmp_mode_used)) {
+		debug_print("Error: The raw bit is set in data product type filed, but no raw compression mode is used.\n");
+		return -1;
+	}
+	if (raw_mode_is_used(info->cmp_mode_used))
 		/* no specific header is used for raw data we are done */
 		return 0;
 
-	switch (cmp_ent_get_data_type(ent)) {
-	case DATA_TYPE_IMAGETTE_ADAPTIVE:
-	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
-	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
-		if (!cfg)
+	if (cmp_ent_set_ima_spill(ent, info->spill_used))
+		return -1;
+	if (cmp_ent_set_ima_golomb_par(ent, info->golomb_par_used))
+		return -1;
+
+	/* use the adaptive imagette parameter from the compression configuration
+	 * if an adaptive imagette compression data type is ent in the entity
+	 */
+	if (cmp_ap_imagette_data_type_is_used(data_type)) {
+		if (!cfg) {
+			debug_print("Error: Need the compression configuration to get the adaptive parameters.\n");
 			return -1;
+		}
 		if (cmp_ent_set_ima_ap1_spill(ent, cfg->ap1_spill))
 			return -1;
 		if (cmp_ent_set_ima_ap1_golomb_par(ent, cfg->ap1_golomb_par))
@@ -1838,38 +2024,6 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info,
 			return -1;
 		if (cmp_ent_set_ima_ap2_golomb_par(ent, cfg->ap2_golomb_par))
 			return -1;
-		/* fall through */
-	case DATA_TYPE_IMAGETTE:
-	case DATA_TYPE_SAT_IMAGETTE:
-	case DATA_TYPE_F_CAM_IMAGETTE:
-		if (cmp_ent_set_ima_spill(ent, info->spill_used))
-			return -1;
-		if (cmp_ent_set_ima_golomb_par(ent, info->golomb_par_used))
-			return -1;
-		break;
-	case DATA_TYPE_OFFSET:
-	case DATA_TYPE_BACKGROUND:
-	case DATA_TYPE_SMEARING:
-	case DATA_TYPE_S_FX:
-	case DATA_TYPE_S_FX_DFX:
-	case DATA_TYPE_S_FX_NCOB:
-	case DATA_TYPE_S_FX_DFX_NCOB_ECOB:
-	case DATA_TYPE_L_FX:
-	case DATA_TYPE_L_FX_DFX:
-	case DATA_TYPE_L_FX_NCOB:
-	case DATA_TYPE_L_FX_DFX_NCOB_ECOB:
-	case DATA_TYPE_F_FX:
-	case DATA_TYPE_F_FX_DFX:
-	case DATA_TYPE_F_FX_NCOB:
-	case DATA_TYPE_F_FX_DFX_NCOB_ECOB:
-	case DATA_TYPE_F_CAM_OFFSET:
-	case DATA_TYPE_F_CAM_BACKGROUND:
-		if (cmp_ent_write_non_ima_parameters(ent, info))
-			return -1;
-		break;
-	case DATA_TYPE_UNKOWN: /* fall through */
-	default:
-		return -1;
 	}
 
 	return 0;
@@ -1877,13 +2031,14 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info,
 
 
 /**
- * @brief create a compression entity by setting the size of the
- * compression entity and the data product type in the entity header
+ * @brief create a compression entity by setting the size of the compression
+ *	entity and the data product type in the entity header
  *
  * @param ent		pointer to a compression entity; if NULL, the function
- *	returns the needed size
+ *			returns the needed size
  * @param data_type	compression entity data product type
- * @param cmp_size_byte	size of the compressed data in bytes
+ * @param raw_mode_flag	set this flag if the raw compression mode (CMP_MODE_RAW) is used
+ * @param cmp_size_byte	size of the compressed data in bytes (should be a multiple of 4)
  *
  * @note if the entity size is smaller than the largest header, the function
  *	rounds up the entity size to the largest header
@@ -1891,12 +2046,12 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info,
  * @returns the size of the compression entity or 0 on error
  */
 
-size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
-		      uint32_t cmp_size_byte)
+uint32_t cmp_ent_create(struct cmp_entity *ent, enum cmp_data_type data_type,
+			int raw_mode_flag, uint32_t cmp_size_byte)
 {
 	int err;
-	uint32_t hdr_size = cmp_ent_cal_hdr_size(data_type);
-	size_t ent_size = hdr_size + cmp_size_byte;
+	uint32_t hdr_size = cmp_ent_cal_hdr_size(data_type, raw_mode_flag);
+	uint32_t ent_size = hdr_size + cmp_size_byte;
 	uint32_t ent_size_cpy = ent_size;
 
 	if (!hdr_size)
@@ -1905,6 +2060,11 @@ size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
 	if (cmp_size_byte > CMP_ENTITY_MAX_SIZE)
 		return 0;
 
+	if (ent_size > CMP_ENTITY_MAX_SIZE)
+		return 0;
+
+	/* to be safe a compression entity should be at least the size of the
+	 * largest entity header */
 	if (ent_size < sizeof(struct cmp_entity))
 		ent_size = sizeof(struct cmp_entity);
 
@@ -1917,7 +2077,7 @@ size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
 	if (err)
 		return 0;
 
-	err = cmp_ent_set_data_type(ent, data_type);
+	err = cmp_ent_set_data_type(ent, data_type, raw_mode_flag);
 	if (err)
 		return 0;
 
@@ -1928,35 +2088,37 @@ size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
 /**
  * @brief create a compression entity and set the header fields
  *
- * @note this function simplifies the entity setup by creating a entity and
+ * @note this function simplifies the entity set up by creating an entity and
  *	setting the header fields in one function call
+ * @note no compressed data are put into the entity
  *
  * @param ent			pointer to a compression entity; if NULL, the
  *	function returns the needed size
- * @param data_type		compression entity data product type
- * @param version_id	applications software version identifier
+ * @param version_id		applications software version identifier
  * @param start_time		compression start timestamp (coarse and fine)
  * @param end_time		compression end timestamp (coarse and fine)
  * @param model_id		model identifier
  * @param model_counter		model counter
- * @param info			decompression information structure
- * @param cfg			compression configuration structure for adaptive
- *	compression parameters (can be NULL)
+ * @param cfg			pointer to compression configuration (can be NULL)
+ * @param cmp_size_bits		length of the compressed data in bits
  *
  * @returns the size of the compression entity or 0 on error
  */
 
-size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
-		     uint32_t version_id, uint64_t start_time,
-		     uint64_t end_time, uint16_t model_id, uint8_t model_counter,
-		     struct cmp_info *info, struct cmp_cfg *cfg)
+size_t cmp_ent_build(struct cmp_entity *ent, uint32_t version_id,
+		     uint64_t start_time, uint64_t end_time, uint16_t model_id,
+		     uint8_t model_counter, struct cmp_cfg *cfg, int cmp_size_bits)
 {
 	uint32_t ent_size;
 
-	if (!info)
+	if (!cfg)
+		return 0;
+
+	if (cmp_size_bits < 0)
 		return 0;
 
-	ent_size = cmp_ent_create(ent, data_type, cmp_bit_to_4byte(info->cmp_size));
+	ent_size = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW,
+				  cmp_bit_to_4byte((unsigned int)cmp_size_bits));
 	if (!ent_size)
 		return 0;
 
@@ -1971,7 +2133,7 @@ size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
 			return 0;
 		if (cmp_ent_set_model_counter(ent, model_counter))
 			return 0;
-		if (cmp_ent_write_cmp_pars(ent, info, cfg))
+		if (cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits))
 			return 0;
 	}
 
@@ -1980,82 +2142,116 @@ size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type,
 
 
 /**
- * @brief read in read in a imagette compression entity header to a info struct
+ * @brief read in an imagette compression entity header to a
+ *	compression configuration
  *
- * @param ent			pointer to a compression entity
- * @param info			pointer to decompression information structure
- *	to store the read values
+ * @param ent	pointer to a compression entity
+ * @param cfg	pointer to a compression configuration
  *
  * @returns 0 on success; otherwise error
  */
 
-int cmp_ent_read_imagette_header(struct cmp_entity *ent, struct cmp_info *info)
+int cmp_ent_read_header(struct cmp_entity *ent, struct cmp_cfg *cfg)
 {
-	uint32_t original_size;
-	uint32_t sample_size;
-
-	if (!ent)
-		return -1;
-
-	if (!info)
-		return -1;
+	int samples;
 
-	info->cmp_mode_used = cmp_ent_get_cmp_mode(ent);
-	info->model_value_used = cmp_ent_get_model_value_used(ent);
-	info->round_used = cmp_ent_get_lossy_cmp_par(ent);
-	info->spill_used = cmp_ent_get_ima_spill(ent);
-	info->golomb_par_used = cmp_ent_get_ima_golomb_par(ent);
-	info->cmp_size = cmp_ent_get_cmp_data_size(ent)*CHAR_BIT;
-
-	sample_size = size_of_a_sample(info->cmp_mode_used);
-	if (!sample_size) {
-		info->samples_used = 0;
-		return -1;
-	}
-
-	original_size = cmp_ent_get_original_size(ent);
-	if (original_size % sample_size != 0) {
-		fprintf(stderr, "Error: original_size and cmp_mode compression header field are not compatible.\n");
-		info->samples_used = 0;
+	cfg->data_type = cmp_ent_get_data_type(ent);
+	if (!cmp_data_type_valid(cfg->data_type)) {
+		debug_print("Error: Compression data type not supported.\n");
 		return -1;
 	}
 
-	info->samples_used = original_size / sample_size;
+	cfg->cmp_mode = cmp_ent_get_cmp_mode(ent);
+	cfg->model_value = cmp_ent_get_model_value_used(ent);
+	cfg->round = cmp_ent_get_lossy_cmp_par(ent);
+	cfg->buffer_length = cmp_ent_get_cmp_data_size(ent);
 
-	if (cmp_ent_get_data_type_raw_bit(ent) != raw_mode_is_used(info->cmp_mode_used)) {
-		fprintf(stderr, "Error: The raw bit is set in Data Product Type Filed, but no raw compression mode is used.\n");
+	samples = cmp_input_size_to_samples(cmp_ent_get_original_size(ent), cfg->data_type);
+	if (samples < 0) {
+		debug_print("Error: original_size and data product type in the compression header field are not compatible.\n");
+		cfg->samples = 0;
 		return -1;
 	}
-	return 0;
-}
 
+	cfg->samples = samples;
 
-#if 0
-int cmp_ent_read_adaptive_imagette_header(struct cmp_entity *ent, struct cmp_info *info)
-{
-	if (!ent)
+	if (cmp_ent_get_data_type_raw_bit(ent) != raw_mode_is_used(cfg->cmp_mode)) {
+		debug_print("Error: The raw bit is set in data product type filed, but no raw compression mode is used.\n");
 		return -1;
+	}
 
-	if (!info)
-		return -1;
+	cfg->icu_output_buf = cmp_ent_get_data_buf(ent);
 
-	if (cmp_ent_get_imagette_header(ent, info))
+	switch (cfg->data_type) {
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+		cfg->ap1_golomb_par = cmp_ent_get_ima_ap1_golomb_par(ent);
+		cfg->ap1_spill = cmp_ent_get_ima_ap1_spill(ent);
+		cfg->ap2_golomb_par = cmp_ent_get_ima_ap2_golomb_par(ent);
+		cfg->ap2_spill = cmp_ent_get_ima_ap2_spill(ent);
+		/* fall through */
+	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
+		cfg->spill = cmp_ent_get_ima_spill(ent);
+		cfg->golomb_par = cmp_ent_get_ima_golomb_par(ent);
+		break;
+	case DATA_TYPE_OFFSET:
+	case DATA_TYPE_BACKGROUND:
+	case DATA_TYPE_SMEARING:
+		cfg->cmp_par_mean = cmp_ent_get_non_ima_cmp_par1(ent);
+		cfg->spill_mean = cmp_ent_get_non_ima_spill1(ent);
+		cfg->cmp_par_variance = cmp_ent_get_non_ima_cmp_par2(ent);
+		cfg->spill_variance = cmp_ent_get_non_ima_spill2(ent);
+		cfg->cmp_par_pixels_error = cmp_ent_get_non_ima_cmp_par3(ent);
+		cfg->spill_pixels_error = cmp_ent_get_non_ima_spill3(ent);
+		break;
+	case DATA_TYPE_S_FX:
+	case DATA_TYPE_S_FX_EFX:
+	case DATA_TYPE_S_FX_NCOB:
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+	case DATA_TYPE_L_FX:
+	case DATA_TYPE_L_FX_EFX:
+	case DATA_TYPE_L_FX_NCOB:
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+	case DATA_TYPE_F_FX:
+	case DATA_TYPE_F_FX_EFX:
+	case DATA_TYPE_F_FX_NCOB:
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		cfg->cmp_par_exp_flags = cmp_ent_get_non_ima_cmp_par1(ent);
+		cfg->spill_exp_flags = cmp_ent_get_non_ima_spill1(ent);
+		cfg->cmp_par_fx = cmp_ent_get_non_ima_cmp_par2(ent);
+		cfg->spill_fx = cmp_ent_get_non_ima_spill2(ent);
+		cfg->cmp_par_ncob = cmp_ent_get_non_ima_cmp_par3(ent);
+		cfg->spill_ncob = cmp_ent_get_non_ima_spill3(ent);
+		cfg->cmp_par_efx = cmp_ent_get_non_ima_cmp_par4(ent);
+		cfg->spill_efx = cmp_ent_get_non_ima_spill4(ent);
+		cfg->cmp_par_ecob = cmp_ent_get_non_ima_cmp_par5(ent);
+		cfg->spill_ecob = cmp_ent_get_non_ima_spill5(ent);
+		cfg->cmp_par_fx_cob_variance = cmp_ent_get_non_ima_cmp_par6(ent);
+		cfg->spill_fx_cob_variance = cmp_ent_get_non_ima_spill6(ent);
+		break;
+	case DATA_TYPE_F_CAM_OFFSET:
+	case DATA_TYPE_F_CAM_BACKGROUND:
+		/* TODO: fix this*/
+			return -1;
+		break;
+	case DATA_TYPE_UNKNOWN: /* fall through */
+	default:
 		return -1;
-	/* info->ap1_cmp_size_byte = cmp_ent_get_ap1_cmp_size_byte(ent); */
-	/* info->ap2_cmp_size_byte = cmp_ent_get_ap2_cmp_size_byte(ent); */
-	/* get ap1_spill and ap1/2 gpar*/
+	}
 
 	return 0;
 }
-#endif
 
 
-#if __has_include(<time.h>)
+#ifdef HAS_TIME_H
 /*
  * @brief Covert a calendar time expressed as a struct tm object to time since
  *	 epoch as a time_t object. The function interprets the input structure
  *	 as representing Universal Coordinated Time (UTC).
- * @note timegm is a GNU C Library extensions, not standardized. This function
+ * @note timegm is a GNU C Library extension, not standardized. This function
  *	is used as a portable alternative
  * @note The function is thread-unsafe
  *
@@ -2068,9 +2264,9 @@ int cmp_ent_read_adaptive_imagette_header(struct cmp_entity *ent, struct cmp_inf
 
 static time_t my_timegm(struct tm *tm)
 {
-#if defined(_WIN32) || defined(_WIN64)
+#  if defined(_WIN32) || defined(_WIN64)
 	return _mkgmtime(tm);
-#else
+#  else
 	time_t ret;
 	char *tz;
 
@@ -2087,14 +2283,14 @@ static time_t my_timegm(struct tm *tm)
 		unsetenv("TZ");
 	tzset();
 	return ret;
-#endif
+#  endif
 }
 
 
 /*
  * @brief Generate a timestamp for the compression header
  *
- * @param ts  pointer to object of type struct timespec of the timestamp time, null for now
+ * @param ts  pointer to an object of type struct timespec of the timestamp time, null for now
  *
  * @returns returns compression header timestamp or 0 on error
  */
@@ -2187,7 +2383,7 @@ void cmp_ent_print(struct cmp_entity *ent)
 
 
 /**
- * @brief parse the generic compressed entity header
+ * @brief parses the generic compressed entity header
  *
  * @param ent	pointer to a compression entity
  */
@@ -2195,16 +2391,17 @@ void cmp_ent_print(struct cmp_entity *ent)
 static void cmp_ent_parse_generic_header(struct cmp_entity *ent)
 {
 	uint32_t version_id, cmp_ent_size, original_size, cmp_mode_used,
-		 model_value_used, model_id, model_counter, lossy_cmp_par_used,
-		 start_coarse_time, end_coarse_time;
+		 model_value_used, model_id, model_counter, max_used_bits_version,
+		 lossy_cmp_par_used, start_coarse_time, end_coarse_time;
 	uint16_t start_fine_time, end_fine_time;
-	enum cmp_ent_data_type data_type;
+	enum cmp_data_type data_type;
 	int raw_bit;
 
 	version_id = cmp_ent_get_version_id(ent);
 	if (version_id & CMP_TOOL_VERSION_ID_BIT) {
 		uint16_t major = (version_id & 0x7FFF0000U) >> 16U;
 		uint16_t minor = version_id & 0xFFFFU;
+
 		printf("Compressed with cmp_tool version: %u.%02u\n", major, minor);
 	} else
 		printf("ICU ASW Version ID: %u\n", version_id);
@@ -2227,10 +2424,11 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent)
 	end_fine_time = cmp_ent_get_fine_end_time(ent);
 	printf("Compression Fine End Time: %d\n", end_fine_time);
 
-#if __has_include(<time.h>)
+#ifdef HAS_TIME_H
 	{
 		struct tm epoch_date = EPOCH_DATE;
 		time_t time = my_timegm(&epoch_date) + start_coarse_time;
+
 		printf("Data were compressed on (local time): %s", ctime(&time));
 	}
 #endif
@@ -2238,7 +2436,7 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent)
 		+ ((end_fine_time - start_fine_time)/256./256.));
 
 	data_type = cmp_ent_get_data_type(ent);
-	if (data_type != DATA_TYPE_UNKOWN)
+	if (data_type != DATA_TYPE_UNKNOWN)
 		printf("Data Product Type: %d\n", data_type);
 	else
 		printf("Data Product Type: unknown!");
@@ -2258,6 +2456,9 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent)
 	model_counter = cmp_ent_get_model_counter(ent);
 	printf("Model Counter: %u\n", model_counter);
 
+	max_used_bits_version = cmp_ent_get_max_use_bits_version(ent);
+	printf("Maximum Used Bits Registry Version: %u\n", max_used_bits_version);
+
 	lossy_cmp_par_used = cmp_ent_get_lossy_cmp_par(ent);
 	printf("Used Lossy Compression Parameters: %u\n", lossy_cmp_par_used);
 }
@@ -2320,17 +2521,26 @@ static void cmp_ent_parese_adaptive_imagette_header(struct cmp_entity *ent)
 
 static void cmp_ent_parese_specific_header(struct cmp_entity *ent)
 {
-	enum cmp_ent_data_type data_type = cmp_ent_get_data_type(ent);
+	enum cmp_data_type data_type = cmp_ent_get_data_type(ent);
+
+	if (cmp_ent_get_data_type_raw_bit(ent)) {
+		printf("Uncompressed data bit is set no specific header is used.\n");
+		return;
+	}
 
 	switch (data_type) {
 	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
 		cmp_ent_parese_imagette_header(ent);
 		break;
 	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
 		cmp_ent_parese_adaptive_imagette_header(ent);
 		break;
 	default:
-		printf("Data Product Type not supported!\n");
+		printf("For this data product type no parse functions is implemented!\n");
 		break;
 	}
 }
@@ -2348,3 +2558,4 @@ void cmp_ent_parse(struct cmp_entity *ent)
 
 	cmp_ent_parese_specific_header(ent);
 }
+
diff --git a/lib/cmp_guess.c b/lib/cmp_guess.c
index 265b9c58ad6fe6eca4111f2feffaa177e49b03fe..87aec6cd5824f7baa9cde955b9cb44f91fd6042f 100644
--- a/lib/cmp_guess.c
+++ b/lib/cmp_guess.c
@@ -15,14 +15,17 @@
  *
  * @brief helps the user to find a good compression parameters for a given
  *	dataset
+ * @warning this part of the software is not intended to run on-board on the ICU.
  */
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-#include "../include/cmp_icu.h"
-#include "../include/cmp_guess.h"
+#include "cmp_data_types.h"
+#include "cmp_icu.h"
+#include "cmp_guess.h"
 
 
 /* how often the model is updated before it is rested */
@@ -67,6 +70,43 @@ uint16_t cmp_guess_model_value(int n_model_updates)
 }
 
 
+/**
+ * @brief get a good spill threshold parameter for the selected Golomb parameter
+ *	and compression mode
+ *
+ * @param golomb_par	Golomb parameter
+ * @param cmp_mode	compression mode
+ *
+ * @returns a good spill parameter (optimal for zero escape mechanism)
+ * @warning icu compression not support yet!
+ */
+
+uint32_t cmp_rdcu_get_good_spill(unsigned int golomb_par, enum cmp_mode cmp_mode)
+{
+	const uint32_t LUT_IMA_MULIT[MAX_IMA_GOLOMB_PAR+1] = {0, 8, 16, 23,
+		30, 36, 44, 51, 58, 64, 71, 77, 84, 90, 97, 108, 115, 121, 128,
+		135, 141, 148, 155, 161, 168, 175, 181, 188, 194, 201, 207, 214,
+		229, 236, 242, 250, 256, 263, 269, 276, 283, 290, 296, 303, 310,
+		317, 324, 330, 336, 344, 351, 358, 363, 370, 377, 383, 391, 397,
+		405, 411, 418, 424, 431, 452 };
+
+	if (zero_escape_mech_is_used(cmp_mode))
+		return cmp_ima_max_spill(golomb_par);
+
+	if (cmp_mode == CMP_MODE_MODEL_MULTI) {
+		if (golomb_par > MAX_IMA_GOLOMB_PAR)
+			return 0;
+		else
+			return LUT_IMA_MULIT[golomb_par];
+	}
+
+	if (cmp_mode == CMP_MODE_DIFF_MULTI)
+		return CMP_GOOD_SPILL_DIFF_MULTI;
+
+	return 0;
+}
+
+
 /**
  * @brief guess a good configuration with pre_cal_method
  *
@@ -79,18 +119,17 @@ uint16_t cmp_guess_model_value(int n_model_updates)
 static uint32_t pre_cal_method(struct cmp_cfg *cfg)
 {
 	uint32_t g;
-	uint32_t cmp_size;
-	uint32_t cmp_size_best = ~0U;
+	int cmp_size, cmp_size_best = INT_MAX;
 	uint32_t golomb_par_best = 0;
 	uint32_t spill_best = 0;
 
-	for (g = MIN_RDCU_GOLOMB_PAR; g < MAX_RDCU_GOLOMB_PAR; g++) {
-		uint32_t s = cmp_get_good_spill(g, cfg->cmp_mode);
+	for (g = MIN_IMA_GOLOMB_PAR; g < MAX_IMA_GOLOMB_PAR; g++) {
+		uint32_t s = cmp_rdcu_get_good_spill(g, cfg->cmp_mode);
 
 		cfg->golomb_par = g;
 		cfg->spill = s;
-		cmp_size = cmp_encode_data(cfg);
-		if (cmp_size == 0) {
+		cmp_size = icu_compress_data(cfg);
+		if (cmp_size <= 0) {
 			return 0;
 		} else if (cmp_size < cmp_size_best) {
 			cmp_size_best = cmp_size;
@@ -120,8 +159,7 @@ static uint32_t brute_force(struct cmp_cfg *cfg)
 	uint32_t g, s;
 	uint32_t n_cal_steps = 0, last = 0;
 	const uint32_t max_cal_steps = CMP_GUESS_MAX_CAL_STEPS;
-	uint32_t cmp_size;
-	uint32_t cmp_size_best = ~0U;
+	int cmp_size, cmp_size_best = INT_MAX;
 	uint32_t golomb_par_best = 0;
 	uint32_t spill_best = 0;
 	uint32_t percent;
@@ -133,13 +171,13 @@ static uint32_t brute_force(struct cmp_cfg *cfg)
 	printf("0%%... ");
 	fflush(stdout);
 
-	for (g = MIN_RDCU_GOLOMB_PAR; g < MAX_RDCU_GOLOMB_PAR; g++) {
-		for (s = MIN_RDCU_SPILL; s < get_max_spill(g, cfg->cmp_mode); s++) {
+	for (g = MIN_IMA_GOLOMB_PAR; g < MAX_IMA_GOLOMB_PAR; g++) {
+		for (s = MIN_IMA_SPILL; s < cmp_ima_max_spill(g); s++) {
 			cfg->golomb_par = g;
 			cfg->spill = s;
 
-			cmp_size = cmp_encode_data(cfg);
-			if (cmp_size == 0) {
+			cmp_size = icu_compress_data(cfg);
+			if (cmp_size <= 0) {
 				return 0;
 			} else if (cmp_size < cmp_size_best) {
 				cmp_size_best = cmp_size;
@@ -173,11 +211,11 @@ static uint32_t brute_force(struct cmp_cfg *cfg)
 
 static void add_rdcu_pars_internal(struct cmp_cfg *cfg)
 {
-	if (cfg->golomb_par == MIN_RDCU_GOLOMB_PAR) {
+	if (cfg->golomb_par == MIN_IMA_GOLOMB_PAR) {
 		cfg->ap1_golomb_par = cfg->golomb_par + 1;
 		cfg->ap2_golomb_par = cfg->golomb_par + 2;
 
-	} else if (cfg->golomb_par == MAX_RDCU_GOLOMB_PAR) {
+	} else if (cfg->golomb_par == MAX_IMA_GOLOMB_PAR) {
 		cfg->ap1_golomb_par = cfg->golomb_par - 2;
 		cfg->ap2_golomb_par = cfg->golomb_par - 1;
 	} else {
@@ -185,19 +223,19 @@ static void add_rdcu_pars_internal(struct cmp_cfg *cfg)
 		cfg->ap2_golomb_par = cfg->golomb_par + 1;
 	}
 
-	cfg->ap1_spill = cmp_get_good_spill(cfg->ap1_golomb_par, cfg->cmp_mode);
-	cfg->ap2_spill = cmp_get_good_spill(cfg->ap2_golomb_par, cfg->cmp_mode);
+	cfg->ap1_spill = cmp_rdcu_get_good_spill(cfg->ap1_golomb_par, cfg->cmp_mode);
+	cfg->ap2_spill = cmp_rdcu_get_good_spill(cfg->ap2_golomb_par, cfg->cmp_mode);
 
 	if (model_mode_is_used(cfg->cmp_mode)) {
-		cfg->rdcu_data_adr = DEFAULT_CFG_MODEL.rdcu_data_adr;
-		cfg->rdcu_model_adr = DEFAULT_CFG_MODEL.rdcu_model_adr;
-		cfg->rdcu_new_model_adr = DEFAULT_CFG_MODEL.rdcu_new_model_adr;
-		cfg->rdcu_buffer_adr = DEFAULT_CFG_MODEL.rdcu_buffer_adr;
+		cfg->rdcu_data_adr = CMP_DEF_IMA_MODEL_RDCU_DATA_ADR;
+		cfg->rdcu_model_adr = CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR;
+		cfg->rdcu_new_model_adr = CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR;
+		cfg->rdcu_buffer_adr = CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR;
 	} else {
-		cfg->rdcu_data_adr = DEFAULT_CFG_DIFF.rdcu_data_adr;
-		cfg->rdcu_model_adr = DEFAULT_CFG_DIFF.rdcu_model_adr;
-		cfg->rdcu_new_model_adr = DEFAULT_CFG_DIFF.rdcu_new_model_adr;
-		cfg->rdcu_buffer_adr = DEFAULT_CFG_DIFF.rdcu_buffer_adr;
+		cfg->rdcu_data_adr = CMP_DEF_IMA_DIFF_RDCU_DATA_ADR;
+		cfg->rdcu_model_adr = CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR;
+		cfg->rdcu_new_model_adr = CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR;
+		cfg->rdcu_buffer_adr = CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR;
 	}
 }
 
@@ -220,7 +258,6 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level)
 {
 	size_t size;
 	struct cmp_cfg work_cfg;
-	int err;
 	uint32_t cmp_size = 0;
 
 	if (!cfg)
@@ -228,38 +265,28 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level)
 
 	if (!cfg->input_buf)
 		return 0;
+	if (model_mode_is_used(cfg->cmp_mode))
+		if (!cfg->model_buf)
+			return 0;
 
-	if (!rdcu_supported_mode_is_used(cfg->cmp_mode)) {
+	if (!rdcu_supported_cmp_mode_is_used(cfg->cmp_mode)) {
 		printf("This compression mode is not implied yet.\n");
 		return 0;
 	}
 	/* make a working copy of the input data (and model) because the
-	 * following function works inplace */
+	 * following function works inplace
+	 */
 	work_cfg = *cfg;
-	work_cfg.input_buf = NULL;
-	work_cfg.model_buf = NULL;
 	work_cfg.icu_new_model_buf = NULL;
 	work_cfg.icu_output_buf = NULL;
 	work_cfg.buffer_length = 0;
+	work_cfg.data_type = DATA_TYPE_IMAGETTE; /* TODO: adapt to others data types */
 
-	size = cfg->samples * size_of_a_sample(work_cfg.cmp_mode);
+	size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);
 	if (size == 0)
 		goto error;
-	work_cfg.input_buf = malloc(size);
-	if (!work_cfg.input_buf) {
-		printf("malloc() failed!\n");
-		goto error;
-	}
-	memcpy(work_cfg.input_buf, cfg->input_buf, size);
-
-	if (cfg->model_buf && model_mode_is_used(cfg->cmp_mode)) {
-		work_cfg.model_buf = malloc(size);
-		if (!work_cfg.model_buf) {
-			printf("malloc() failed!\n");
-			goto error;
-		}
-		memcpy(work_cfg.model_buf, cfg->model_buf, size);
 
+	if (model_mode_is_used(cfg->cmp_mode)) {
 		work_cfg.icu_new_model_buf = malloc(size);
 		if (!work_cfg.icu_new_model_buf) {
 			printf("malloc() failed!\n");
@@ -267,14 +294,6 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level)
 		}
 	}
 
-	err = cmp_pre_process(&work_cfg);
-	if (err)
-		goto error;
-
-	err = cmp_map_to_pos(&work_cfg);
-	if (err)
-		goto error;
-
 	/* find the best parameters */
 	switch (level) {
 	case 3:
@@ -294,8 +313,6 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level)
 	if (!cmp_size)
 		goto error;
 
-	free(work_cfg.input_buf);
-	free(work_cfg.model_buf);
 	free(work_cfg.icu_new_model_buf);
 
 	cfg->golomb_par = work_cfg.golomb_par;
@@ -303,16 +320,15 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level)
 
 	cfg->model_value = cmp_guess_model_value(num_model_updates);
 
-	if (rdcu_supported_mode_is_used(cfg->cmp_mode))
+	if (rdcu_supported_data_type_is_used(cfg->data_type))
 		add_rdcu_pars_internal(cfg);
 
-	cfg->buffer_length = ((cmp_size + 32)&~0x1FU)/(size_of_a_sample(work_cfg.cmp_mode)*8);
+	/* TODO: check that for non-imagette data */
+	cfg->buffer_length = ((cmp_size + 32)&~0x1FU)/(size_of_a_sample(cfg->data_type)*8);
 
 	return cmp_size;
 
 error:
-	free(work_cfg.input_buf);
-	free(work_cfg.model_buf);
 	free(work_cfg.icu_new_model_buf);
 	return 0;
 }
diff --git a/lib/cmp_icu.c b/lib/cmp_icu.c
index 5409045e74899ebcbfb49457b33458e559b5b4bb..79d1a64f075989c59700f5ceb865048635d64a04 100644
--- a/lib/cmp_icu.c
+++ b/lib/cmp_icu.c
@@ -15,1761 +15,2422 @@
  *
  * @brief software compression library
  * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ *
+ * To compress data, first create a compression configuration with the
+ * cmp_cfg_icu_create() function.
+ * Then set the different data buffers with the data to compressed, the model
+ * data and the compressed data with the cmp_cfg_icu_buffers() function.
+ * Then set the compression data type specific compression parameters. For
+ * imagette data use the cmp_cfg_icu_imagette() function. For flux and center of
+ * brightness data use the cmp_cfg_fx_cob() function. And for background, offset
+ * and smearing data use the cmp_cfg_aux() function.
+ * Finally, you can compress the data with the icu_compress_data() function.
  */
 
 
-#include <stdio.h>
 #include <stdint.h>
 #include <string.h>
 #include <limits.h>
 
-#include "../include/cmp_support.h"
-#include "../include/cmp_data_types.h"
-#include "../include/cmp_icu.h"
-#include "../include/byteorder.h"
-#include "../include/cmp_debug.h"
+#include <byteorder.h>
+#include <cmp_debug.h>
+#include <cmp_data_types.h>
+#include <cmp_support.h>
+#include <cmp_icu.h>
+#include <cmp_entity.h>
+
+
+/* maximum used bits registry */
+extern struct cmp_max_used_bits max_used_bits;
+
+
+/* pointer to a code word generation function */
+typedef uint32_t (*generate_cw_f_pt)(uint32_t value, uint32_t encoder_par1,
+				     uint32_t encoder_par2, uint32_t *cw);
+
+
+/* structure to hold a setup to encode a value */
+struct encoder_setupt {
+	generate_cw_f_pt generate_cw_f; /* pointer to the code word encoder */
+	int (*encode_method_f)(uint32_t data, uint32_t model, int stream_len,
+			       const struct encoder_setupt *setup); /* pointer to the encoding function */
+	uint32_t *bitstream_adr; /* start address of the compressed data bitstream */
+	uint32_t max_stream_len; /* maximum length of the bitstream/icu_output_buf in bits */
+	uint32_t encoder_par1; /* encoding parameter 1 */
+	uint32_t encoder_par2; /* encoding parameter 2 */
+	uint32_t spillover_par; /* outlier parameter */
+	uint32_t lossy_par; /* lossy compression parameter */
+	uint32_t max_data_bits; /* how many bits are needed to represent the highest possible value */
+};
 
 
 /**
- * @brief check if the compressor configuration is valid for a SW compression,
- *	see the user manual for more information (PLATO-UVIE-PL-UM-0001).
+ * @brief create an ICU compression configuration
  *
- * @param cfg	configuration contains all parameters required for compression
- * @param info	compressor information contains information of an executed
- *		compression (can be NULL)
+ * @param data_type	compression data product type
+ * @param cmp_mode	compression mode
+ * @param model_value	model weighting parameter (only needed for model compression mode)
+ * @param lossy_par	lossy rounding parameter (use CMP_LOSSLESS for lossless compression)
  *
- * @returns 0 when configuration is valid, invalid configuration otherwise
+ * @returns a compression configuration containing the chosen parameters;
+ *	on error the data_type record is set to DATA_TYPE_UNKNOWN
  */
 
-int icu_cmp_cfg_valid(const struct cmp_cfg *cfg, struct cmp_info *info)
+struct cmp_cfg cmp_cfg_icu_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode,
+				  uint32_t model_value, uint32_t lossy_par)
 {
-	int cfg_invalid = 0;
+	struct cmp_cfg cfg;
 
-	if (!cfg) {
-		debug_print("Error: compression configuration structure is NULL.\n");
-		return -1;
-	}
+	memset(&cfg, 0, sizeof(cfg));
 
-	if (!info)
-		debug_print("Warning: compressor information structure is NULL.\n");
+	cfg.data_type = data_type;
+	cfg.cmp_mode = cmp_mode;
+	cfg.model_value = model_value;
+	cfg.round = lossy_par;
 
-	if (info)
-		info->cmp_err = 0;  /* reset errors */
+	if (cmp_cfg_icu_gen_par_is_invalid(&cfg))
+		cfg.data_type = DATA_TYPE_UNKNOWN;
 
-	if (cfg->input_buf == NULL) {
-		debug_print("Error: The input_buf buffer for the data to be compressed is NULL.\n");
-		cfg_invalid++;
-	}
+	return cfg;
+}
 
-	if (cfg->samples == 0)
-		debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended.\n");
 
-	/* icu_output_buf can be NULL if rdcu compression is used */
-	if (cfg->icu_output_buf == NULL) {
-		debug_print("Error: The icu_output_buf buffer for the compressed data is NULL.\n");
-		cfg_invalid++;
-	}
+/**
+ * @brief setup the different data buffers for an ICU compression
+ *
+ * @param cfg			pointer to a compression configuration (created
+ *				with the cmp_cfg_icu_create() function)
+ * @param data_to_compress	pointer to the data to be compressed
+ * @param data_samples		length of the data to be compressed measured in
+ *				data samples/entitys (collection header not
+ *				included by imagette data)
+ * @param model_of_data		pointer to model data buffer (can be NULL if no
+ *				model compression mode is used)
+ * @param updated_model		pointer to store the updated model for the next
+ *				model mode compression (can be the same as the model_of_data
+ *				buffer for in-place update or NULL if updated model is not needed)
+ * @param compressed_data	pointer to the compressed data buffer (can be NULL)
+ * @param compressed_data_len_samples	length of the compressed_data buffer in
+ *					measured in the same units as the data_samples
+ *
+ * @returns the size of the compressed_data buffer on success; 0 if the
+ *	parameters are invalid
+ */
 
-	if (cfg->buffer_length == 0 && cfg->samples != 0) {
-		debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data.\n");
-		cfg_invalid++;
-	}
+uint32_t cmp_cfg_icu_buffers(struct cmp_cfg *cfg, void *data_to_compress,
+			     uint32_t data_samples, void *model_of_data,
+			     void *updated_model, uint32_t *compressed_data,
+			     uint32_t compressed_data_len_samples)
+{
+	uint32_t data_size, hdr_size;
 
-	if (cfg->icu_output_buf == cfg->input_buf) {
-		debug_print("Error: The icu_output_buf buffer is the same as the input_buf buffer.\n");
-		cfg_invalid++;
+	if (!cfg) {
+		debug_print("Error: pointer to the compression configuration structure is NULL.\n");
+		return 0;
 	}
 
-	if (model_mode_is_used(cfg->cmp_mode)) {
-		if (cfg->model_buf == NULL) {
-			debug_print("Error: The model_buf buffer for the model data is NULL.\n");
-			cfg_invalid++;
-		}
-
-		if (cfg->model_buf == cfg->input_buf) {
-			debug_print("Error: The model_buf buffer is the same as the input_buf buffer.\n");
-			cfg_invalid++;
-		}
-
-		if (cfg->model_buf == cfg->icu_output_buf) {
-			debug_print("Error: The model_buf buffer is the same as the icu_output_buf buffer.\n");
-			cfg_invalid++;
-		}
+	cfg->input_buf = data_to_compress;
+	cfg->model_buf = model_of_data;
+	cfg->samples = data_samples;
+	cfg->icu_new_model_buf = updated_model;
+	cfg->icu_output_buf = compressed_data;
+	cfg->buffer_length = compressed_data_len_samples;
 
-		if (cfg->icu_new_model_buf == cfg->input_buf) {
-			debug_print("Error: The icu_new_model_buf buffer is the same as the input_buf buffer.\n");
-			cfg_invalid++;
-		}
+	if (cmp_cfg_icu_buffers_is_invalid(cfg))
+		return 0;
 
-		if (cfg->icu_new_model_buf == cfg->icu_output_buf) {
-			debug_print("Error: The icu_output_buf buffer is the same as the icu_output_buf buffer.\n");
-			cfg_invalid++;
-		}
-	}
+	data_size = cmp_cal_size_of_data(compressed_data_len_samples, cfg->data_type);
+	hdr_size = cmp_ent_cal_hdr_size(cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW);
 
-	if (raw_mode_is_used(cfg->cmp_mode)) {
-		if (cfg->samples > cfg->buffer_length) {
-			debug_print("Error: The buffer_length is to small to hold the data form the input_buf.\n");
-			cfg_invalid++;
-		}
-	} else {
-		if (cfg->samples*size_of_a_sample(cfg->cmp_mode) <
-		    cfg->buffer_length*sizeof(uint16_t)/3) /* TODO: have samples and buffer_lengt the same unit */
-			debug_print("Warning: The size of the icu_output_buf is 3 times smaller than the input_buf. This is probably unintentional.\n");
+	if ((data_size + hdr_size) > CMP_ENTITY_MAX_SIZE) {
+		debug_print("Error: The buffer for the compressed data is too large to fit in a compression entity.\n");
+		return 0;
 	}
 
+	return data_size;
+}
 
-	if (!(diff_mode_is_used(cfg->cmp_mode)
-	     || model_mode_is_used(cfg->cmp_mode)
-	     || raw_mode_is_used(cfg->cmp_mode))) {
-		debug_print("Error: selected cmp_mode: %u is not supported\n.",
-			    cfg->cmp_mode);
-		if (info)
-			info->cmp_err |= 1UL << CMP_MODE_ERR_BIT;
-		cfg_invalid++;
-	}
 
-	if (raw_mode_is_used(cfg->cmp_mode)) /* additional checks are not needed for the raw mode */
-		return -cfg_invalid;
+/**
+ * @brief set up the configuration parameters for an ICU imagette compression
+ *
+ * @param cfg			pointer to a compression configuration (created
+ *				by the cmp_cfg_icu_create() function)
+ * @param cmp_par		imagette compression parameter (Golomb parameter)
+ * @param spillover_par		imagette spillover threshold parameter
+ *
+ * @returns 0 if parameters are valid, non-zero if parameters are invalid
+ */
 
-	if (model_mode_is_used(cfg->cmp_mode)) {
-		if (cfg->model_value > MAX_MODEL_VALUE) {
-			debug_print("Error: selected model_value: %u is invalid. Largest supported value is: %lu.\n",
-				    cfg->model_value, MAX_MODEL_VALUE);
-			if (info)
-				info->cmp_err |= 1UL << MODEL_VALUE_ERR_BIT;
-			cfg_invalid++;
-		}
-	}
+int cmp_cfg_icu_imagette(struct cmp_cfg *cfg, uint32_t cmp_par,
+			 uint32_t spillover_par)
+{
+	if (!cfg)
+		return -1;
 
-	if (cfg->golomb_par < MIN_ICU_GOLOMB_PAR ||
-	    cfg->golomb_par > MAX_ICU_GOLOMB_PAR) {
-		debug_print("Error: The selected Golomb parameter: %u is not supported. The Golomb parameter has to  be between [%lu, %u].\n",
-			    cfg->golomb_par, MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
-		if (info)
-			info->cmp_err |= 1UL << CMP_PAR_ERR_BIT;
-		cfg_invalid++;
-	}
+	cfg->golomb_par = cmp_par;
+	cfg->spill = spillover_par;
 
-	if (cfg->spill < MIN_ICU_SPILL) {
-		debug_print("Error: The selected spillover threshold value: %u is too small. Smallest possible spillover value is: %lu.\n",
-			    cfg->spill, MIN_ICU_SPILL);
-		if (info)
-			info->cmp_err |= 1UL << CMP_PAR_ERR_BIT;
-		cfg_invalid++;
-	}
+	if (cmp_cfg_imagette_is_invalid(cfg, ICU_CHECK))
+		return -1;
 
-	if (cfg->spill > get_max_spill(cfg->golomb_par, cfg->cmp_mode)) {
-		debug_print("Error: The selected spillover threshold value: %u is too large for the selected Golomb parameter: %u, the largest possible spillover value in the selected compression mode is: %u.\n",
-			    cfg->spill, cfg->golomb_par,
-			    get_max_spill(cfg->golomb_par, cfg->cmp_mode));
-		if (info)
-			info->cmp_err |= 1UL << CMP_PAR_ERR_BIT;
-		cfg_invalid++;
-	}
+	return 0;
+}
 
-#ifdef ADAPTIVE_CHECK_ENA
-	/*
-	 * ap1_spill and ap2_spill are not used for the icu_compression
-	 */
 
-	if (cfg->ap1_spill > get_max_spill(cfg->ap1_golomb_par, cfg->cmp_mode)) {
-		if (info)
-			info->cmp_err |= 1UL << AP1_CMP_PAR_ERR_BIT;
-		cfg_invalid++;
-	}
+/**
+ * @brief set up the configuration parameters for a flux/COB compression
+ * @note not all parameters are needed for every flux/COB compression data type
+ *
+ * @param cfg			pointer to a compression configuration (created
+ *				by the cmp_cfg_icu_create() function)
+ * @param cmp_par_exp_flags	exposure flags compression parameter
+ * @param spillover_exp_flags	exposure flags spillover threshold parameter
+ * @param cmp_par_fx		normal flux compression parameter
+ * @param spillover_fx		normal flux spillover threshold parameter
+ * @param cmp_par_ncob		normal center of brightness compression parameter
+ * @param spillover_ncob	normal center of brightness spillover threshold parameter
+ * @param cmp_par_efx		extended flux compression parameter
+ * @param spillover_efx		extended flux spillover threshold parameter
+ * @param cmp_par_ecob		extended center of brightness compression parameter
+ * @param spillover_ecob	extended center of brightness spillover threshold parameter
+ * @param cmp_par_fx_cob_variance	flux/COB variance compression parameter
+ * @param spillover_fx_cob_variance	flux/COB variance spillover threshold parameter
+ *
+ * @returns 0 if parameters are valid, non-zero if parameters are invalid
+ */
 
-	if (cfg->ap2_spill > get_max_spill(cfg->ap2_golomb_par, cfg->cmp_mode)) {
-		if (info)
-			info->cmp_err |= 1UL << AP2_CMP_PAR_ERR_BIT;
-		cfg_invalid++;
-	}
-#endif
+int cmp_cfg_fx_cob(struct cmp_cfg *cfg,
+		   uint32_t cmp_par_exp_flags, uint32_t spillover_exp_flags,
+		   uint32_t cmp_par_fx, uint32_t spillover_fx,
+		   uint32_t cmp_par_ncob, uint32_t spillover_ncob,
+		   uint32_t cmp_par_efx, uint32_t spillover_efx,
+		   uint32_t cmp_par_ecob, uint32_t spillover_ecob,
+		   uint32_t cmp_par_fx_cob_variance, uint32_t spillover_fx_cob_variance)
+{
+	if (!cfg)
+		return -1;
 
-	if (cfg->round > MAX_ICU_ROUND) {
-		debug_print("Error: selected round parameter: %u is not supported. Largest supported value is: %lu.\n",
-			    cfg->round, MAX_ICU_ROUND);
-		cfg_invalid++;
-	}
+	cfg->cmp_par_exp_flags = cmp_par_exp_flags;
+	cfg->cmp_par_fx = cmp_par_fx;
+	cfg->cmp_par_ncob = cmp_par_ncob;
+	cfg->cmp_par_efx = cmp_par_efx;
+	cfg->cmp_par_ecob = cmp_par_ecob;
+	cfg->cmp_par_fx_cob_variance = cmp_par_fx_cob_variance;
+
+	cfg->spill_exp_flags = spillover_exp_flags;
+	cfg->spill_fx = spillover_fx;
+	cfg->spill_ncob = spillover_ncob;
+	cfg->spill_efx = spillover_efx;
+	cfg->spill_ecob = spillover_ecob;
+	cfg->spill_fx_cob_variance = spillover_fx_cob_variance;
+
+	if (cmp_cfg_fx_cob_is_invalid(cfg))
+		return -1;
 
-	return -(cfg_invalid);
+	return 0;
 }
 
 
 /**
- * @brief sets the compression information used based on the compression
- *	configuration
- *
- * @param cfg	compression configuration struct
- * @param info	compressor information struct to set the used compression
- *	parameters (can be NULL)
- *
- * @note set cmp_size, ap1_cmp_size, ap2_cmp_size will be set to 0
- *
- * @returns 0 on success, error otherwise
+ * @brief set up the configuration parameters for an auxiliary science data compression
+ * @note auxiliary compression data types are: DATA_TYPE_OFFSET, DATA_TYPE_BACKGROUND,
+	DATA_TYPE_SMEARING, DATA_TYPE_F_CAM_OFFSET, DATA_TYPE_F_CAM_BACKGROUND
+ * @note not all parameters are needed for the every auxiliary compression data type
+ *
+ * @param cfg				pointer to a compression configuration (created
+ *					with the cmp_cfg_icu_create() function)
+ * @param cmp_par_mean			mean compression parameter
+ * @param spillover_mean		mean spillover threshold parameter
+ * @param cmp_par_variance		variance compression parameter
+ * @param spillover_variance		variance spillover threshold parameter
+ * @param cmp_par_pixels_error		outlier pixels number compression parameter
+ * @param spillover_pixels_error	outlier pixels number spillover threshold parameter
+ *
+ * @returns 0 if parameters are valid, non-zero if parameters are invalid
  */
 
-
-static int set_info(struct cmp_cfg *cfg, struct cmp_info *info)
+int cmp_cfg_aux(struct cmp_cfg *cfg,
+		uint32_t cmp_par_mean, uint32_t spillover_mean,
+		uint32_t cmp_par_variance, uint32_t spillover_variance,
+		uint32_t cmp_par_pixels_error, uint32_t spillover_pixels_error)
 {
 	if (!cfg)
 		return -1;
 
-	if (cfg->cmp_mode > UINT8_MAX)
-		return -1;
+	cfg->cmp_par_mean = cmp_par_mean;
+	cfg->cmp_par_variance = cmp_par_variance;
+	cfg->cmp_par_pixels_error = cmp_par_pixels_error;
 
-	if (cfg->round > UINT8_MAX)
-		return -1;
+	cfg->spill_mean = spillover_mean;
+	cfg->spill_variance = spillover_variance;
+	cfg->spill_pixels_error = spillover_pixels_error;
 
-	if (cfg->model_value > UINT8_MAX)
+	if (cmp_cfg_aux_is_invalid(cfg))
 		return -1;
 
-	if (info) {
-		info->cmp_err = 0;
-		info->cmp_mode_used = (uint8_t)cfg->cmp_mode;
-		info->model_value_used = (uint8_t)cfg->model_value;
-		info->round_used = (uint8_t)cfg->round;
-		info->spill_used = cfg->spill;
-		info->golomb_par_used = cfg->golomb_par;
-		info->samples_used = cfg->samples;
-		info->cmp_size = 0;
-		info->ap1_cmp_size = 0;
-		info->ap2_cmp_size = 0;
-		info->rdcu_new_model_adr_used = cfg->rdcu_new_model_adr;
-		info->rdcu_cmp_adr_used = cfg->rdcu_buffer_adr;
-	}
 	return 0;
 }
 
 
 /**
- * @brief 1d-differentiating pre-processing and rounding of a uint16_t data buffer
- *
- * @note change the data_buf in-place
- * @note output is I[0] = I[0], I[i] = I[i] - I[i-1], where i is 1,2,..samples-1
+ * @brief map a signed value into a positive value range
  *
- * @param data_buf	pointer to the uint16_t formatted data buffer to process
- * @param samples	amount of data samples in the data buffer
- * @param round		number of bits to round; if zero no rounding takes place
+ * @param value_to_map	signed value to map
+ * @param max_data_bits	how many bits are needed to represent the
+ *			highest possible value
  *
- * @returns 0 on success, error otherwise
+ * @returns the positive mapped value
  */
 
-static int diff_16(uint16_t *data_buf, unsigned int samples, unsigned int round)
+static uint32_t map_to_pos(uint32_t value_to_map, unsigned int max_data_bits)
 {
-	size_t i;
-
-	if (!data_buf)
-		return -1;
-
-	lossy_rounding_16(data_buf, samples, round);
-
-	for (i = samples - 1; i > 0; i--) {
-		/* possible underflow is intended */
-		data_buf[i] = data_buf[i] - data_buf[i-1];
+	uint32_t result;
+	uint32_t mask = (~0U >> (32 - max_data_bits)); /* mask the used bits */
+
+	value_to_map &= mask;
+	if (value_to_map >> (max_data_bits - 1)) { /* check the leading signed bit */
+		value_to_map |= ~mask; /* convert to 32-bit signed integer */
+		/* map negative values to uneven numbers */
+		result = (-value_to_map) * 2 - 1; /* possible integer overflow is intended */
+	} else {
+		/* map positive values to even numbers */
+		result = value_to_map * 2; /* possible integer overflow is intended */
 	}
-	return 0;
+
+	return result;
 }
 
 
 /**
- * @brief 1d-differentiating pre-processing and rounding of a uint32_t data buffer
- *
- * @note change the data_buf in-place
- * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index
- *
- * @param data_buf	pointer to the uint32_t formatted data buffer to process
- * @param samples	amount of data samples in the data_buf buffer
- * @param round		number of bits to round; if zero no rounding takes place
- *
- * @returns 0 on success, error otherwise
+ * @brief put the value of up to 32 bits into a bitstream
+ *
+ * @param value			the value to put
+ * @param n_bits		number of bits to put in the bitstream
+ * @param bit_offset		bit index where the bits will be put, seen from
+ *				the very beginning of the bitstream
+ * @param bitstream_adr		this is the pointer to the beginning of the
+ *				bitstream (can be NULL)
+ * @param max_stream_len	maximum length of the bitstream in bits; is
+ *				ignored if bitstream_adr is NULL
+ *
+ * @returns length in bits of the generated bitstream on success; returns
+ *          negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if
+ *          the bitstream buffer is too small to put the value in the bitstream
  */
 
-static int diff_32(uint32_t *data_buf, unsigned int samples, unsigned int round)
+static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset,
+			uint32_t *bitstream_adr, unsigned int max_stream_len)
 {
-	size_t i;
+	uint32_t *local_adr;
+	uint32_t mask;
+	unsigned int shiftRight, shiftLeft, bitsLeft, bitsRight;
+	int stream_len = (int)(n_bits + (unsigned int)bit_offset); /* overflow results in a negative return value */
 
-	if (!data_buf)
+	/* Leave in case of erroneous input */
+	if (bit_offset < 0)
 		return -1;
 
-	lossy_rounding_32(data_buf, samples, round);
+	if (n_bits == 0)
+		return stream_len;
 
-	for (i = samples - 1; i > 0; i--) {
-		/* possible underflow is intended */
-		data_buf[i] = data_buf[i] - data_buf[i-1];
+	if (n_bits > 32)
+		return -1;
+
+	/* Do we need to write data to the bitstream? */
+	if (!bitstream_adr)
+		return stream_len;
+
+	/* Check if bitstream buffer is large enough */
+	if ((unsigned int)stream_len > max_stream_len) {
+		debug_print("Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n");
+		return CMP_ERROR_SMALL_BUF;
 	}
-	return 0;
+
+	/* (M) is the n_bits parameter large enough to cover all value bits; the
+	 * calculations can be re-used in the unsegmented code, so we have no overhead
+	 */
+	shiftRight = 32 - n_bits;
+	mask = 0xFFFFFFFFU >> shiftRight;
+	value &= mask;
+
+	/* Separate the bit_offset into word offset (set local_adr pointer) and local bit offset (bitsLeft) */
+	local_adr = bitstream_adr + (bit_offset >> 5);
+	bitsLeft = bit_offset & 0x1F;
+
+	/* Calculate the bitsRight for the unsegmented case. If bitsRight is
+	 * negative we need to split the value over two words
+	 */
+	bitsRight = shiftRight - bitsLeft;
+
+	if ((int)bitsRight >= 0) {
+		/*         UNSEGMENTED
+		 *
+		 *|-----------|XXXXX|----------------|
+		 *   bitsLeft    n       bitsRight
+		 *
+		 *  -> to get the mask:
+		 *  shiftRight = bitsLeft + bitsRight = 32 - n
+		 *  shiftLeft = bitsRight = 32 - n - bitsLeft = shiftRight - bitsLeft
+		 */
+
+		shiftLeft = bitsRight;
+
+		/* generate the mask, the bits for the values will be true
+		 * shiftRight = 32 - n_bits; see (M) above!
+		 * mask = (0XFFFFFFFF >> shiftRight) << shiftLeft; see (M) above!
+		 */
+		mask <<= shiftLeft;
+		value <<= shiftLeft;
+
+		/* clear the destination with inverse mask */
+		*(local_adr) &= ~mask;
+
+		/* assign the value */
+		*(local_adr) |= value;
+
+	} else {
+		/*                             SEGMENTED
+		 *
+		 *|-----------------------------|XXX| |XX|------------------------------|
+		 *          bitsLeft              n1   n2          bitsRight
+		 *
+		 *  -> to get the mask part 1:
+		 *  shiftRight = bitsLeft
+		 *  n1 = n - (bitsLeft + n - 32) = 32 - bitsLeft
+		 *
+		 *  -> to get the mask part 2:
+		 *  n2 = bitsLeft + n - 32 = -(32 - n - bitsLeft) = -(bitsRight_UNSEGMENTED)
+		 *  shiftLeft = 32 - n2 = 32 - (bitsLeft + n - 32) = 64 - bitsLeft - n
+		 *
+		 */
+
+		unsigned int n2 = -bitsRight;
+
+		/* part 1: */
+		shiftRight = bitsLeft;
+		mask = 0XFFFFFFFFU >> shiftRight;
+
+		/* clear the destination with inverse mask */
+		*(local_adr) &= ~mask;
+
+		/* assign the value part 1 */
+		*(local_adr) |= (value >> n2);
+
+		/* part 2: */
+		/* adjust address */
+		local_adr += 1;
+		shiftLeft = 32 - n2;
+		mask = 0XFFFFFFFFU >> n2;
+
+		/* clear the destination */
+		*(local_adr) &= mask;
+
+		/* assign the value part 2 */
+		*(local_adr) |= (value << shiftLeft);
+	}
+	return stream_len;
 }
 
 
 /**
- * @brief 1d-differentiating pre-processing and round of a S_FX data buffer
- *
- * @note change the data_buf in-place
- * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index
+ * @brief forms the codeword according to the Rice code
  *
- * @param data		pointer to a S_FX data buffer
- * @param samples	amount of data samples in the data buffer
- * @param round		number of bits to round; if zero no rounding takes place
+ * @param value		value to be encoded
+ * @param m		Golomb parameter, only m's which are power of 2 are allowed
+ * @param log2_m	Rice parameter, is log_2(m) calculate outside function
+ *			for better performance
+ * @param cw		address were the encode code word is stored
  *
- * @returns 0 on success, error otherwise
+ * @returns the length of the formed code word in bits
+ * @note no check if the generated code word is not longer than 32 bits!
  */
 
-static int diff_S_FX(struct S_FX *data, unsigned int samples, unsigned int
-		     round)
+static uint32_t rice_encoder(uint32_t value, uint32_t m, uint32_t log2_m,
+			     uint32_t *cw)
 {
-	size_t i;
-	int err;
+	uint32_t g;  /* quotient of value/m */
+	uint32_t q;  /* quotient code without ending zero */
+	uint32_t r;  /* remainder of value/m */
+	uint32_t rl; /* remainder length */
 
-	if (!data)
-		return -1;
+	g = value >> log2_m; /* quotient, number of leading bits */
+	q = (1U << g) - 1;   /* prepare the quotient code without ending zero */
 
-	err = lossy_rounding_S_FX(data, samples, round);
-	if (err)
-		return err;
+	r = value & (m-1);   /* calculate the remainder */
+	rl = log2_m + 1;     /* length of the remainder (+1 for the 0 in the quotient code) */
+	*cw = (q << rl) | r; /* put the quotient and remainder code together */
+	/*
+	 * NOTE: If log2_m = 31 -> rl = 32, (q << rl) leads to an undefined
+	 * behavior. However, in this case, a valid code with a maximum of 32
+	 * bits can only be formed if q = 0. Any shift with 0 << x always
+	 * results in 0, which forms the correct codeword in this case. For
+	 * performance reasons, this undefined behaviour is not caught.
+	 */
 
-	for (i = samples - 1; i > 0; i--) {
-		/* possible underflow is intended */
-		data[i] = sub_S_FX(data[i], data[i-1]);
-	}
-	return 0;
+	return rl + g;	      /* calculate the length of the code word */
 }
 
 
 /**
- * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX data buffer
+ * @brief forms a codeword according to the Golomb code
  *
- * @note change the data_buf in-place
- * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index
- *
- * @param data		pointer to a S_FX_EFX data buffer
- * @param samples	amount of data samples in the data buffer
- * @param round		number of bits to round; if zero no rounding takes place
+ * @param value		value to be encoded
+ * @param m		Golomb parameter (have to be bigger than 0)
+ * @param log2_m	is log_2(m) calculate outside function for better
+ *			performance
+ * @param cw		address were the formed code word is stored
  *
- * @returns 0 on success, error otherwise
+ * @returns the length of the formed code word in bits
+ * @note no check if the generated code word is not longer than 32 bits!
  */
 
-static int diff_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples, unsigned
-			 int round)
+static uint32_t golomb_encoder(uint32_t value, uint32_t m, uint32_t log2_m,
+			       uint32_t *cw)
 {
-	size_t i;
-	int err;
-
-	if (!data)
-		return -1;
+	uint32_t len0, b, g, q, lg;
+	uint32_t len;
+	uint32_t cutoff;
 
-	err = lossy_rounding_S_FX_EFX(data, samples, round);
-	if (err)
-		return err;
+	len0 = log2_m + 1;                 /* codeword length in group 0 */
+	cutoff = (1U << (log2_m + 1)) - m; /* members in group 0 */
 
-	for (i = samples - 1; i > 0; i--) {
-		/* possible underflow is intended */
-		data[i] = sub_S_FX_EFX(data[i], data[i-1]);
+	if (value < cutoff) { /* group 0 */
+		*cw = value;
+		len = len0;
+	} else { /* other groups */
+		g = (value-cutoff) / m; /* this group is which one */
+		b = cutoff << 1;        /* form the base codeword */
+		lg = len0 + g;          /* it has lg remainder bits */
+		q = (1U << g) - 1;      /* prepare the left side in unary */
+		*cw = (q << (len0+1)) + b + (value-cutoff) - g*m; /* composed codeword */
+		len = lg + 1;           /* length of the codeword */
 	}
-	return 0;
+	return len;
 }
 
 
 /**
- * @brief 1d-differentiating pre-processing and rounding of a S_FX_NCOB data buffer
- *
- * @note change the data_buf in-place
- * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index
+ * @brief generate a code word without an outlier mechanism and put in the
+ *	bitstream
  *
- * @param data		pointer to a S_FX_NCOB data buffer
- * @param samples	amount of data samples in the data buffer
- * @param round		number of bits to round; if zero no rounding takes place
+ * @param value		value to encode in the bitstream
+ * @param stream_len	length of the bitstream in bits
+ * @param setup		pointer to the encoder setup
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream with the added encoded value on
+ *	success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer
+ *	is too small to put the value in the bitstream
  */
 
-static int diff_S_FX_NCOB(struct S_FX_NCOB *data, unsigned int samples, unsigned
-			  int round)
+static int encode_normal(uint32_t value, int stream_len,
+			 const struct encoder_setupt *setup)
 {
-	size_t i;
-	int err;
-
-	if (!data)
-		return -1;
+	uint32_t code_word, cw_len;
 
-	err = lossy_rounding_S_FX_NCOB(data, samples, round);
-	if (err)
-		return err;
+	cw_len = setup->generate_cw_f(value, setup->encoder_par1,
+				      setup->encoder_par2, &code_word);
 
-	for (i = samples - 1; i > 0; i--) {
-		/* possible underflow is intended */
-		data[i] = sub_S_FX_NCOB(data[i], data[i-1]);
-	}
-	return 0;
+	return put_n_bits32(code_word, cw_len, stream_len, setup->bitstream_adr,
+			    setup->max_stream_len);
 }
 
 
 /**
- * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX_NCOB_ECOB data buffer
+ * @brief subtract the model from the data, encode the result and put it into
+ *	bitstream, for encoding outlier use the zero escape symbol mechanism
  *
- * @note change the data_buf in-place
- * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index
+ * @param data		data to encode
+ * @param model		model of the data (0 if not used)
+ * @param stream_len	length of the bitstream in bits
+ * @param setup		pointer to the encoder setup
  *
- * @param data		pointer to a S_FX_EFX_NCOB_ECOB data buffer
- * @param samples	amount of data samples in the data buffer
- * @param round		number of bits to round; if zero no rounding takes place
+ * @returns the bit length of the bitstream with the added encoded value on
+ *	success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer
+ *	is too small to put the value in the bitstream
  *
- * @returns 0 on success, error otherwise
+ * @note no check if the data or model are in the allowed range
+ * @note no check if the setup->spillover_par is in the allowed range
  */
 
-static int diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data, unsigned int
-				   samples, unsigned int round)
+static int encode_value_zero(uint32_t data, uint32_t model, int stream_len,
+			     const struct encoder_setupt *setup)
 {
-	size_t i;
-	int err;
-
-	if (!data)
-		return -1;
+	data -= model; /* possible underflow is intended */
 
-	err = lossy_rounding_S_FX_EFX_NCOB_ECOB(data, samples, round);
-	if (err)
-		return err;
+	data = map_to_pos(data, setup->max_data_bits);
 
-	for (i = samples - 1; i > 0; i--) {
-		/* possible underflow is intended */
-		data[i] = sub_S_FX_EFX_NCOB_ECOB(data[i], data[i-1]);
+	/* For performance reasons, we check to see if there is an outlier
+	 * before adding one, rather than the other way around:
+	 * data++;
+	 * if (data < setup->spillover_par && data != 0)
+	 *	return ...
+	 */
+	if (data < (setup->spillover_par - 1)) { /* detect non-outlier */
+		data++; /* add 1 to every value so we can use 0 as escape symbol */
+		return encode_normal(data, stream_len, setup);
 	}
 
-	return 0;
+	data++; /* add 1 to every value so we can use 0 as escape symbol */
+
+	/* use zero as escape symbol */
+	stream_len = encode_normal(0, stream_len, setup);
+	if (stream_len <= 0)
+		return stream_len;
+
+	/* put the data unencoded in the bitstream */
+	stream_len = put_n_bits32(data, setup->max_data_bits, stream_len,
+				  setup->bitstream_adr, setup->max_stream_len);
+
+	return stream_len;
 }
 
 
 /**
- * @brief model pre-processing and rounding of a uint16_t data buffer
+ * @brief subtract the model from the data, encode the result and put it into
+ *	bitstream, for encoding outlier use the multi escape symbol mechanism
  *
- * @note overwrite the data_buf in-place with the result
- * @note update the model_buf in-place if up_model_buf = NULL
+ * @param data		data to encode
+ * @param model		model of the data (0 if not used)
+ * @param stream_len	length of the bitstream in bits
+ * @param setup		pointer to the encoder setup
  *
- * @param data_buf	pointer to the uint16_t data buffer to process
- * @param model_buf	pointer to the model buffer of the data to process
- * @param up_model_buf	pointer to the updated model buffer can be NULL
- * @param samples	amount of data samples in the data_buf and model_buf buffer
- * @param model_value	model weighting parameter
- * @param round		number of bits to round; if zero no rounding takes place
+ * @returns the bit length of the bitstream with the added encoded value on
+ *	success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer
+ *	is too small to put the value in the bitstream
  *
- * @returns 0 on success, error otherwise
+ * @note no check if the data or model are in the allowed range
+ * @note no check if the setup->spillover_par is in the allowed range
  */
 
-static int model_16(uint16_t *data_buf, uint16_t *model_buf, uint16_t *up_model_buf,
-		    unsigned int samples, unsigned int model_value, unsigned int round)
+static int encode_value_multi(uint32_t data, uint32_t model, int stream_len,
+			      const struct encoder_setupt *setup)
 {
-	size_t i;
+	uint32_t unencoded_data;
+	unsigned int unencoded_data_len;
+	uint32_t escape_sym, escape_sym_offset;
 
-	if (!data_buf)
-		return -1;
+	data -= model; /* possible underflow is intended */
 
-	if (!model_buf)
-		return -1;
+	data = map_to_pos(data, setup->max_data_bits);
 
-	if (model_value > MAX_MODEL_VALUE)
-		return -1;
+	if (data < setup->spillover_par) /* detect non-outlier */
+		return  encode_normal(data, stream_len, setup);
+
+	/*
+	 * In this mode we put the difference between the data and the spillover
+	 * threshold value (unencoded_data) after an encoded escape symbol, which
+	 * indicate that the next codeword is unencoded.
+	 * We use different escape symbol depended on the size the needed bit of
+	 * unencoded data:
+	 * 0, 1, 2 bits needed for unencoded data -> escape symbol is spillover_par + 0
+	 * 3, 4 bits needed for unencoded data -> escape symbol is spillover_par + 1
+	 * 5, 6 bits needed for unencoded data -> escape symbol is spillover_par + 2
+	 * and so on
+	 */
+	unencoded_data = data - setup->spillover_par;
 
-	if (!up_model_buf)
-		up_model_buf = model_buf;
+	if (!unencoded_data) /* catch __builtin_clz(0) because the result is undefined.*/
+		escape_sym_offset = 0;
+	else
+		escape_sym_offset = (31U - (uint32_t)__builtin_clz(unencoded_data)) >> 1;
 
-	for (i = 0; i < samples; i++) {
-		uint16_t round_input = (uint16_t)round_fwd(data_buf[i], round);
-		uint16_t round_model = (uint16_t)round_fwd(model_buf[i], round);
-		/* possible underflow is intended */
-		data_buf[i] = round_input - round_model; /* TDOO: check if this is the right order */
-		/* round back input because for decompression the accurate data
-		 * are not available
-		 */
-		up_model_buf[i] = (uint16_t)cal_up_model(round_inv(round_input, round),
-							 model_buf[i], model_value);
-	}
-	return 0;
+	escape_sym = setup->spillover_par + escape_sym_offset;
+	unencoded_data_len = (escape_sym_offset + 1U) << 1;
+
+	/* put the escape symbol in the bitstream */
+	stream_len = encode_normal(escape_sym, stream_len, setup);
+	if (stream_len <= 0)
+		return stream_len;
+
+	/* put the unencoded data in the bitstream */
+	stream_len = put_n_bits32(unencoded_data, unencoded_data_len, stream_len,
+				  setup->bitstream_adr, setup->max_stream_len);
+
+	return stream_len;
 }
 
 
 /**
- * @brief model pre-processing and round_input of a uint32_t data buffer
+ * @brief put the value unencoded with setup->cmp_par_1 bits without any changes
+ *	in the bitstream
  *
- * @note overwrite the data_buf in-place with the result
- * @note update the model_buf in-place if up_model_buf = NULL
+ * @param value		value to put unchanged in the bitstream
+ *	(setup->cmp_par_1 how many bits of the value are used)
+ * @param unused	this parameter is ignored
+ * @param stream_len	length of the bitstream in bits
+ * @param setup		pointer to the encoder setup
  *
- * @param data_buf	pointer to the uint32_t data buffer to process
- * @param model_buf	pointer to the model buffer of the data to process
- * @param samples	amount of data samples in the data_buf and model_buf buffer
- * @param model_value	model weighting parameter
- * @param round		number of bits to round; if zero no rounding takes place
+ * @returns the bit length of the bitstream with the added unencoded value on
+ *	success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer
+ *	is too small to put the value in the bitstream
  *
- * @returns 0 on success, error otherwise
  */
 
-static int model_32(uint32_t *data_buf, uint32_t *model_buf, unsigned int samples,
-		    unsigned int model_value, unsigned int round)
+static int encode_value_none(uint32_t value, uint32_t unused, int stream_len,
+			     const struct encoder_setupt *setup)
 {
-	size_t i;
+	(void)(unused);
 
-	if (!data_buf)
-		return -1;
+	return put_n_bits32(value, setup->encoder_par1, stream_len,
+			    setup->bitstream_adr, setup->max_stream_len);
+}
 
-	if (!model_buf)
-		return -1;
 
-	if (model_value > MAX_MODEL_VALUE)
-		return -1;
+/**
+ * @brief encodes the data with the model and the given setup and put it into
+ *	the bitstream
+ *
+ * @param data		data to encode
+ * @param model		model of the data (0 if not used)
+ * @param stream_len	length of the bitstream in bits
+ * @param setup		pointer to the encoder setup
+ *
+ * @returns the bit length of the bitstream with the added encoded value on
+ *	success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer
+ *	is too small to put the value in the bitstream, CMP_ERROR_HIGH_VALUE if
+ *	the value or the model is bigger than the max_used_bits parameter allows
+ */
 
-	for (i = 0; i < samples; i++) {
-		uint32_t round_input = round_fwd(data_buf[i], round);
-		uint32_t round_model = round_fwd(model_buf[i], round);
-		/* possible underflow is intended */
-		data_buf[i] = round_input - round_model;
-		/* round back input because for decompression the accurate data
-		 * are not available
-		 */
-		model_buf[i] = cal_up_model(round_inv(round_input, round),
-					    model_buf[i], model_value);
+static int encode_value(uint32_t data, uint32_t model, int stream_len,
+			const struct encoder_setupt *setup)
+{
+	uint32_t mask = ~(0xFFFFFFFFU >> (32-setup->max_data_bits));
+
+	/* lossy rounding of the data if lossy_par > 0 */
+	data = round_fwd(data, setup->lossy_par);
+	model = round_fwd(model, setup->lossy_par);
+
+	if (data & mask || model & mask) {
+		debug_print("Error: The data or the model of the data are bigger than expected.\n");
+		return CMP_ERROR_HIGH_VALUE;
 	}
-	return 0;
+
+	return setup->encode_method_f(data, model, stream_len, setup);
 }
 
 
 /**
- * @brief model pre-processing and round_input of a S_FX data buffer
+ * @brief calculate the maximum length of the bitstream/icu_output_buf in bits
+ * @note we round down to the next 4-byte allied address because we access the
+ *	cmp_buffer in uint32_t words
  *
- * @note overwrite the data_buf in-place with the result
- * @note update the model_buf in-place if up_model_buf = NULL
+ * @param buffer_length	length of the icu_output_buf in samples
+ * @param data_type	used compression data type
  *
- * @param data_buf	pointer to the S_FX data buffer to process
- * @param model_buf	pointer to the updated model buffer (if NULL model_buf
- *	will be overwrite with the updated model)
- * @param samples	amount of data samples in the data_buf and model_buf buffer
- * @param model_value	model weighting parameter
- * @param round		number of bits to round; if zero no rounding takes place
+ * @returns buffer size in bits
  *
- * @returns 0 on success, error otherwise
  */
 
-int model_S_FX(struct S_FX *data_buf, struct S_FX *model_buf,
-		      struct S_FX *up_model_buf, unsigned int samples,
-		      unsigned int model_value, unsigned int round)
+static uint32_t cmp_buffer_length_to_bits(uint32_t buffer_length, enum cmp_data_type data_type)
 {
-	size_t i;
+	return (cmp_cal_size_of_data(buffer_length, data_type) & ~0x3U) * CHAR_BIT;
+}
 
-	if (!samples)
-		return 0;
 
-	if (!model_buf)
+/**
+ * @brief configure an encoder setup structure to have a setup to encode a vale
+ *
+ * @param setup		pointer to the encoder setup
+ * @param cmp_par	compression parameter
+ * @param spillover	spillover_par parameter
+ * @param lossy_par	lossy compression parameter
+ * @param max_data_bits	how many bits are needed to represent the highest possible value
+ * @param cfg		pointer to the compression configuration structure
+ *
+ * @returns 0 on success; otherwise error
+ */
+
+static int configure_encoder_setup(struct encoder_setupt *setup,
+				   uint32_t cmp_par, uint32_t spillover,
+				   uint32_t lossy_par, uint32_t max_data_bits,
+				   const struct cmp_cfg *cfg)
+{
+	if (!setup)
 		return -1;
 
-	if (model_value > MAX_MODEL_VALUE)
+	if (!cfg)
 		return -1;
 
-	if (!up_model_buf)  /* overwrite the model buffer if no up_model_buf is set */
-		up_model_buf = model_buf;
+	if (max_data_bits > 32) {
+		debug_print("Error: max_data_bits parameter is bigger than 32 bits.\n");
+		return -1;
+	}
 
+	memset(setup, 0, sizeof(*setup));
 
-	for (i = 0; i < samples; i++) {
-		struct S_FX round_data = data_buf[i];
-		struct S_FX round_model = model_buf[i];
-		int err;
+	setup->encoder_par1 = cmp_par;
+	setup->max_data_bits = max_data_bits;
+	setup->lossy_par = lossy_par;
+	setup->bitstream_adr = cfg->icu_output_buf;
+	setup->max_stream_len = cmp_buffer_length_to_bits(cfg->buffer_length, cfg->data_type);
 
-		err = lossy_rounding_S_FX(&round_data, 1, round);
-		if (err)
-			return err;
+	if (cfg->cmp_mode != CMP_MODE_STUFF) {
+		if (ilog_2(cmp_par) < 0)
+			return -1;
+		setup->encoder_par2 = (uint32_t)ilog_2(cmp_par);
 
-		err = lossy_rounding_S_FX(&round_model, 1, round);
-		if (err)
-			return err;
+		setup->spillover_par = spillover;
 
-		/* possible underflow is intended */
-		data_buf[i] = sub_S_FX(round_data, round_model);
+		/* for encoder_par1 which are a power of two we can use the faster rice_encoder */
+		if (is_a_pow_of_2(setup->encoder_par1))
+			setup->generate_cw_f = &rice_encoder;
+		else
+			setup->generate_cw_f = &golomb_encoder;
+	}
 
-		/* round back input because for decompression the accurate data
-		 * are not available
-		 */
-		err = de_lossy_rounding_S_FX(&round_data, 1, round);
-		if (err)
-			return err;
-		up_model_buf[i] = cal_up_model_S_FX(round_data, model_buf[i],
-						    model_value);
+	switch (cfg->cmp_mode) {
+	case CMP_MODE_MODEL_ZERO:
+	case CMP_MODE_DIFF_ZERO:
+		setup->encode_method_f = &encode_value_zero;
+		break;
+	case CMP_MODE_MODEL_MULTI:
+	case CMP_MODE_DIFF_MULTI:
+		setup->encode_method_f = &encode_value_multi;
+		break;
+	case CMP_MODE_STUFF:
+		setup->encode_method_f = &encode_value_none;
+		setup->max_data_bits = cmp_par;
+		break;
+	case CMP_MODE_RAW:
+	default:
+		return -1;
 	}
 
+
 	return 0;
 }
 
 
 /**
- * @brief data pre-processing to decorrelate the data
+ * @brief compress imagette data
  *
- * @param cfg	configuration contains all parameters required for compression
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream, CMP_ERROR_HIGH_VALUE if the value or the model is
+ *	bigger than the max_used_bits parameter allows
  */
 
-int cmp_pre_process(struct cmp_cfg *cfg)
+static int compress_imagette(const struct cmp_cfg *cfg)
 {
-	if (!cfg)
-		return -1;
+	int err;
+	int stream_len = 0;
+	size_t i;
+	struct encoder_setupt setup;
 
-	if (cfg->samples == 0)
-		return 0;
+	uint16_t *data_buf = cfg->input_buf;
+	uint16_t *model_buf = cfg->model_buf;
+	uint16_t model = 0;
+	uint16_t *next_model_p = data_buf;
+	uint16_t *up_model_buf = NULL;
 
-	if (!cfg->input_buf)
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+		up_model_buf = cfg->icu_new_model_buf;
+	}
+
+	err = configure_encoder_setup(&setup, cfg->golomb_par, cfg->spill,
+				      cfg->round, max_used_bits.nc_imagette, cfg);
+	if (err)
 		return -1;
 
-	switch (cfg->cmp_mode) {
-	case MODE_RAW:
-	case MODE_RAW_S_FX:
-		return 0; /* in raw mode no pre-processing is necessary */
-		break;
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_MULTI:
-		return model_16((uint16_t *)cfg->input_buf, (uint16_t *)cfg->model_buf,
-				(uint16_t *)cfg->icu_new_model_buf, cfg->samples,
-				cfg->model_value, cfg->round);
-		break;
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_MULTI:
-		return diff_16((uint16_t *)cfg->input_buf, cfg->samples,
-			       cfg->round);
-		break;
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-		return model_S_FX((struct S_FX *)cfg->input_buf, (struct S_FX *)cfg->model_buf,
-				  (struct S_FX *)cfg->icu_new_model_buf, cfg->samples,
-				  cfg->model_value, cfg->round);
-		break;
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		return diff_S_FX((struct S_FX *)cfg->input_buf, cfg->samples, cfg->round);
-		break;
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		return diff_S_FX_EFX((struct S_FX_EFX *)cfg->input_buf,
-				     cfg->samples, cfg->round);
-		break;
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-		return diff_S_FX_NCOB((struct S_FX_NCOB *)cfg->input_buf,
-				      cfg->samples, cfg->round);
-		break;
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		return diff_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *)cfg->input_buf,
-					       cfg->samples, cfg->round);
-		break;
-	case MODE_MODEL_ZERO_32:
-	case MODE_MODEL_MULTI_32:
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-		return model_32((uint32_t *)cfg->input_buf, (uint32_t *)cfg->model_buf,
-				cfg->samples, cfg->model_value, cfg->round);
-		break;
-	case MODE_DIFF_ZERO_32:
-	case MODE_DIFF_MULTI_32:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		return diff_32((uint32_t *)cfg->input_buf, cfg->samples, cfg->round);
-		break;
-	default:
-		debug_print("Error: Compression mode not supported.\n");
-	}
-
-	return -1;
-}
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i], model, stream_len, &setup);
+		if (stream_len <= 0)
+			break;
 
+		if (up_model_buf)
+			up_model_buf[i] = cmp_up_model(data_buf[i], model, cfg->model_value,
+						       setup.lossy_par);
+		if (i >= cfg->samples-1)
+			break;
 
-static uint8_t map_to_pos_alg_8(int8_t value_to_map)
-{
-	if (value_to_map < 0)
-		/* NOTE: possible integer overflow is intended */
-		return (uint8_t)((-value_to_map) * 2 - 1);
-	else
-		/* NOTE: possible integer overflow is intended */
-		return (uint8_t)(value_to_map * 2);
+		model = next_model_p[i];
+	}
+	return stream_len;
 }
 
 
-static uint16_t map_to_pos_alg_16(int16_t value_to_map)
+/**
+ * @brief compress the multi-entry packet header structure and sets the data,
+ *	model and up_model pointers to the data after the header
+ *
+ * @param data			pointer to a pointer pointing to the data to be compressed
+ * @param model			pointer to a pointer pointing to the model of the data
+ * @param up_model		pointer to a pointer pointing to the updated model buffer
+ * @param compressed_data	pointer to the compressed data buffer
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *
+ * @note the (void **) cast relies on all pointer types having the same internal
+ *	representation which is common, but not universal; http://www.c-faq.com/ptrs/genericpp.html
+ */
+
+static int compress_multi_entry_hdr(void **data, void **model, void **up_model,
+				    void *compressed_data)
 {
-	if (value_to_map < 0)
-		/* NOTE: possible integer overflow is intended */
-		return (uint16_t)((-value_to_map) * 2 - 1);
-	else
-		/* NOTE: possible integer overflow is intended */
-		return (uint16_t)(value_to_map * 2);
-}
+	if (*up_model) {
+		if (*data)
+			memcpy(*up_model, *data, MULTI_ENTRY_HDR_SIZE);
+		*up_model = (uint8_t *)*up_model + MULTI_ENTRY_HDR_SIZE;
+	}
+
+	if (*data) {
+		if (compressed_data)
+			memcpy(compressed_data, *data, MULTI_ENTRY_HDR_SIZE);
+		*data = (uint8_t *)*data + MULTI_ENTRY_HDR_SIZE;
+	}
 
+	if (*model)
+		*model = (uint8_t *)*model + MULTI_ENTRY_HDR_SIZE;
 
-static uint32_t map_to_pos_alg_32(int32_t value_to_map)
-{
-	if (value_to_map < 0)
-		/* NOTE: possible integer overflow is intended */
-		return (uint32_t)((-value_to_map) * 2 - 1);
-	else
-		/* NOTE: possible integer overflow is intended */
-		return (uint32_t)(value_to_map * 2);
+	return MULTI_ENTRY_HDR_SIZE * CHAR_BIT;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range for a 16 bit buffer
- *
- * @note overwrite the data_buf in-place with the result
+ * @brief compress short normal light flux (S_FX) data
  *
- * @param data_buf	pointer to the uint16_t data buffer to process
- * @param samples	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static int map_to_pos_16(uint16_t *data_buf, uint32_t samples, int zero_mode_used)
+static int compress_s_fx(const struct cmp_cfg *cfg)
 {
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	if (!data_buf)
+	struct s_fx *data_buf = cfg->input_buf;
+	struct s_fx *model_buf = cfg->model_buf;
+	struct s_fx *up_model_buf = NULL;
+	struct s_fx *next_model_p;
+	struct s_fx model;
+	struct encoder_setupt setup_exp_flag, setup_fx;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.s_exp_flags, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.s_fx, cfg);
+	if (err)
 		return -1;
 
-	for (i = 0; i < samples; i++) {
-		data_buf[i] = map_to_pos_alg_16(data_buf[i]);
-		if (zero_mode_used)
-			data_buf[i] += 1;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range for a 32 bit buffer
- *
- * @note overwrite the data_buf in-place with the result
+ * @brief compress S_FX_EFX data
  *
- * @param data_buf	pointer to the uint32_t data buffer to process
- * @param samples	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static int map_to_pos_32(uint32_t *data_buf, uint32_t samples, int
-			 zero_mode_used)
+static int compress_s_fx_efx(const struct cmp_cfg *cfg)
 {
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	if (!data_buf)
+	struct s_fx_efx *data_buf = cfg->input_buf;
+	struct s_fx_efx *model_buf = cfg->model_buf;
+	struct s_fx_efx *up_model_buf = NULL;
+	struct s_fx_efx *next_model_p;
+	struct s_fx_efx model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_efx;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.s_exp_flags, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.s_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				      cfg->round, max_used_bits.s_efx, cfg);
+	if (err)
 		return -1;
 
-	for (i = 0; i < samples; i++) {
-		data_buf[i] = map_to_pos_alg_32(data_buf[i]);
-		if (zero_mode_used)
-			data_buf[i] += 1;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].efx, model.efx,
+					  stream_len, &setup_efx);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range for a S_FX buffer
- *
- * @note overwrite the data_buf in-place with the result
+ * @brief compress S_FX_NCOB data
  *
- * @param data_buf	pointer to the S_FX data buffer to process
- * @param samples	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-int map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples, int
-			   zero_mode_used)
+static int compress_s_fx_ncob(const struct cmp_cfg *cfg)
 {
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	if (!data_buf)
-		return -1;
+	struct s_fx_ncob *data_buf = cfg->input_buf;
+	struct s_fx_ncob *model_buf = cfg->model_buf;
+	struct s_fx_ncob *up_model_buf = NULL;
+	struct s_fx_ncob *next_model_p;
+	struct s_fx_ncob model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	for (i = 0; i < samples; i++) {
-		data_buf[i].EXPOSURE_FLAGS =
-			map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX);
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.s_exp_flags, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.s_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				      cfg->round, max_used_bits.s_ncob, cfg);
+	if (err)
+		return -1;
 
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS += 1; */
-			data_buf[i].FX += 1;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
 		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range for a S_FX_EFX buffer
- *
- * @note overwrite the data_buf in-place with the result
+ * @brief compress S_FX_EFX_NCOB_ECOB data
  *
- * @param data_buf	pointer to the S_FX_EFX data buffer to process
- * @param samples	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static int map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples, int
-			       zero_mode_used)
+static int compress_s_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
 {
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	if (!data_buf)
-		return -1;
+	struct s_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct s_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct s_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct s_fx_efx_ncob_ecob *next_model_p;
+	struct s_fx_efx_ncob_ecob model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob, setup_efx,
+			      setup_ecob;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
 
-	for (i = 0; i < samples; i++) {
-		data_buf[i].EXPOSURE_FLAGS =
-			map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX);
-		data_buf[i].EFX = map_to_pos_alg_32(data_buf[i].EFX);
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.s_exp_flags, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.s_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				      cfg->round, max_used_bits.s_ncob, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				      cfg->round, max_used_bits.s_efx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				      cfg->round, max_used_bits.s_ecob, cfg);
+	if (err)
+		return -1;
 
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS += 1; */
-			data_buf[i].FX += 1;
-			data_buf[i].EFX += 1;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].efx, model.efx,
+					  stream_len, &setup_efx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ecob_x, model.ecob_x,
+					  stream_len, &setup_ecob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ecob_y, model.ecob_y,
+					  stream_len, &setup_ecob);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+				cfg->model_value, setup_ecob.lossy_par);
 		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range for a S_FX_NCOB buffer
- *
- * @note overwrite the data_buf in-place with the result
+ * @brief compress F_FX data
  *
- * @param data_buf	pointer to the S_FX_NCOB data buffer to process
- * @param samples	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static int map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t samples,
-				int zero_mode_used)
+static int compress_f_fx(const struct cmp_cfg *cfg)
 {
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	if (!data_buf)
+	struct f_fx *data_buf = cfg->input_buf;
+	struct f_fx *model_buf = cfg->model_buf;
+	struct f_fx *up_model_buf = NULL;
+	struct f_fx *next_model_p;
+	struct f_fx model;
+	struct encoder_setupt setup_fx;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.f_fx, cfg);
+	if (err)
 		return -1;
 
-	for (i = 0; i < samples; i++) {
-		data_buf[i].EXPOSURE_FLAGS =
-			map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX);
-		data_buf[i].NCOB_X = map_to_pos_alg_32(data_buf[i].NCOB_X);
-		data_buf[i].NCOB_Y = map_to_pos_alg_32(data_buf[i].NCOB_Y);
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
 
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS += 1; */
-			data_buf[i].FX += 1;
-			data_buf[i].NCOB_X += 1;
-			data_buf[i].NCOB_Y += 1;
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
 		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range for a S_FX_EFX_NCOB_ECOB buffer
+ * @brief compress F_FX_EFX data
  *
- * @note overwrite the data_buf in-place with the result
+ * @param cfg	pointer to the compression configuration structure
  *
- * @param data_buf	pointer to the S_FX_EFX_NCOB_ECOB data buffer to process
- * @param samples	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
- *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static int map_to_pos_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-					 uint32_t samples, int zero_mode_used)
+static int compress_f_fx_efx(const struct cmp_cfg *cfg)
 {
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	if (!data_buf)
-		return -1;
-
-	for (i = 0; i < samples; i++) {
-		data_buf[i].EXPOSURE_FLAGS =
-			map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX);
-		data_buf[i].NCOB_X = map_to_pos_alg_32(data_buf[i].NCOB_X);
-		data_buf[i].NCOB_Y = map_to_pos_alg_32(data_buf[i].NCOB_Y);
-		data_buf[i].EFX = map_to_pos_alg_32(data_buf[i].EFX);
-		data_buf[i].ECOB_X = map_to_pos_alg_32(data_buf[i].ECOB_X);
-		data_buf[i].ECOB_Y = map_to_pos_alg_32(data_buf[i].ECOB_Y);
-
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS += 1; */
-			data_buf[i].FX += 1;
-			data_buf[i].NCOB_X += 1;
-			data_buf[i].NCOB_Y += 1;
-			data_buf[i].EFX += 1;
-			data_buf[i].ECOB_X += 1;
-			data_buf[i].ECOB_Y += 1;
+	struct f_fx_efx *data_buf = cfg->input_buf;
+	struct f_fx_efx *model_buf = cfg->model_buf;
+	struct f_fx_efx *up_model_buf = NULL;
+	struct f_fx_efx *next_model_p;
+	struct f_fx_efx model;
+	struct encoder_setupt setup_fx, setup_efx;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.f_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				      cfg->round, max_used_bits.f_efx, cfg);
+	if (err)
+		return -1;
+
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].efx, model.efx,
+					  stream_len, &setup_efx);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
 		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
 /**
- * @brief map the signed output of the pre-processing stage to a unsigned value
- *	range
- *
- * @note change the data_buf in-place
+ * @brief compress F_FX_NCOB data
  *
- * @param cfg	configuration contains all parameters required for compression
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-int cmp_map_to_pos(struct cmp_cfg *cfg)
+static int compress_f_fx_ncob(const struct cmp_cfg *cfg)
 {
-	int zero_mode_used;
+	int err;
+	int stream_len = 0;
+	size_t i;
 
-	if (!cfg)
-		return -1;
+	struct f_fx_ncob *data_buf = cfg->input_buf;
+	struct f_fx_ncob *model_buf = cfg->model_buf;
+	struct f_fx_ncob *up_model_buf = NULL;
+	struct f_fx_ncob *next_model_p;
+	struct f_fx_ncob model;
+	struct encoder_setupt setup_fx, setup_ncob;
 
-	if (cfg->samples == 0)
-		return 0;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!cfg->input_buf)
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.f_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				      cfg->round, max_used_bits.f_ncob, cfg);
+	if (err)
 		return -1;
 
-	zero_mode_used = zero_escape_mech_is_used(cfg->cmp_mode);
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+		}
 
-	switch (cfg->cmp_mode) {
-	case MODE_RAW:
-	case MODE_RAW_S_FX:
-		return 0; /* in raw mode no mapping is necessary */
-		break;
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_MULTI:
-		return map_to_pos_16((uint16_t *)cfg->input_buf, cfg->samples,
-				     zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		return map_to_pos_S_FX((struct S_FX *)cfg->input_buf,
-				       cfg->samples, zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		return map_to_pos_S_FX_EFX((struct S_FX_EFX *)cfg->input_buf,
-					   cfg->samples, zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-		return map_to_pos_S_FX_NCOB((struct S_FX_NCOB *)cfg->input_buf,
-					    cfg->samples, zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		return map_to_pos_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *)cfg->input_buf,
-						     cfg->samples, zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_32:
-	case MODE_MODEL_MULTI_32:
-	case MODE_DIFF_ZERO_32:
-	case MODE_DIFF_MULTI_32:
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		return map_to_pos_32((uint32_t *)cfg->input_buf, cfg->samples,
-				     zero_mode_used);
-		break;
-	default:
-		debug_print("Error: Compression mode not supported.\n");
-		break;
+		if (i >= cfg->samples-1)
+			break;
 
+		model = next_model_p[i];
 	}
-
-	return -1;
+	return stream_len;
 }
 
 
 /**
- * @brief forms the codeword accurate to the Rice code and returns its length
+ * @brief compress F_FX_EFX_NCOB_ECOB data
  *
- * @param m		Golomb parameter, only m's which are power of 2 and >0
- *			are allowed!
- * @param log2_m	Rice parameter, is log_2(m) calculate outside function
- *			for better performance
- * @param value		value to be encoded
- * @param cw		address were the encode code word is stored
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns length of the encoded code word in bits
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static unsigned int Rice_encoder(unsigned int value, unsigned int m,
-				 unsigned int log2_m, unsigned int *cw)
+static int compress_f_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
 {
-	unsigned int g;  /* quotient of value/m */
-	unsigned int q;  /* quotient code without ending zero */
-	unsigned int r;  /* remainder of value/m */
-	unsigned int rl; /* remainder length */
+	int err;
+	int stream_len = 0;
+	size_t i;
 
-	g = value >> log2_m; /* quotient, number of leading bits */
-	q = (1U << g) - 1;    /* prepare the quotient code without ending zero */
+	struct f_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct f_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct f_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct f_fx_efx_ncob_ecob *next_model_p;
+	struct f_fx_efx_ncob_ecob model;
+	struct encoder_setupt setup_fx, setup_ncob, setup_efx, setup_ecob;
 
-	r = value & (m-1);   /* calculate the remainder */
-	rl = log2_m + 1;     /* length of the remainder (+1 for the 0 in the
-			      * quotient code)
-			      */
-	*cw = (q << rl) | r; /* put the quotient and remainder code together */
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-	return rl + g;	      /* calculate the length of the code word */
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.f_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				      cfg->round, max_used_bits.f_ncob, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				      cfg->round, max_used_bits.f_efx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				      cfg->round, max_used_bits.f_ecob, cfg);
+	if (err)
+		return -1;
+
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].efx, model.efx,
+					  stream_len, &setup_efx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ecob_x, model.ecob_x,
+					  stream_len, &setup_ecob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ecob_y, model.ecob_y,
+					  stream_len, &setup_ecob);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+				cfg->model_value, setup_ecob.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_len;
 }
 
 
 /**
- * @brief forms the codeword accurate to the Golomb code and returns its length
+ * @brief compress L_FX data
  *
- * @param m		Golomb parameter, only m's which are power of 2 and >0
- *			are allowed!
- * @param log2_m	is log_2(m) calculate outside function for better
- *			performance
- * @param value		value to be encoded
- * @param cw		address were the encode code word is stored
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns length of the encoded code word in bits
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static unsigned int Golomb_encoder(unsigned int value, unsigned int m,
-				   unsigned int log2_m, unsigned int *cw)
+static int compress_l_fx(const struct cmp_cfg *cfg)
 {
-	unsigned int len0, b, g, q, lg;
-	unsigned int len;
-	unsigned int cutoff;
+	int err;
+	int stream_len = 0;
+	size_t i;
 
-	len0 = log2_m + 1; /* codeword length in group 0 */
-	cutoff = (1U << (log2_m+1)) - m; /* members in group 0 */
-	if (cutoff == 0) /* for powers of two we fix cutoff = m */
-		cutoff = m;
+	struct l_fx *data_buf = cfg->input_buf;
+	struct l_fx *model_buf = cfg->model_buf;
+	struct l_fx *up_model_buf = NULL;
+	struct l_fx *next_model_p;
+	struct l_fx model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_fx_var;
 
-	if (value < cutoff) { /* group 0 */
-		*cw = value;
-		len = len0;
-	} else { /* other groups */
-		b = (cutoff << 1); /* form the base codeword */
-		g = (value-cutoff)/m; /* this group is which one  */
-		lg = len0 + g; /* it has lg remainder bits */
-		q = (1U << g) - 1; /* prepare the left side in unary */
-		*cw = (q << (len0+1)) + b + (value-cutoff)-g*m; /* composed codeword */
-		len = lg + 1; /* length of the codeword */
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
 	}
-	return len;
-}
 
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.l_exp_flags, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.l_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				      cfg->round, max_used_bits.l_fx_variance, cfg);
+	if (err)
+		return -1;
 
-typedef unsigned int (*encoder_ptr)(unsigned int, unsigned int, unsigned int,
-				    unsigned int*);
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance,
+					  stream_len, &setup_fx_var);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+		}
 
-static encoder_ptr select_encoder(unsigned int golomb_par)
-{
-	if (!golomb_par)
-		return NULL;
+		if (i >= cfg->samples-1)
+			break;
 
-	if (is_a_pow_of_2(golomb_par))
-		return &Rice_encoder;
-	else
-		return &Golomb_encoder;
+		model = next_model_p[i];
+	}
+	return stream_len;
 }
 
 
 /**
- * @brief    safe (but slow) way to put the value of up to 32 bits into a
- *           bitstream accessed as 32-bit RAM in big endian
- * @param    value      the value to put, it will be masked
- * @param    bitOffset  bit index where the bits will be put, seen from the very
- *			beginning of the bitstream
- * @param    nBits      number of bits to put in the bitstream
- * @param    destAddr   this is the pointer to the beginning of the bitstream
- * @param    dest_len   length of the bitstream buffer (starting at destAddr)
- * @returns  TODO number of bits written, 0 if the number was too big, -2 if the
- *	     destAddr buffer is to small to store the bitstream
- * @note     works in SRAM2
+ * @brief compress L_FX_EFX data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
  */
 
-static unsigned int put_n_bits32(unsigned int value, unsigned int bitOffset,
-				 unsigned int nBits, unsigned int *destAddr,
-				 unsigned int dest_len)
+static int compress_l_fx_efx(const struct cmp_cfg *cfg)
 {
-	unsigned int *localAddr;
-	unsigned int bitsLeft, shiftRight, shiftLeft, localEndPos;
-	unsigned int mask;
+	int err;
+	int stream_len = 0;
+	size_t i;
 
-	if (!destAddr)
-		return nBits;
+	struct l_fx_efx *data_buf = cfg->input_buf;
+	struct l_fx_efx *model_buf = cfg->model_buf;
+	struct l_fx_efx *up_model_buf = NULL;
+	struct l_fx_efx *next_model_p;
+	struct l_fx_efx model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_efx, setup_fx_var;
 
-	/* check if destination buffer is large enough */
-	/* TODO: adapt that to the other science products */
-	if ((bitOffset + nBits) > ((dest_len&~0x1U)*16)) {
-		debug_print("Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n");
-		return -2U;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
 	}
 
-	/* leave in case of erroneous input */
-	if (nBits == 0)
-		return 0;
-	if (nBits > 32)
-		return 0;
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.l_exp_flags, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.l_fx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				      cfg->round, max_used_bits.l_efx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				      cfg->round, max_used_bits.l_fx_variance, cfg);
+	if (err)
+		return -1;
 
-	/* separate the bitOffset into word offset (set localAddr pointer) and local bit offset (bitsLeft) */
-	localAddr = destAddr + (bitOffset >> 5);
-	bitsLeft = bitOffset & 0x1f;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].efx, model.efx,
+					  stream_len, &setup_efx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance,
+					  stream_len, &setup_fx_var);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+		}
 
-	/* (M) we mask the value first to match its size in nBits */
-	/* the calculations can be re-used in the unsegmented code, so we have no overhead */
-	shiftRight = 32 - nBits;
-	mask = 0xffffffff >> shiftRight;
-	value &= mask;
+		if (i >= cfg->samples-1)
+			break;
 
-	/* to see if we need to split the value over two words we need the right end position */
-	localEndPos = bitsLeft + nBits;
+		model = next_model_p[i];
+	}
+	return stream_len;
+}
 
-	if (localEndPos <= 32) {
-		/*         UNSEGMENTED
-		 *
-		 *|-----------|XXXXX|----------------|
-		 *   bitsLeft    n       bitsRight
-		 *
-		 *  -> to get the mask:
-		 *  shiftRight = bitsLeft + bitsRight = 32 - n
-		 *  shiftLeft = bitsRight
-		 *
-		 */
 
-		/* shiftRight = 32 - nBits; */ /* see (M) above! */
-		shiftLeft = shiftRight - bitsLeft;
+/**
+ * @brief compress L_FX_NCOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
 
-		/* generate the mask, the bits for the values will be true */
-		/* mask = (0xffffffff >> shiftRight) << shiftLeft; */ /* see (M) above! */
-		mask <<= shiftLeft;
+static int compress_l_fx_ncob(const struct cmp_cfg *cfg)
+{
+	int err;
+	int stream_len = 0;
+	size_t i;
 
-		/* clear the destination with inverse mask */
-		*(localAddr) &= ~mask;
+	struct l_fx_ncob *data_buf = cfg->input_buf;
+	struct l_fx_ncob *model_buf = cfg->model_buf;
+	struct l_fx_ncob *up_model_buf = NULL;
+	struct l_fx_ncob *next_model_p;
+	struct l_fx_ncob model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob,
+			      setup_fx_var, setup_cob_var;
 
-		/* assign the value */
-		*(localAddr) |= (value << (32 - localEndPos)); /* NOTE: 32-localEndPos = shiftLeft can be simplified */
-
-	} else {
-		/*                             SEGMENTED
-		 *
-		 *|-----------------------------|XXX| |XX|------------------------------|
-		 *          bitsLeft              n1   n2          bitsRight
-		 *
-		 *  -> to get the mask part 1:
-		 *  shiftright = bitsleft
-		 *  n1 = n - (bitsleft + n - 32) = 32 - bitsleft
-		 *
-		 *  -> to get the mask part 2:
-		 *  n2 = bitsleft + n - 32
-		 *  shiftleft = 32 - n2 = 32 - (bitsleft + n - 32) = 64 - bitsleft - n
-		 *
-		 */
-
-		unsigned int n2 = bitsLeft + nBits - 32;
-
-		/* part 1: */
-		shiftRight = bitsLeft;
-		mask = 0xffffffff >> shiftRight;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-		/* clear the destination with inverse mask */
-		*(localAddr) &= ~mask;
-
-		/* assign the value part 1 */
-		*(localAddr) |= (value >> n2);
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
 
-		/* part 2: */
-		/* adjust address */
-		localAddr += 1;
-		shiftLeft = 64 - bitsLeft - nBits;
-		mask = 0xffffffff << shiftLeft;
-
-		/* clear the destination with inverse mask */
-		*(localAddr) &= ~mask;
-
-		/* assign the value part 2 */
-		*(localAddr) |= (value << (32 - n2));
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
 	}
-	return nBits;
-}
-
-
-struct encoder_struct {
-	encoder_ptr encoder;
-	unsigned int log2_golomb_par; /* pre-calculated for performance increase */
-	uint32_t cmp_size; /* Compressed data size; measured in bits */
-};
-
-
-static int encode_raw(struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	size_t cmp_size_in_bytes;
 
-	if (!cfg)
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.l_exp_flags, cfg);
+	if (err)
 		return -1;
-
-	if (!cfg->icu_output_buf)
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.l_fx, cfg);
+	if (err)
 		return -1;
-
-	if (!cfg->input_buf)
+	err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				      cfg->round, max_used_bits.l_ncob, cfg);
+	if (err)
 		return -1;
-
-	cmp_size_in_bytes = cfg->samples * size_of_a_sample(cfg->cmp_mode);
-
-	enc->cmp_size = cmp_size_in_bytes * CHAR_BIT; /* cmp_size is measured in bits */
-
-	if (cmp_size_in_bytes > cfg->buffer_length * sizeof(uint16_t))
+	/* we use compression parameter for both variance data fields */
+	err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				      cfg->round, max_used_bits.l_fx_variance, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				      cfg->round, max_used_bits.l_cob_variance, cfg);
+	if (err)
 		return -1;
 
-	memcpy(cfg->icu_output_buf, cfg->input_buf, cmp_size_in_bytes);
-
-	return 0;
-}
-
-
-static int encode_raw_16(struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	int err;
-	size_t i;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance,
+					  stream_len, &setup_fx_var);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].cob_x_variance, model.cob_x_variance,
+					  stream_len, &setup_cob_var);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].cob_y_variance, model.cob_y_variance,
+					  stream_len, &setup_cob_var);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+			up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+			up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+		}
 
-	enc->cmp_size = 0;
+		if (i >= cfg->samples-1)
+			break;
 
-	for (i = 0; i < cfg->samples; i++) {
-		uint16_t *p = cfg->input_buf;
-		err = put_n_bits32(p[i], enc->cmp_size, 16, cfg->icu_output_buf,
-				   cfg->buffer_length);
-		if (err <= 0)
-			return err;
-		enc->cmp_size += 16;
+		model = next_model_p[i];
 	}
-
-	return 0;
+	return stream_len;
 }
 
 
-static int encode_raw_S_FX(struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	int err;
-
-	err = encode_raw(cfg, enc);
-	if (err)
-		return err;
-
-#if defined(__LITTLE_ENDIAN)
-	{
-		size_t i;
-		for (i = 0; i < cfg->samples; i++) {
-			struct S_FX *output_buf = (void *)cfg->icu_output_buf;
-			output_buf[i].FX = cpu_to_be32(output_buf[i].FX);
-		}
-	}
-#endif
-	return 0;
-}
-
+/**
+ * @brief compress L_FX_EFX_NCOB_ECOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
 
-static int encode_normal(uint32_t value_to_encode, struct cmp_cfg *cfg,
-			 struct encoder_struct *enc)
+static int compress_l_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
 {
-	unsigned int code_word;
-	unsigned int cw_len;
 	int err;
+	int stream_len = 0;
+	size_t i;
 
-	if (!enc->encoder)
-		return -1;
-
-	cw_len = enc->encoder(value_to_encode, cfg->golomb_par,
-			      enc->log2_golomb_par, &code_word);
+	struct l_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct l_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct l_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct l_fx_efx_ncob_ecob *next_model_p;
+	struct l_fx_efx_ncob_ecob model;
+	struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob, setup_efx,
+			      setup_ecob, setup_fx_var, setup_cob_var;
 
-	err = put_n_bits32(code_word, enc->cmp_size, cw_len,
-			   cfg->icu_output_buf, cfg->buffer_length);
-	if (err <= 0)
-		return err;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-	enc->cmp_size += cw_len;
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
 
-	return 0;
-}
-
-
-static int encode_outlier_zero(uint32_t value_to_encode, int max_bits,
-			       struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	int err;
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (max_bits > 32)
+	err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				      cfg->round, max_used_bits.l_exp_flags, cfg);
+	if (err)
 		return -1;
-
-	/* use zero as escape symbol */
-	err = encode_normal(0, cfg, enc);
+	err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				      cfg->round, max_used_bits.l_fx, cfg);
 	if (err)
-		return err;
+		return -1;
+	err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				      cfg->round, max_used_bits.l_ncob, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				      cfg->round, max_used_bits.l_efx, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				      cfg->round, max_used_bits.l_ecob, cfg);
+	if (err)
+		return -1;
+	/* we use compression parameter for both variance data fields */
+	err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				      cfg->round, max_used_bits.l_fx_variance, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				      cfg->round, max_used_bits.l_cob_variance, cfg);
+	if (err)
+		return -1;
 
-	/* put the data unencoded in the bitstream */
-	err = put_n_bits32(value_to_encode, enc->cmp_size, max_bits,
-			   cfg->icu_output_buf, cfg->buffer_length);
-	if (err <= 0)
-		return err;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags,
+					  stream_len, &setup_exp_flag);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx, model.fx, stream_len,
+					  &setup_fx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y,
+					  stream_len, &setup_ncob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].efx, model.efx,
+					  stream_len, &setup_efx);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ecob_x, model.ecob_x,
+					  stream_len, &setup_ecob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].ecob_y, model.ecob_y,
+					  stream_len, &setup_ecob);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance,
+					  stream_len, &setup_fx_var);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].cob_x_variance, model.cob_x_variance,
+					  stream_len, &setup_cob_var);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].cob_y_variance, model.cob_y_variance,
+					  stream_len, &setup_cob_var);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flag.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+			up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+			up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+		}
 
-	enc->cmp_size += max_bits;
+		if (i >= cfg->samples-1)
+			break;
 
-	return 0;
+		model = next_model_p[i];
+	}
+	return stream_len;
 }
 
 
-static int cal_multi_offset(unsigned int unencoded_data)
-{
-	if (unencoded_data <= 0x3)
-		return 0;
-	if (unencoded_data <= 0xF)
-		return 1;
-	if (unencoded_data <= 0x3F)
-		return 2;
-	if (unencoded_data <= 0xFF)
-		return 3;
-	if (unencoded_data <= 0x3FF)
-		return 4;
-	if (unencoded_data <= 0xFFF)
-		return 5;
-	if (unencoded_data <= 0x3FFF)
-		return 6;
-	if (unencoded_data <= 0xFFFF)
-		return 7;
-	if (unencoded_data <= 0x3FFFF)
-		return 8;
-	if (unencoded_data <= 0xFFFFF)
-		return 9;
-	if (unencoded_data <= 0x3FFFFF)
-		return 10;
-	if (unencoded_data <= 0xFFFFFF)
-		return 11;
-	if (unencoded_data <= 0x3FFFFFF)
-		return 12;
-	if (unencoded_data <= 0xFFFFFFF)
-		return 13;
-	if (unencoded_data <= 0x3FFFFFFF)
-		return 14;
-	else
-		return 15;
-}
-
+/**
+ * @brief compress offset data from the normal cameras
+ *
+ * @param cfg	pointer to the compression configuration structure
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
 
-static int encode_outlier_multi(uint32_t value_to_encode, struct cmp_cfg *cfg,
-				struct encoder_struct *enc)
+static int compress_nc_offset(const struct cmp_cfg *cfg)
 {
-	uint32_t unencoded_data;
-	unsigned int unencoded_data_len;
-	uint32_t escape_sym;
-	int escape_sym_offset;
 	int err;
+	int stream_len = 0;
+	size_t i;
 
-	/*
-	 * In this mode we put the difference between the data and the spillover
-	 * threshold value (unencoded_data) after a encoded escape symbol, which
-	 * indicate that the next codeword is unencoded.
-	 * We use different escape symbol depended on the size the needed bit of
-	 * unencoded data:
-	 * 0, 1, 2 bits needed for unencoded data -> escape symbol is spill + 0
-	 * 3, 4 bits needed for unencoded data -> escape symbol is spill + 1
-	 * ..
-	 */
-
-	unencoded_data = value_to_encode - cfg->spill;
-	escape_sym_offset = cal_multi_offset(unencoded_data);
-	escape_sym  = cfg->spill + escape_sym_offset;
-	unencoded_data_len = (escape_sym_offset + 1) * 2;
-
-	/* put the escape symbol in the bitstream */
-	err = encode_normal(escape_sym, cfg, enc);
-	if (err)
-		return err;
-
-	/* put the unencoded data in the bitstream */
-	err = put_n_bits32(unencoded_data, enc->cmp_size, unencoded_data_len,
-			   cfg->icu_output_buf, cfg->buffer_length);
-	if (err <= 0)
-		return err;
-
-	enc->cmp_size += unencoded_data_len;
-
-	return 0;
-}
-
-static int encode_outlier(uint32_t value_to_encode, int bit_len, struct cmp_cfg
-			  *cfg, struct encoder_struct *enc)
-{
-	if (multi_escape_mech_is_used(cfg->cmp_mode))
-		return encode_outlier_multi(value_to_encode, cfg, enc);
-
-	if (zero_escape_mech_is_used(cfg->cmp_mode))
-		return encode_outlier_zero(value_to_encode, bit_len, cfg, enc);
-
-	return -1;
-}
-
+	struct nc_offset *data_buf = cfg->input_buf;
+	struct nc_offset *model_buf = cfg->model_buf;
+	struct nc_offset *up_model_buf = NULL;
+	struct nc_offset *next_model_p;
+	struct nc_offset model;
+	struct encoder_setupt setup_mean, setup_var;
 
-int encode_value(uint32_t value_to_encode, int bit_len, struct cmp_cfg *cfg,
-		 struct encoder_struct *enc)
-{
-	/* 0 is an outlier in case of a zero-escape mechanism, because an
-	 * overflow can occur by incrementing by one
-	 */
-	if (value_to_encode >= cfg->spill ||
-	    (zero_escape_mech_is_used(cfg->cmp_mode) && value_to_encode == 0))
-		return encode_outlier(value_to_encode, bit_len, cfg, enc);
-	else
-		return encode_normal(value_to_encode, cfg, enc);
-}
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
 
-static int encode_16(struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	size_t i;
-	uint16_t *data_to_encode;
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!cfg)
+	err = configure_encoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				      cfg->round, max_used_bits.nc_offset_mean, cfg);
+	if (err)
 		return -1;
-
-	if (!enc)
+	err = configure_encoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				      cfg->round, max_used_bits.nc_offset_variance, cfg);
+	if (err)
 		return -1;
 
-	data_to_encode = cfg->input_buf;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].mean, model.mean,
+					  stream_len, &setup_mean);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].variance, model.variance,
+					  stream_len, &setup_var);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, model.mean,
+				cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance = cmp_up_model(data_buf[i].variance, model.variance,
+				cfg->model_value, setup_var.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
 
-	for (i = 0; i < cfg->samples; i++) {
-		int err = encode_value(data_to_encode[i], 16, cfg, enc);
-		if (err)
-			return err;
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
-static int encode_32(struct cmp_cfg *cfg, struct encoder_struct *enc)
+/**
+ * @brief compress background data from the normal cameras
+ *
+ * @param cfg	pointer to the compression configuration structure
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int compress_nc_background(const struct cmp_cfg *cfg)
 {
-	uint32_t *data_to_encode = cfg->input_buf;
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	for (i = 0; i < cfg->samples; i++) {
-		int err = encode_value(data_to_encode[i], 32, cfg, enc);
-		if (err)
-			return err;
-	}
-	return 0;
-}
+	struct nc_background *data_buf = cfg->input_buf;
+	struct nc_background *model_buf = cfg->model_buf;
+	struct nc_background *up_model_buf = NULL;
+	struct nc_background *next_model_p;
+	struct nc_background model;
+	struct encoder_setupt setup_mean, setup_var, setup_pix;
 
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-static int encode_S_FX(struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	struct S_FX *data_to_encode = cfg->input_buf;
-	size_t i;
-	struct cmp_cfg cfg_exp_flag = *cfg;
-	struct encoder_struct enc_exp_flag = *enc;
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
 
-	cfg_exp_flag.golomb_par = GOLOMB_PAR_EXPOSURE_FLAGS;
-	enc_exp_flag.log2_golomb_par = ilog_2(GOLOMB_PAR_EXPOSURE_FLAGS);
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	for (i = 0; i < cfg->samples; i++) {
-		int err;
+	err = configure_encoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				      cfg->round, max_used_bits.nc_background_mean, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				      cfg->round, max_used_bits.nc_background_variance, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+				      cfg->round, max_used_bits.nc_background_outlier_pixels, cfg);
+	if (err)
+		return -1;
 
-		/* err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, &cfg_exp_flag, enc); */
-		err = encode_normal(data_to_encode[i].EXPOSURE_FLAGS, &cfg_exp_flag, &enc_exp_flag);
-		if (err)
-			return err;
-		enc->cmp_size = enc_exp_flag.cmp_size;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].mean, model.mean,
+					  stream_len, &setup_mean);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].variance, model.variance,
+					  stream_len, &setup_var);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].outlier_pixels, model.outlier_pixels,
+					  stream_len, &setup_pix);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, model.mean,
+				cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance = cmp_up_model(data_buf[i].variance, model.variance,
+				cfg->model_value, setup_var.lossy_par);
+			up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels, model.outlier_pixels,
+				cfg->model_value, setup_pix.lossy_par);
+		}
 
-		enc->log2_golomb_par = ilog_2(cfg->golomb_par);
-		err = encode_value(data_to_encode[i].FX, 32, cfg, enc);
-		if (err)
-			return err;
+		if (i >= cfg->samples-1)
+			break;
 
-		enc_exp_flag.cmp_size = enc->cmp_size;
+		model = next_model_p[i];
 	}
-
-	return 0;
+	return stream_len;
 }
 
 
-static int encode_S_FX_EFX(struct cmp_cfg *cfg, struct encoder_struct *enc)
+/**
+ * @brief compress smearing data from the normal cameras
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
+
+static int compress_smearing(const struct cmp_cfg *cfg)
 {
-	struct S_FX_EFX *data_to_encode = cfg->input_buf;
+	int err;
+	int stream_len = 0;
 	size_t i;
 
-	for (i = 0; i < cfg->samples; i++) {
-		int err;
+	struct smearing *data_buf = cfg->input_buf;
+	struct smearing *model_buf = cfg->model_buf;
+	struct smearing *up_model_buf = NULL;
+	struct smearing *next_model_p;
+	struct smearing model;
+	struct encoder_setupt setup_mean, setup_var_mean, setup_pix;
 
-		err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, cfg, enc);
-		if (err)
-			return err;
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
 
-		err = encode_value(data_to_encode[i].FX, 32, cfg, enc);
-		if (err)
-			return err;
+	stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+					      (void **)&up_model_buf, cfg->icu_output_buf);
 
-		err = encode_value(data_to_encode[i].EFX, 32, cfg, enc);
-		if (err)
-			return err;
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
 	}
-	return 0;
-}
-
-
-static int encode_S_FX_NCOB(struct cmp_cfg *cfg, struct encoder_struct *enc)
-{
-	struct S_FX_NCOB *data_to_encode = cfg->input_buf;
-	size_t i;
-
-	for (i = 0; i < cfg->samples; i++) {
-		int err;
 
-		err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, cfg, enc);
-		if (err)
-			return err;
+	err = configure_encoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				      cfg->round, max_used_bits.smearing_mean, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_var_mean, cfg->cmp_par_variance, cfg->spill_variance,
+				      cfg->round, max_used_bits.smearing_variance_mean, cfg);
+	if (err)
+		return -1;
+	err = configure_encoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+				      cfg->round, max_used_bits.smearing_outlier_pixels, cfg);
+	if (err)
+		return -1;
 
-		err = encode_value(data_to_encode[i].FX, 32, cfg, enc);
-		if (err)
-			return err;
+	for (i = 0;; i++) {
+		stream_len = encode_value(data_buf[i].mean, model.mean,
+					  stream_len, &setup_mean);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].variance_mean, model.variance_mean,
+					  stream_len, &setup_var_mean);
+		if (stream_len <= 0)
+			return stream_len;
+		stream_len = encode_value(data_buf[i].outlier_pixels, model.outlier_pixels,
+					  stream_len, &setup_pix);
+		if (stream_len <= 0)
+			return stream_len;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, model.mean,
+				cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance_mean = cmp_up_model(data_buf[i].variance_mean, model.variance_mean,
+				cfg->model_value, setup_var_mean.lossy_par);
+			up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels, model.outlier_pixels,
+				cfg->model_value, setup_pix.lossy_par);
+		}
 
-		err = encode_value(data_to_encode[i].NCOB_X, 32, cfg, enc);
-		if (err)
-			return err;
+		if (i >= cfg->samples-1)
+			break;
 
-		err = encode_value(data_to_encode[i].NCOB_Y, 32, cfg, enc);
-		if (err)
-			return err;
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_len;
 }
 
 
-static int encode_S_FX_EFX_NCOB_ECOB(struct cmp_cfg *cfg, struct encoder_struct
-				     *enc)
-{
-	struct S_FX_EFX_NCOB_ECOB *data_to_encode = cfg->input_buf;
-	size_t i;
-
-	for (i = 0; i < cfg->samples; i++) {
-		int err;
-
-		err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, cfg, enc);
-		if (err)
-			return err;
+/**
+ * @brief fill the last part of the bitstream with zeros
+ *
+ * @param cfg		pointer to the compression configuration structure
+ * @param cmp_size	length of the bitstream in bits
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the
+ *	value in the bitstream
+ */
 
-		err = encode_value(data_to_encode[i].FX, 32, cfg, enc);
-		if (err)
-			return err;
+static int pad_bitstream(const struct cmp_cfg *cfg, int cmp_size)
+{
+	unsigned int output_buf_len_bits, n_pad_bits;
 
-		err = encode_value(data_to_encode[i].NCOB_X, 32, cfg, enc);
-		if (err)
-			return err;
+	if (cmp_size < 0)
+		return cmp_size;
 
-		err = encode_value(data_to_encode[i].NCOB_Y, 32, cfg, enc);
-		if (err)
-			return err;
+	if (!cfg->icu_output_buf)
+		return cmp_size;
 
-		err = encode_value(data_to_encode[i].EFX, 32, cfg, enc);
-		if (err)
-			return err;
+	/* no padding in RAW mode; ALWAYS BIG-ENDIAN */
+	if (cfg->cmp_mode == CMP_MODE_RAW)
+		return cmp_size;
 
-		err = encode_value(data_to_encode[i].ECOB_X, 32, cfg, enc);
-		if (err)
-			return err;
+	/* maximum length of the bitstream/icu_output_buf in bits */
+	output_buf_len_bits = cmp_buffer_length_to_bits(cfg->buffer_length, cfg->data_type);
 
-		err = encode_value(data_to_encode[i].ECOB_Y, 32, cfg, enc);
-		if (err)
-			return err;
+	n_pad_bits = 32 - ((unsigned int)cmp_size & 0x1FU);
+	if (n_pad_bits < 32) {
+		int n_bits = put_n_bits32(0, n_pad_bits, cmp_size, cfg->icu_output_buf,
+					  output_buf_len_bits);
+		if (n_bits < 0)
+			return n_bits;
 	}
-	return 0;
-}
 
-
-/* pad the bitstream with zeros */
-int pad_bitstream(struct cmp_cfg *cfg, uint32_t cmp_size)
-{
-	int n_bits = 0;
-
-	if (!cfg)
-		return -1;
-
-	/* is padding needed */
-	if (cmp_size) {
-		int n_pad_bits = 32U - (cmp_size & 0x1f);
-		if (n_pad_bits < 32) {
-			 n_bits = put_n_bits32(0, cmp_size, n_pad_bits,
-					       cfg->icu_output_buf,
-					       cfg->buffer_length);
-			if (n_bits <= 0)
-				return -2;
-		}
-	}
-	return n_bits;
+	return cmp_size;
 }
 
 
-uint32_t cmp_encode_data(struct cmp_cfg *cfg)
-{
-	struct encoder_struct enc;
-	int err, n_bits;
-
-	enc.encoder = select_encoder(cfg->golomb_par);
-	enc.log2_golomb_par = ilog_2(cfg->golomb_par);
-	enc.cmp_size = 0;
+/**
+ * @brief change the endianness of the compressed data to big-endian
+ *
+ * @param cfg		pointer to the compression configuration structure
+ * @param cmp_size	length of the bitstream in bits
+ *
+ * @returns 0 on success; non-zero on failure
+ */
 
-	switch (cfg->cmp_mode) {
-	case MODE_RAW:
-		err = encode_raw_16(cfg, &enc);
-		break;
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_MULTI:
-		err = encode_16(cfg, &enc);
-		break;
-	case MODE_RAW_S_FX:
-		err = encode_raw_S_FX(cfg, &enc);
-		break;
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		err = encode_S_FX(cfg, &enc);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		err = encode_S_FX_EFX(cfg, &enc);
-		break;
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-		err = encode_S_FX_NCOB(cfg, &enc);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		err = encode_S_FX_EFX_NCOB_ECOB(cfg, &enc);
-		break;
-	case MODE_MODEL_ZERO_32:
-	case MODE_MODEL_MULTI_32:
-	case MODE_DIFF_ZERO_32:
-	case MODE_DIFF_MULTI_32:
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		err = encode_32(cfg, &enc);
-		break;
-	default:
-		debug_print("Error: Compression mode not supported.\n");
-		return -1;
-		break;
-	}
+static int cmp_data_to_big_endian(const struct cmp_cfg *cfg, int cmp_size)
+{
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+	size_t i;
+	uint32_t *p;
+	uint32_t s = (uint32_t)cmp_size;
 
-	n_bits = pad_bitstream(cfg, enc.cmp_size);
-	if (n_bits < 0)
-		return n_bits;
+	if (cmp_size < 0)
+		return cmp_size;
 
-#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-	{
-		size_t i;
-		uint32_t *p = (uint32_t *)cfg->icu_output_buf;
+	if (!cfg->icu_output_buf)
+		return cmp_size;
 
-		if (p) {
-			for (i = 0; i < cmp_bit_to_4byte(enc.cmp_size)/sizeof(uint32_t); i++)
-				cpu_to_be32s(&p[i]);
+	if (cfg->cmp_mode == CMP_MODE_RAW) {
+		if (s & 0x7) /* size must be a multiple of 8 in RAW mode */
+			return -1;
+		if (cmp_input_big_to_cpu_endianness(cfg->icu_output_buf,
+						    s/CHAR_BIT, cfg->data_type))
+			cmp_size = -1;
+	} else {
+		if (rdcu_supported_data_type_is_used(cfg->data_type)) {
+			p = cfg->icu_output_buf;
+		} else {
+			p = &cfg->icu_output_buf[MULTI_ENTRY_HDR_SIZE/sizeof(uint32_t)];
+			s -= MULTI_ENTRY_HDR_SIZE * CHAR_BIT;
 		}
+
+		for (i = 0; i < cmp_bit_to_4byte(s)/sizeof(uint32_t); i++)
+			cpu_to_be32s(&p[i]);
 	}
+#else
+	/* do nothing data are already in big-endian */
+	(void)cfg;
 #endif /*__BYTE_ORDER__ */
-
-	if (err)
-		return err;
-	else
-		return enc.cmp_size;
+	return cmp_size;
 }
 
 
 /**
- * @brief	compress data on the ICU
+ * @brief compress data on the ICU in software
  *
- * @param cfg	compressor configuration contains all parameters required for
- *		compression
- * @param info	compressor information contains information of the executed
- *		compression
+ * @param cfg	pointer to a compression configuration (created with the
+ *		cmp_cfg_icu_create() function, setup with the cmp_cfg_xxx() functions)
  *
- * @note this function violates the input_buf in place
- * @note if icu_new_model_buf = model_buf or NULL, the model will be updated in place
  * @note the validity of the cfg structure is checked before the compression is
  *	 started
- * @note when using the 1d-differencing mode or the raw mode (cmp_mode = 0,2,4),
- *      the model parameters (model_value, model_buf, rdcu_model_adr) are ignored
- * @note the rdcu_***_adr configuration parameters are ignored for icu
- *	 compression
- * @note semi adaptive compression not supported; configuration parameters
- *	 ap1\_golomb\_par, ap2\_golomb\_par, ap1\_spill ap2\_spill will be
- *	 ignored; information parameters ap1_cmp_size, ap2_cmp_size will always
- *	 be 0
- *
- * @returns 0 on success, error otherwise
+ *
+ * @returns the bit length of the bitstream on success; negative on error,
+ *	CMP_ERROR_SMALL_BUF (-2) if the compressed data buffer is too small to
+ *	hold the whole compressed data, CMP_ERROR_HIGH_VALUE (-3) if a data or
+ *	model value is bigger than the max_used_bits parameter allows (set with
+ *	the cmp_set_max_used_bits() function)
  */
 
-int icu_compress_data(struct cmp_cfg *cfg, struct cmp_info *info)
+int icu_compress_data(const struct cmp_cfg *cfg)
 {
-	int err;
 	int cmp_size = 0;
 
-	err = set_info(cfg, info);
-	if (err)
-		return err;
+	if (!cfg)
+		return -1;
 
-	err = icu_cmp_cfg_valid(cfg, info);
-	if (err)
-		return err;
+	if (cfg->samples == 0) /* nothing to compress we are done*/
+		return 0;
 
-	err = cmp_pre_process(cfg);
-	if (err)
-		return err;
+	if (raw_mode_is_used(cfg->cmp_mode))
+		if (cfg->samples > cfg->buffer_length)
+			return CMP_ERROR_SMALL_BUF;
 
-	err = cmp_map_to_pos(cfg);
-	if (err)
-		return err;
+	if (cmp_cfg_is_invalid(cfg))
+		return -1;
 
-	cmp_size = cmp_encode_data(cfg);
-	if (cmp_size == -2 && info)
-		/* the icu_output_buf is to small to store the whole bitstream */
-		info->cmp_err |= 1UL << SMALL_BUFFER_ERR_BIT; /* set small buffer error */
-	if (cmp_size < 0)
-		return cmp_size;
-	if (info)
-		info->cmp_size = cmp_size;
+	if (raw_mode_is_used(cfg->cmp_mode)) {
+		cmp_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);
+		if (cfg->icu_output_buf)
+			memcpy(cfg->icu_output_buf, cfg->input_buf, cmp_size);
+		cmp_size *= CHAR_BIT; /* convert to bits */
+	} else {
+		if (cfg->icu_output_buf && cfg->samples/3 > cfg->buffer_length)
+			debug_print("Warning: The size of the compressed_data buffer is 3 times smaller than the data_to_compress. This is probably unintended.\n");
+
+		switch (cfg->data_type) {
+		case DATA_TYPE_IMAGETTE:
+		case DATA_TYPE_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_SAT_IMAGETTE:
+		case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_F_CAM_IMAGETTE:
+		case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+			cmp_size = compress_imagette(cfg);
+			break;
+
+		case DATA_TYPE_S_FX:
+			cmp_size = compress_s_fx(cfg);
+			break;
+		case DATA_TYPE_S_FX_EFX:
+			cmp_size = compress_s_fx_efx(cfg);
+			break;
+		case DATA_TYPE_S_FX_NCOB:
+			cmp_size = compress_s_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+			cmp_size = compress_s_fx_efx_ncob_ecob(cfg);
+			break;
+
+		case DATA_TYPE_F_FX:
+			cmp_size = compress_f_fx(cfg);
+			break;
+		case DATA_TYPE_F_FX_EFX:
+			cmp_size = compress_f_fx_efx(cfg);
+			break;
+		case DATA_TYPE_F_FX_NCOB:
+			cmp_size = compress_f_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+			cmp_size = compress_f_fx_efx_ncob_ecob(cfg);
+			break;
+
+		case DATA_TYPE_L_FX:
+			cmp_size = compress_l_fx(cfg);
+			break;
+		case DATA_TYPE_L_FX_EFX:
+			cmp_size = compress_l_fx_efx(cfg);
+			break;
+		case DATA_TYPE_L_FX_NCOB:
+			cmp_size = compress_l_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+			cmp_size = compress_l_fx_efx_ncob_ecob(cfg);
+			break;
+
+		case DATA_TYPE_OFFSET:
+			cmp_size = compress_nc_offset(cfg);
+			break;
+		case DATA_TYPE_BACKGROUND:
+			cmp_size = compress_nc_background(cfg);
+			break;
+		case DATA_TYPE_SMEARING:
+			cmp_size = compress_smearing(cfg);
+			break;
+
+		case DATA_TYPE_F_CAM_OFFSET:
+		case DATA_TYPE_F_CAM_BACKGROUND:
+		/* LCOV_EXCL_START */
+		case DATA_TYPE_UNKNOWN:
+		default:
+			debug_print("Error: Data type not supported.\n");
+			cmp_size = -1;
+		}
+		/* LCOV_EXCL_STOP */
+	}
 
-	return 0;
+	cmp_size = pad_bitstream(cfg, cmp_size);
+	cmp_size = cmp_data_to_big_endian(cfg, cmp_size);
+
+	return cmp_size;
 }
diff --git a/lib/cmp_io.c b/lib/cmp_io.c
index 9f7fd7294ee4884cc7624deea3588b6cad403dbb..0dfcc8d71d2f656934383000d5f71ac109af9ec3 100644
--- a/lib/cmp_io.c
+++ b/lib/cmp_io.c
@@ -15,6 +15,7 @@
  * more details.
  *
  * @brief compression tool Input/Output library
+ * @warning this part of the software is not intended to run on-board on the ICU.
  */
 
 #include <stdio.h>
@@ -24,10 +25,44 @@
 #include <ctype.h>
 #include <sys/stat.h>
 
-#include "../include/cmp_io.h"
-#include "../include/cmp_support.h"
-#include "../include/rdcu_cmd.h"
-#include "../include/byteorder.h"
+#include <cmp_tool-config.h>
+#include <cmp_io.h>
+#include <cmp_support.h>
+#include <rdcu_cmd.h>
+#include <byteorder.h>
+#include <cmp_data_types.h>
+
+
+/* directory to convert from data_type to string */
+static const struct {
+	enum cmp_data_type data_type;
+	const char *str;
+} data_type_string_table[] = {
+	{DATA_TYPE_IMAGETTE, "DATA_TYPE_IMAGETTE"},
+	{DATA_TYPE_IMAGETTE_ADAPTIVE, "DATA_TYPE_IMAGETTE_ADAPTIVE"},
+	{DATA_TYPE_SAT_IMAGETTE, "DATA_TYPE_SAT_IMAGETTE"},
+	{DATA_TYPE_SAT_IMAGETTE_ADAPTIVE, "DATA_TYPE_SAT_IMAGETTE_ADAPTIVE"},
+	{DATA_TYPE_OFFSET, "DATA_TYPE_OFFSET"},
+	{DATA_TYPE_BACKGROUND, "DATA_TYPE_BACKGROUND"},
+	{DATA_TYPE_SMEARING, "DATA_TYPE_SMEARING"},
+	{DATA_TYPE_S_FX, "DATA_TYPE_S_FX"},
+	{DATA_TYPE_S_FX_EFX, "DATA_TYPE_S_FX_EFX"},
+	{DATA_TYPE_S_FX_NCOB, "DATA_TYPE_S_FX_NCOB"},
+	{DATA_TYPE_S_FX_EFX_NCOB_ECOB, "DATA_TYPE_S_FX_EFX_NCOB_ECOB"},
+	{DATA_TYPE_L_FX, "DATA_TYPE_L_FX"},
+	{DATA_TYPE_L_FX_EFX, "DATA_TYPE_L_FX_EFX"},
+	{DATA_TYPE_L_FX_NCOB, "DATA_TYPE_L_FX_NCOB"},
+	{DATA_TYPE_L_FX_EFX_NCOB_ECOB, "DATA_TYPE_L_FX_EFX_NCOB_ECOB"},
+	{DATA_TYPE_F_FX, "DATA_TYPE_F_FX"},
+	{DATA_TYPE_F_FX_EFX, "DATA_TYPE_F_FX_EFX"},
+	{DATA_TYPE_F_FX_NCOB, "DATA_TYPE_F_FX_NCOB"},
+	{DATA_TYPE_F_FX_EFX_NCOB_ECOB, "DATA_TYPE_F_FX_EFX_NCOB_ECOB"},
+	{DATA_TYPE_F_CAM_IMAGETTE, "DATA_TYPE_F_CAM_IMAGETTE"},
+	{DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE, "DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE"},
+	{DATA_TYPE_F_CAM_OFFSET, "DATA_TYPE_F_CAM_OFFSET"},
+	{DATA_TYPE_F_CAM_BACKGROUND, "DATA_TYPE_F_CAM_BACKGROUND"},
+	{DATA_TYPE_UNKNOWN, "DATA_TYPE_UNKNOWN"}
+};
 
 
 /**
@@ -112,31 +147,34 @@ static FILE *open_file(const char *dirname, const char *filename)
 
 
 /**
- * @brief write a uint16_t buffer to an output file
- *
- * @param buf		the buffer to write a file
- * @param buf_len	length of the buffer
+ * @brief write uncompressed input data to an output file
  *
+ * @param data		the data to write a file
+ * @param data_size	size of the data in bytes
  * @param output_prefix  file name without file extension
  * @param name_extension file extension (with leading point character)
- *
  * @param verbose	print verbose output if not zero
  *
  * @returns 0 on success, error otherwise
  */
 
-int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char
-		    *output_prefix, const char *name_extension, int verbose)
+int write_input_data_to_file(void *data, uint32_t data_size, enum cmp_data_type data_type,
+			     const char *output_prefix, const char *name_extension, int verbose)
 {
-	uint32_t i;
+	uint32_t i = 0;
 	FILE *fp;
+	uint8_t *tmp_buf;
+	size_t sample_size = size_of_a_sample(data_type);
 
-	if (!buf)
+	if (!data)
 		abort();
 
-	if (buf_len == 0)
+	if (data_size == 0)
 		return 0;
 
+	if (!sample_size)
+		return -1;
+
 	fp = open_file(output_prefix, name_extension);
 	if (fp == NULL) {
 		fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix,
@@ -144,8 +182,12 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char
 		return -1;
 	}
 
-	for (i = 0; i < buf_len; i++) {
-		fprintf(fp, "%02X %02X", buf[i] >> 8, buf[i] & 0xFF);
+	tmp_buf = malloc(data_size);
+	memcpy(tmp_buf, data, data_size);
+	cmp_input_big_to_cpu_endianness(tmp_buf, data_size, data_type);
+
+	for (i = 0 ; i < data_size; i++) {
+		fprintf(fp, "%02X",  tmp_buf[i]);
 		if ((i + 1) % 16 == 0)
 			fprintf(fp, "\n");
 		else
@@ -157,8 +199,8 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char
 
 	if (verbose) {
 		printf("\n\n");
-			for (i = 0; i < buf_len; i++) {
-				printf("%02X %02X", buf[i] >> 8, buf[i] & 0xFF);
+			for (i = 0; i < data_size; i++) {
+				printf("%02X", tmp_buf[i]);
 			if ((i + 1) % 16 == 0)
 				printf("\n");
 			else
@@ -168,6 +210,7 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char
 		printf("\n\n");
 	}
 
+	free(tmp_buf);
 	return 0;
 }
 
@@ -354,6 +397,67 @@ int atoui32(const char *dep_str, const char *val_str, uint32_t *red_val)
 }
 
 
+/**
+ * @brief parse a compression data_type string to a data_type
+ * @note string can be either a number or the name of the compression data type
+ *
+ * @param data_type_str	string containing the compression data type to parse
+ *
+ * @returns data type on success, DATA_TYPE_UNKNOWN on error
+ */
+
+enum cmp_data_type string2data_type(const char *data_type_str)
+{
+	enum cmp_data_type data_type = DATA_TYPE_UNKNOWN;
+
+	if (data_type_str) {
+		if (isalpha(data_type_str[0])) {  /* check if mode is given as text */
+			size_t j;
+
+			for (j = 0; j < sizeof(data_type_string_table) / sizeof(data_type_string_table[0]); j++) {
+				if (!strcmp(data_type_str, data_type_string_table[j].str)) {
+					data_type = data_type_string_table[j].data_type;
+					break;
+				}
+			}
+		} else {
+			uint32_t read_val;
+
+			if (!atoui32("Compression Data Type", data_type_str, &read_val)) {
+				data_type = read_val;
+				if (!cmp_data_type_valid(data_type))
+					data_type = DATA_TYPE_UNKNOWN;
+			}
+		}
+	}
+	return data_type;
+}
+
+/**
+ * @brief parse a compression data_type string to a data_type
+ * @note string can be either a number or the name of the compression data type
+ *
+ * @param data_type compression data type to convert in string
+ *
+ * @returns data type on success, DATA_TYPE_UNKNOWN on error
+ */
+
+const char *data_type2string(enum cmp_data_type data_type)
+{
+	size_t j;
+	const char *string = "DATA_TYPE_UNKNOWN";
+
+	for (j = 0; j < sizeof(data_type_string_table) / sizeof(data_type_string_table[0]); j++) {
+		if (data_type == data_type_string_table[j].data_type) {
+			string = data_type_string_table[j].str;
+			break;
+		}
+	}
+
+	return string;
+}
+
+
 /**
  * @brief parse a compression mode vale string to an integer
  * @note string can be either a number or the name of the compression mode
@@ -368,14 +472,19 @@ int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode)
 {
 	size_t j;
 	static const struct {
-		uint32_t  cmp_mode;
+		uint32_t cmp_mode;
 		const char *str;
 	} conversion[] = {
-		{MODE_RAW, "MODE_RAW"},
-		{MODE_MODEL_ZERO, "MODE_MODEL_ZERO"},
-		{MODE_DIFF_ZERO, "MODE_DIFF_ZERO"},
-		{MODE_MODEL_MULTI, "MODE_MODEL_MULTI"},
-		{MODE_DIFF_MULTI, "MODE_DIFF_MULTI"},
+		{CMP_MODE_RAW, "MODE_RAW"},
+		{CMP_MODE_MODEL_ZERO, "MODE_MODEL_ZERO"},
+		{CMP_MODE_DIFF_ZERO, "MODE_DIFF_ZERO"},
+		{CMP_MODE_MODEL_MULTI, "MODE_MODEL_MULTI"},
+		{CMP_MODE_DIFF_MULTI, "MODE_DIFF_MULTI"},
+		{CMP_MODE_RAW, "CMP_MODE_RAW"},
+		{CMP_MODE_MODEL_ZERO, "CMP_MODE_MODEL_ZERO"},
+		{CMP_MODE_DIFF_ZERO, "CMP_MODE_DIFF_ZERO"},
+		{CMP_MODE_MODEL_MULTI, "CMP_MODE_MODEL_MULTI"},
+		{CMP_MODE_DIFF_MULTI, "CMP_MODE_DIFF_MULTI"},
 	};
 
 	if (!cmp_mode_str)
@@ -384,7 +493,7 @@ int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode)
 		return -1;
 
 	if (isalpha(cmp_mode_str[0])) {  /* check if mode is given as text */
-		for (j = 0;  j < sizeof(conversion) / sizeof(conversion[0]);  ++j) {
+		for (j = 0; j < sizeof(conversion) / sizeof(conversion[0]); ++j) {
 			if (!strcmp(cmp_mode_str, conversion[j].str)) {
 				*cmp_mode = conversion[j].cmp_mode;
 				return 0;
@@ -396,7 +505,7 @@ int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode)
 			return -1;
 	}
 
-	if (!cmp_mode_available(*cmp_mode))
+	if (!cmp_mode_is_supported(*cmp_mode))
 		return -1;
 
 	return 0;
@@ -418,7 +527,7 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 {
 	char *token1, *token2;
 	char line[MAX_CONFIG_LINE];
-	enum {CMP_MODE, GOLOMB_PAR, SPILL, SAMPLES, BUFFER_LENGTH, LAST_ITEM};
+	enum {CMP_MODE, SAMPLES, BUFFER_LENGTH, LAST_ITEM};
 	int j, must_read_items[LAST_ITEM] = {0};
 
 	if (!fp)
@@ -448,48 +557,26 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 			continue;
 
 
+		if (!strcmp(token1, "data_type")) {
+			cfg->data_type = string2data_type(token2);
+			if (cfg->data_type == DATA_TYPE_UNKNOWN)
+				return -1;
+			continue;
+		}
 		if (!strcmp(token1, "cmp_mode")) {
 			must_read_items[CMP_MODE] = 1;
-			if (isalpha(*token2)) { /* check if mode is given as text or val*/
-				if (!strcmp(token2, "MODE_RAW")) {
-					cfg->cmp_mode = 0;
-					continue;
-				}
-				if (!strcmp(token2, "MODE_MODEL_ZERO")) {
-					cfg->cmp_mode = 1;
-					continue;
-				}
-				if (!strcmp(token2, "MODE_DIFF_ZERO")) {
-					cfg->cmp_mode = 2;
-					continue;
-				}
-				if (!strcmp(token2, "MODE_MODEL_MULTI")) {
-					cfg->cmp_mode = 3;
-					continue;
-				}
-				if (!strcmp(token2, "MODE_DIFF_MULTI")) {
-					cfg->cmp_mode = 4;
-					continue;
-				}
-				fprintf(stderr, "%s: Error read in cmp_mode.\n",
-					PROGRAM_NAME);
+			if (cmp_mode_parse(token2, &cfg->cmp_mode))
 				return -1;
-			} else {
-				if (atoui32(token1, token2, &cfg->cmp_mode))
-					return -1;
-				continue;
-			}
+			continue;
 		}
 		if (!strcmp(token1, "golomb_par")) {
 			if (atoui32(token1, token2, &cfg->golomb_par))
 				return -1;
-			must_read_items[GOLOMB_PAR] = 1;
 			continue;
 		}
 		if (!strcmp(token1, "spill")) {
 			if (atoui32(token1, token2, &cfg->spill))
 				return -1;
-			must_read_items[SPILL] = 1;
 			continue;
 		}
 		if (!strcmp(token1, "model_value")) {
@@ -522,6 +609,96 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
 				return -1;
 			continue;
 		}
+		if (!strcmp(token1, "cmp_par_exp_flags")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_exp_flags))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_exp_flags")) {
+			if (atoui32(token1, token2, &cfg->spill_exp_flags))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_fx")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_fx))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_fx")) {
+			if (atoui32(token1, token2, &cfg->spill_fx))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_ncob")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_ncob))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_ncob")) {
+			if (atoui32(token1, token2, &cfg->spill_ncob))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_efx")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_efx))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_efx")) {
+			if (atoui32(token1, token2, &cfg->spill_efx))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_ecob")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_ecob))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_ecob")) {
+			if (atoui32(token1, token2, &cfg->spill_ecob))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_fx_cob_variance")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_fx_cob_variance))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_fx_cob_variance")) {
+			if (atoui32(token1, token2, &cfg->spill_fx_cob_variance))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_mean")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_mean))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_mean")) {
+			if (atoui32(token1, token2, &cfg->spill_mean))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_variance")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_variance))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_variance")) {
+			if (atoui32(token1, token2, &cfg->spill_variance))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_par_pixels_error")) {
+			if (atoui32(token1, token2, &cfg->cmp_par_pixels_error))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill_pixels_error")) {
+			if (atoui32(token1, token2, &cfg->spill_pixels_error))
+				return -1;
+			continue;
+		}
 		if (!strcmp(token1, "rdcu_data_adr")) {
 			int i = sram_addr_to_int(token2);
 
@@ -643,18 +820,12 @@ int read_cmp_cfg(const char *file_name, struct cmp_cfg *cfg, int verbose_en)
 		printf("\n");
 	}
 
-	if (cfg->buffer_length < cfg->samples/2) {
-		fprintf(stderr,
-			"%s: warning: buffer_length: %u is relative small to the chosen samples parameter of %u.\n",
-			PROGRAM_NAME, cfg->buffer_length, cfg->samples);
-	}
-
 	return 0;
 }
 
 
 /**
- * @brief  parse a file containing a decompression information
+ * @brief parse a file containing a decompression information
  * @note internal use only!
  *
  * @param fp	FILE pointer
@@ -703,6 +874,7 @@ static int parse_info(FILE *fp, struct cmp_info *info)
 		if (!strcmp(token1, "cmp_mode_used")) {
 			must_read_items[CMP_MODE_USED] = 1;
 			if (isalpha(*token2)) { /* check if mode is given as text or val*/
+				/* TODO: use conversion function for this: */
 				if (!strcmp(token2, "MODE_RAW")) {
 					info->cmp_mode_used = 0;
 					continue;
@@ -1011,7 +1183,7 @@ static uint8_t str_to_uint8(const char *str, char **str_end)
 
 
 /**
- * @brief reads n_word words of a hex-encoded string to a uint8_t buffer
+ * @brief reads buf_size words of a hex-encoded string to a uint8_t buffer
  *
  * @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage
  *	return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a
@@ -1024,14 +1196,14 @@ static uint8_t str_to_uint8(const char *str, char **str_end)
  *
  * @param str		pointer to the null-terminated byte string to be interpreted
  * @param data		buffer to write the interpreted content (can be NULL)
- * @param n_word	number of uint8_t data words to read in
+ * @param buf_size	number of uint8_t data words to read in
  * @param file_name	file name for better error output (can be NULL)
  * @param verbose_en	print verbose output if not zero
  *
  * @returns the size in bytes to store the string content; negative on error
  */
 
-static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word,
+static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t buf_size,
 			     const char *file_name, int verbose_en)
 {
 	const char *nptr = str;
@@ -1041,12 +1213,12 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word,
 	errno = 0;
 
 	if (!data)
-		n_word = ~0;
+		buf_size = ~0;
 
 	if (!file_name)
 		file_name = "unknown file name";
 
-	for (i = 0; i < n_word; ) {
+	for (i = 0; i < buf_size; ) {
 		uint8_t read_val;
 		unsigned char c = *nptr;
 
@@ -1116,8 +1288,7 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word,
 
 
 /**
- * @brief reads n_word words of a hex-encoded uint8_t data form a file to a
- *	buffer
+ * @brief reads hex-encoded uint8_t data form a file to a buffer
  *
  * @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage
  *	return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a
@@ -1130,13 +1301,13 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word,
  *
  * @param file_name	data/model file name
  * @param buf		buffer to write the file content (can be NULL)
- * @param n_word	number of uint8_t data words to read in
+ * @param buf_size	number of uint8_t data words to read in
  * @param verbose_en	print verbose output if not zero
  *
  * @returns the size in bytes to store the file content; negative on error
  */
 
-ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int verbose_en)
+ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, int verbose_en)
 {
 	FILE *fp;
 	char *file_cpy = NULL;
@@ -1163,6 +1334,10 @@ ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int ver
 		fclose(fp);
 		return 0;
 	}
+	if ((unsigned long)file_size < buf_size) {
+		fprintf(stderr, "%s: %s: Error: The files do not contain enough data as requested.\n", PROGRAM_NAME, file_name);
+		goto fail;
+	}
 	/* reset the file position indicator to the beginning of the file */
 	if (fseek(fp, 0L, SEEK_SET) != 0)
 		goto fail;
@@ -1186,7 +1361,7 @@ ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int ver
 	fclose(fp);
 	fp = NULL;
 
-	size = str2uint8_arr(file_cpy, buf, n_word, file_name, verbose_en);
+	size = str2uint8_arr(file_cpy, buf, buf_size, file_name, verbose_en);
 
 	free(file_cpy);
 	file_cpy = NULL;
@@ -1204,75 +1379,38 @@ fail:
 
 
 /**
- * @brief reads the number of uint16_t samples of a hex-encoded data (or model)
- *	file into a buffer
+ * @brief reads hex-encoded data from a file into a buffer
  *
  * @param file_name	data/model file name
+ * @param data_type	compression data type used for the data
  * @param buf		buffer to write the file content (can be NULL)
- * @param samples	amount of uint16_t data samples to read in
+ * @param buf_size	size in bytes of the buffer
  * @param verbose_en	print verbose output if not zero
  *
  * @returns the size in bytes to store the file content; negative on error
  */
 
-ssize_t read_file16(const char *file_name, uint16_t *buf, uint32_t samples,
-		    int verbose_en)
+ssize_t read_file_data(const char *file_name, enum cmp_data_type data_type,
+		       void *buf, uint32_t buf_size, int verbose_en)
 {
-	ssize_t size = read_file8(file_name, (uint8_t *)buf,
-				  samples*sizeof(uint16_t), verbose_en);
+	ssize_t size;
+	int samples, err;
+
+	size = read_file8(file_name, (uint8_t *)buf, buf_size, verbose_en);
 
 	if (size < 0)
 		return size;
 
-	if (size & 0x1) {
-		fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected multiple of 2 hex words.\n",
+	samples = cmp_input_size_to_samples(size, data_type);
+	if (samples < 0) {
+		fprintf(stderr, "%s: %s: Error: The data are not correct formatted for the used compression data type.\n",
 				PROGRAM_NAME, file_name);
 		return -1;
 	}
 
-	if (buf) {
-		size_t i;
-		for (i = 0; i < samples; i++)
-			be16_to_cpus(&buf[i]);
-	}
-
-
-	return size;
-}
-
-
-/**
- * @brief reads the number of uint32_t samples of a hex-encoded data (or model)
- *	file into a buffer
- *
- * @param file_name	data/model file name
- * @param buf		buffer to write the file content (can be NULL)
- * @param samples	amount of uint32_t data samples to read in
- * @param verbose_en	print verbose output if not zero
- *
- * @returns the size in bytes to store the file content; negative on error
- */
-
-ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t samples,
-		    int verbose_en)
-{
-	ssize_t size = read_file8(file_name, (uint8_t *)buf,
-				  samples*sizeof(uint32_t), verbose_en);
-
-	if (size < 0)
-		return -1;
-
-	if (size & 0x3) {
-		fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected multiple of 4 hex words.\n",
-				PROGRAM_NAME, file_name);
+	err = cmp_input_big_to_cpu_endianness(buf, size, data_type);
+	if (err)
 		return -1;
-	}
-
-	if (buf) {
-		size_t i;
-		for (i = 0; i < samples; i++)
-			be32_to_cpus(&buf[i]);
-	}
 
 	return size;
 }
@@ -1290,7 +1428,7 @@ ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t samples,
  */
 
 ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent,
-			   uint32_t ent_size, int verbose_en)
+			     uint32_t ent_size, int verbose_en)
 {
 	ssize_t size;
 
@@ -1305,9 +1443,9 @@ ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent,
 	}
 
 	if (ent) {
-		enum cmp_ent_data_type data_type = cmp_ent_get_data_type(ent);
+		enum cmp_data_type data_type = cmp_ent_get_data_type(ent);
 
-		if (!cmp_ent_data_type_valid(data_type)) {
+		if (data_type == DATA_TYPE_UNKNOWN) {
 			fprintf(stderr, "%s: %s: Error: Compression data type is not supported.\n",
 				PROGRAM_NAME, file_name);
 			return -1;
@@ -1326,6 +1464,41 @@ ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent,
 }
 
 
+/**
+ * @brief reads hex-encoded uint32_t samples from a file into a buffer
+ *
+ * @param file_name	data/model file name
+ * @param buf		buffer to write the file content (can be NULL)
+ * @param buf_size	size of the buf buffer in bytes
+ * @param verbose_en	print verbose output if not zero
+ *
+ * @returns the size in bytes to store the file content; negative on error
+ */
+
+ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t buf_size,
+		    int verbose_en)
+{
+	ssize_t size = read_file8(file_name, (uint8_t *)buf, buf_size, verbose_en);
+
+	if (size < 0)
+		return -1;
+
+	if (size & 0x3) {
+		fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected multiple of 4 hex words.\n",
+				PROGRAM_NAME, file_name);
+		return -1;
+	}
+
+	if (buf) {
+		size_t i;
+		for (i = 0; i < buf_size/sizeof(uint32_t); i++)
+			be32_to_cpus(&buf[i]);
+	}
+
+	return size;
+}
+
+
 /*
  * @brief generate from the cmp_tool version string a version_id for the
  * compression entity header
@@ -1369,7 +1542,7 @@ uint32_t cmp_tool_gen_version_id(const char *version)
 
 	version_id |= n;
 
-	return version_id |= CMP_TOOL_VERSION_ID_BIT;
+	return version_id | CMP_TOOL_VERSION_ID_BIT;
 }
 
 
@@ -1387,6 +1560,10 @@ static void write_cfg_internal(FILE *fp, const struct cmp_cfg *cfg, int rdcu_cfg
 	fprintf(fp, "#-------------------------------------------------------------------------------\n");
 	fprintf(fp, "# Default Configuration File\n");
 	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Selected compression data type\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "data_type = %s\n", data_type2string(cfg->data_type));
+	fprintf(fp, "\n");
 	fprintf(fp, "# Selected compression mode\n");
 	fprintf(fp, "# 0: raw mode\n");
 	fprintf(fp, "# 1: model mode with zero escape symbol mechanism\n");
diff --git a/lib/cmp_rdcu.c b/lib/cmp_rdcu.c
index c24ebed0e8eefb9e8e297ed1919d0b72e851442a..6a7354573e94d64a5e5b982c01ac71f979e5a6ee 100644
--- a/lib/cmp_rdcu.c
+++ b/lib/cmp_rdcu.c
@@ -15,21 +15,37 @@
  *
  * @brief hardware compressor control library
  * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ *
+ * To compress data, first create a compression configuration with the
+ * rdcu_cfg_create() function.
+ * Then set the different data buffers with the data to compressed, the model
+ * data and the RDCU SRAM addresses with the rdcu_cfg_buffers() function.
+ * Then set the imagette compression parameters with the rdcu_cfg_imagette()
+ * function.
+ * Finally, you can compress the data with the RDCU using the
+ * rdcu_compress_data() function.
  */
 
 #include <stdint.h>
 #include <stdio.h>
+#include <string.h>
+
+#include <rdcu_cmd.h>
+#include <cmp_debug.h>
+#include <cmp_support.h>
+#include <cmp_data_types.h>
+#include <rdcu_ctrl.h>
+#include <rdcu_rmap.h>
 
-#include "../include/rdcu_cmd.h"
-#include "../include/cmp_support.h"
-#include "../include/rdcu_ctrl.h"
-#include "../include/rdcu_rmap.h"
 
+#define IMA_SAM2BYT                                                            \
+	2 /* imagette sample to byte conversion factor; one imagette samples has 16 bits (2 bytes) */
 
 #define RDCU_INTR_SIG_ENA 1 /* RDCU interrupt signal enabled */
 #define RDCU_INTR_SIG_DIS 0 /* RDCU interrupt signal disable */
-#define RDCU_INTR_SIG_DEFAULT RDCU_INTR_SIG_ENA /* default start value for RDCU
-						   interrupt signal */
+#define RDCU_INTR_SIG_DEFAULT RDCU_INTR_SIG_ENA /* default start value for RDCU interrupt signal */
+
+
 /* RDCU interrupt signal status */
 static int interrupt_signal_enabled = RDCU_INTR_SIG_DEFAULT;
 
@@ -48,6 +64,7 @@ static void sync(void)
 	not needed for packed generation
 
 	int cnt = 0;
+
 	printf("syncing...");
 	while (rdcu_rmap_sync_status()) {
 		printf("pending: %d\n", rdcu_rmap_sync_status());
@@ -63,6 +80,87 @@ static void sync(void)
 }
 
 
+/**
+ * @brief check if the compression data product type, compression mode, model
+ *	value and the lossy rounding parameters are valid for an RDCU compression
+ *
+ * @param cfg	pointer to a compression configuration containing the compression
+ *	data product type, compression mode, model value and the rounding parameters
+ *
+ * @returns 0 if the compression data type, compression mode, model value and
+ *	the lossy rounding parameters are valid for an RDCU compression, non-zero
+ *	if parameters are invalid
+ */
+
+static int rdcu_cfg_gen_par_is_invalid(const struct cmp_cfg *cfg)
+{
+	int cfg_invalid = 0;
+
+	if (!cfg)
+		return -1;
+
+	if (!cmp_imagette_data_type_is_used(cfg->data_type)) {
+		debug_print("Error: The selected compression data type is not supported for RDCU compression");
+		cfg_invalid++;
+	}
+
+	if (cfg->cmp_mode > MAX_RDCU_CMP_MODE) {
+		debug_print("Error: selected cmp_mode: %u is not supported. Largest supported mode is: %u.\n",
+			    cfg->cmp_mode, MAX_RDCU_CMP_MODE);
+		cfg_invalid++;
+	}
+
+	if (cfg->model_value > MAX_MODEL_VALUE) {
+		debug_print("Error: selected model_value: %u is invalid. Largest supported value is: %u.\n",
+			    cfg->model_value, MAX_MODEL_VALUE);
+		cfg_invalid++;
+	}
+
+	if (cfg->round > MAX_RDCU_ROUND) {
+		debug_print("Error: selected round parameter: %u is not supported. Largest supported value is: %u.\n",
+			    cfg->round, MAX_RDCU_ROUND);
+		cfg_invalid++;
+	}
+
+#ifdef SKIP_CMP_PAR_CHECK
+	return 0;
+#endif
+
+	return -cfg_invalid;
+}
+
+
+/**
+ * @brief create an RDCU compression configuration
+ *
+ * @param data_type	compression data product type
+ * @param cmp_mode	compression mode
+ * @param model_value	model weighting parameter (only needed for model compression mode)
+ * @param lossy_par	lossy rounding parameter (use CMP_LOSSLESS for lossless compression)
+ *
+ * @returns a compression configuration containing the chosen parameters;
+ *	on error the data_type record is set to DATA_TYPE_UNKNOWN
+ */
+
+struct cmp_cfg rdcu_cfg_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode,
+			       uint32_t model_value, uint32_t lossy_par)
+{
+	struct cmp_cfg cfg;
+
+	memset(&cfg, 0, sizeof(cfg));
+
+	cfg.data_type = data_type;
+	cfg.cmp_mode = cmp_mode;
+	cfg.model_value = model_value;
+	cfg.round = lossy_par;
+
+	if (rdcu_cfg_gen_par_is_invalid(&cfg))
+		cfg.data_type = DATA_TYPE_UNKNOWN;
+
+	return cfg;
+}
+
+
 /**
  * @brief check if a buffer is in inside the RDCU SRAM
  *
@@ -99,6 +197,7 @@ static int in_sram_range(uint32_t addr, uint32_t size)
  * @returns 0 if buffers are not overlapping, otherwise buffer are
  *	overlapping
  */
+
 static int buffers_overlap(uint32_t start_a, uint32_t end_a, uint32_t start_b,
 			   uint32_t end_b)
 {
@@ -110,302 +209,372 @@ static int buffers_overlap(uint32_t start_a, uint32_t end_a, uint32_t start_b,
 
 
 /**
- * @brief check if the compressor configuration is valid for a RDCU compression,
- * see the user manual for more information (PLATO-UVIE-PL-UM-0001).
+ * @brief check if RDCU buffer settings are invalid
  *
- * @param cfg	configuration contains all parameters required for compression
+ * @param cfg	a pointer to a compression configuration
  *
- * @returns  >= 0 on success, error otherwise
+ * @returns 0 if buffers configuration is valid, otherwise the configuration is
+ *	invalid
  */
 
-int rdcu_cmp_cfg_valid(const struct cmp_cfg *cfg)
+static int rdcu_cfg_buffers_is_invalid(const struct cmp_cfg *cfg)
 {
 	int cfg_invalid = 0;
-	int cfg_warning = 0;
-
-	if (cfg == NULL)
-		return -1;
 
-	if (cfg->cmp_mode > MAX_RDCU_CMP_MODE) {
-		printf("Error: selected cmp_mode: %u is not supported. "
-		       "Largest supported mode is: %lu.\n", cfg->cmp_mode,
-		       MAX_RDCU_CMP_MODE);
-		cfg_invalid++;
-	}
-
-	if (cfg->model_value > MAX_MODEL_VALUE) {
-		printf("Error: selected model_value: %u is invalid. "
-		       "Largest supported value is: %lu.\n", cfg->model_value,
-		       MAX_MODEL_VALUE);
-		cfg_invalid++;
-	}
-
-	if (cfg->golomb_par < MIN_RDCU_GOLOMB_PAR||
-	    cfg->golomb_par > MAX_RDCU_GOLOMB_PAR) {
-		printf("Error: The selected Golomb parameter: %u is not supported. "
-		       "The Golomb parameter has to  be between [%lu, %lu].\n",
-		       cfg->golomb_par, MIN_RDCU_GOLOMB_PAR,
-		       MAX_RDCU_GOLOMB_PAR);
-		cfg_invalid++;
-	}
-
-	if (cfg->ap1_golomb_par < MIN_RDCU_GOLOMB_PAR ||
-	    cfg->ap1_golomb_par > MAX_RDCU_GOLOMB_PAR) {
-		printf("Error: The selected adaptive 1 Golomb parameter: %u is not supported. "
-		       "The Golomb parameter has to  be between [%lu, %lu].\n",
-		       cfg->ap1_golomb_par, MIN_RDCU_GOLOMB_PAR,
-		       MAX_RDCU_GOLOMB_PAR);
-		cfg_invalid++;
-	}
-
-	if (cfg->ap2_golomb_par < MIN_RDCU_GOLOMB_PAR ||
-	    cfg->ap2_golomb_par > MAX_RDCU_GOLOMB_PAR) {
-		printf("Error: The selected adaptive 2 Golomb parameter: %u is not supported. "
-		       "The Golomb parameter has to be between [%lu, %lu].\n",
-		       cfg->ap2_golomb_par, MIN_RDCU_GOLOMB_PAR,
-		       MAX_RDCU_GOLOMB_PAR);
-		cfg_invalid++;
-	}
-
-	if (cfg->spill < MIN_RDCU_SPILL) {
-		printf("Error: The selected spillover threshold value: %u is too small. "
-		       "Smallest possible spillover value is: %lu.\n",
-		       cfg->spill, MIN_RDCU_SPILL);
-		cfg_invalid++;
-	}
-
-	if (cfg->spill > get_max_spill(cfg->golomb_par, cfg->cmp_mode)) {
-		printf("Error: The selected spillover threshold value: %u is "
-		       "too large for the selected Golomb parameter: %u, the "
-		       "largest possible spillover value is: %u.\n",
-		       cfg->spill, cfg->golomb_par,
-		       get_max_spill(cfg->golomb_par, cfg->cmp_mode));
-		cfg_invalid++;
-	}
-
-	if (cfg->ap1_spill < MIN_RDCU_SPILL) {
-		printf("Error: The selected adaptive 1 spillover threshold "
-		       "value: %u is too small. "
-		       "Smallest possible spillover value is: %lu.\n",
-		       cfg->ap1_spill, MIN_RDCU_SPILL);
-		cfg_invalid++;
-	}
-
-	if (cfg->ap1_spill > get_max_spill(cfg->ap1_golomb_par, cfg->cmp_mode)) {
-		printf("Error: The selected adaptive 1 spillover threshold "
-		       "value: %u is too large for the selected adaptive 1 "
-		       "Golomb parameter: %u, the largest possible adaptive 1 "
-		       "spillover value is: %u.\n",
-		       cfg->ap1_spill, cfg->ap1_golomb_par,
-		       get_max_spill(cfg->ap1_golomb_par, cfg->cmp_mode));
-		cfg_invalid++;
-	}
-
-	if (cfg->ap2_spill < MIN_RDCU_SPILL) {
-		printf("Error: The selected adaptive 2 spillover threshold "
-		       "value: %u is too small."
-		       "Smallest possible spillover value is: %lu.\n",
-		       cfg->ap2_spill, MIN_RDCU_SPILL);
-		cfg_invalid++;
-	}
-
-	if (cfg->ap2_spill > get_max_spill(cfg->ap2_golomb_par, cfg->cmp_mode)) {
-		printf("Error: The selected adaptive 2 spillover threshold "
-		       "value: %u is too large for the selected adaptive 2 "
-		       "Golomb parameter: %u, the largest possible adaptive 2 "
-		       "spillover value is: %u.\n",
-		       cfg->ap2_spill, cfg->ap2_golomb_par,
-		       get_max_spill(cfg->ap2_golomb_par, cfg->cmp_mode));
-		cfg_invalid++;
-	}
-
-	if (cfg->round > MAX_RDCU_ROUND) {
-		printf("Error: selected round parameter: %u is not supported. "
-		       "Largest supported value is: %lu.\n",
-		       cfg->round, MAX_RDCU_ROUND);
-		cfg_invalid++;
-	}
-
-	if (cfg->samples == 0) {
-		printf("Warning: The samples parameter is set to 0. No data will be compressed.\n");
-		cfg_warning++;
-	}
-
-	if (cfg->buffer_length == 0) {
-		printf("Error: The buffer_length is set to 0. There is no place "
-		       "to store the compressed data.\n");
-		cfg_invalid++;
-	}
-
-	if (cfg->cmp_mode == MODE_RAW) {
+	if (cfg->cmp_mode == CMP_MODE_RAW) {
 		if (cfg->buffer_length < cfg->samples) {
-			printf("buffer_length is smaller than samples parameter. "
-			       "There is not enough space to copy the data in "
-			       "RAW mode.\n");
+			debug_print("rdcu_buffer_length is smaller than samples parameter. There is not enough space to copy the data in RAW mode.\n");
 			cfg_invalid++;
 		}
 	}
 
-	if (!cfg->input_buf) {
-		printf("Warning: The data to compress buffer is set to NULL. "
-		       "No data will be transferred to the rdcu_data_adr in  "
-		       "the RDCU-SRAM.\n");
-		cfg_warning++;
-	}
-
 	if (cfg->rdcu_data_adr & 0x3) {
-		printf("Error: The RDCU data to compress start address is not 4-Byte aligned.\n");
+		debug_print("Error: The RDCU data to compress start address is not 4-Byte aligned.\n");
 		cfg_invalid++;
 	}
 
 	if (cfg->rdcu_buffer_adr & 0x3) {
-		printf("Error: The RDCU compressed data start address is not 4-Byte aligned.\n");
+		debug_print("Error: The RDCU compressed data start address is not 4-Byte aligned.\n");
 		cfg_invalid++;
 	}
 
-	if (!in_sram_range(cfg->rdcu_data_adr, cfg->samples * SAM2BYT)) {
-		printf("Error: The RDCU data to compress buffer is outside the RDCU SRAM address space.\n");
+	if (!in_sram_range(cfg->rdcu_data_adr, cfg->samples * IMA_SAM2BYT)) {
+		debug_print("Error: The RDCU data to compress buffer is outside the RDCU SRAM address space.\n");
 		cfg_invalid++;
 	}
 
-	if (!in_sram_range(cfg->rdcu_buffer_adr, cfg->buffer_length * SAM2BYT)) {
-		printf("Error: The RDCU compressed data buffer is outside the RDCU SRAM address space.\n");
+	if (!in_sram_range(cfg->rdcu_buffer_adr, cfg->buffer_length * IMA_SAM2BYT)) {
+		debug_print("Error: The RDCU compressed data buffer is outside the RDCU SRAM address space.\n");
 		cfg_invalid++;
 	}
 
 	if (buffers_overlap(cfg->rdcu_data_adr,
-			    cfg->rdcu_data_adr + cfg->samples * SAM2BYT,
+			    cfg->rdcu_data_adr + cfg->samples * IMA_SAM2BYT,
 			    cfg->rdcu_buffer_adr,
-			    cfg->rdcu_buffer_adr + cfg->buffer_length * SAM2BYT)) {
-		printf("Error: The RDCU data to compress buffer and the RDCU "
-		       "compressed data buffer are overlapping.\n");
+			    cfg->rdcu_buffer_adr + cfg->buffer_length * IMA_SAM2BYT)) {
+		debug_print("Error: The RDCU data to compress buffer and the RDCU compressed data buffer are overlapping.\n");
 		cfg_invalid++;
 	}
 
 	if (model_mode_is_used(cfg->cmp_mode)) {
-		if (cfg->model_buf == cfg->input_buf) {
-			printf("Error: The model buffer (model_buf) and the data "
-			       "to be compressed (input_buf) are equal.");
+		if (cfg->model_buf && cfg->model_buf == cfg->input_buf) {
+			debug_print("Error: The model buffer (model_buf) and the data to be compressed (input_buf) are equal.");
 			cfg_invalid++;
 		}
 
-		if (!cfg->model_buf) {
-			printf("Warning: The model buffer is set to NULL. No "
-			       "model data will be transferred to the "
-			       "rdcu_model_adr in the RDCU-SRAM.\n");
-			cfg_warning++;
-		}
-
 		if (cfg->rdcu_model_adr & 0x3) {
-			printf("Error: The RDCU model start address is not 4-Byte aligned.\n");
+			debug_print("Error: The RDCU model start address is not 4-Byte aligned.\n");
 			cfg_invalid++;
 		}
 
-		if (!in_sram_range(cfg->rdcu_model_adr, cfg->samples * SAM2BYT)) {
-			printf("Error: The RDCU model buffer is outside the RDCU SRAM address space.\n");
+		if (!in_sram_range(cfg->rdcu_model_adr, cfg->samples * IMA_SAM2BYT)) {
+			debug_print("Error: The RDCU model buffer is outside the RDCU SRAM address space.\n");
 			cfg_invalid++;
 		}
 
 		if (buffers_overlap(
 			    cfg->rdcu_model_adr,
-			    cfg->rdcu_model_adr + cfg->samples * SAM2BYT,
+			    cfg->rdcu_model_adr + cfg->samples * IMA_SAM2BYT,
 			    cfg->rdcu_data_adr,
-			    cfg->rdcu_data_adr + cfg->samples * SAM2BYT)) {
-			printf("Error: The model buffer and the data to compress buffer are overlapping.\n");
+			    cfg->rdcu_data_adr + cfg->samples * IMA_SAM2BYT)) {
+			debug_print("Error: The model buffer and the data to compress buffer are overlapping.\n");
 			cfg_invalid++;
 		}
 
 		if (buffers_overlap(
 			cfg->rdcu_model_adr,
-			cfg->rdcu_model_adr + cfg->samples * SAM2BYT,
+			cfg->rdcu_model_adr + cfg->samples * IMA_SAM2BYT,
 			cfg->rdcu_buffer_adr,
-			cfg->rdcu_buffer_adr + cfg->buffer_length * SAM2BYT)
-		    ){
-			printf("Error: The model buffer and the compressed data buffer are overlapping.\n");
+			cfg->rdcu_buffer_adr + cfg->buffer_length * IMA_SAM2BYT)
+		    ) {
+			debug_print("Error: The model buffer and the compressed data buffer are overlapping.\n");
 			cfg_invalid++;
 		}
 
 		if (cfg->rdcu_model_adr != cfg->rdcu_new_model_adr) {
 			if (cfg->rdcu_new_model_adr & 0x3) {
-				printf("Error: The RDCU updated model start address "
-				       "(rdcu_new_model_adr) is not 4-Byte aligned.\n");
+				debug_print("Error: The RDCU updated model start address (rdcu_new_model_adr) is not 4-Byte aligned.\n");
 				cfg_invalid++;
 			}
 
 			if (!in_sram_range(cfg->rdcu_new_model_adr,
-					   cfg->samples * SAM2BYT)) {
-				printf("Error: The RDCU updated model buffer is "
-				       "outside the RDCU SRAM address space.\n");
+					   cfg->samples * IMA_SAM2BYT)) {
+				debug_print("Error: The RDCU updated model buffer is outside the RDCU SRAM address space.\n");
 				cfg_invalid++;
 			}
 
 			if (buffers_overlap(
 				cfg->rdcu_new_model_adr,
-				cfg->rdcu_new_model_adr + cfg->samples * SAM2BYT,
+				cfg->rdcu_new_model_adr + cfg->samples * IMA_SAM2BYT,
 				cfg->rdcu_data_adr,
-				cfg->rdcu_data_adr + cfg->samples * SAM2BYT)
-			    ){
-				printf("Error: The updated model buffer and the data to "
-				       "compress buffer are overlapping.\n");
+				cfg->rdcu_data_adr + cfg->samples * IMA_SAM2BYT)
+			    ) {
+				debug_print("Error: The updated model buffer and the data to compress buffer are overlapping.\n");
 				cfg_invalid++;
 			}
 
 			if (buffers_overlap(
 				cfg->rdcu_new_model_adr,
-				cfg->rdcu_new_model_adr + cfg->samples * SAM2BYT,
+				cfg->rdcu_new_model_adr + cfg->samples * IMA_SAM2BYT,
 				cfg->rdcu_buffer_adr,
-				cfg->rdcu_buffer_adr + cfg->buffer_length * SAM2BYT)
-			    ){
-				printf("Error: The updated model buffer and the compressed "
-				       "data buffer are overlapping.\n");
+				cfg->rdcu_buffer_adr + cfg->buffer_length * IMA_SAM2BYT)
+			    ) {
+				debug_print("Error: The updated model buffer and the compressed data buffer are overlapping.\n");
 				cfg_invalid++;
 			}
 			if (buffers_overlap(
 				cfg->rdcu_new_model_adr,
-				cfg->rdcu_new_model_adr + cfg->samples * SAM2BYT,
+				cfg->rdcu_new_model_adr + cfg->samples * IMA_SAM2BYT,
 				cfg->rdcu_model_adr,
-				cfg->rdcu_model_adr + cfg->samples * SAM2BYT)
-			    ){
-				printf("Error: The updated model buffer and the "
-				       "model buffer are overlapping.\n");
+				cfg->rdcu_model_adr + cfg->samples * IMA_SAM2BYT)
+			    ) {
+				debug_print("Error: The updated model buffer and the model buffer are overlapping.\n");
 				cfg_invalid++;
 			}
 		}
 	}
 
-	if (cfg->icu_new_model_buf) {
-		printf("Warning: ICU updated model buffer is set. This "
-		       "buffer is not used for an RDCU compression.\n");
-		cfg_warning++;
+	if (cfg->icu_new_model_buf)
+		debug_print("Warning: ICU updated model buffer is set. This buffer is not used for an RDCU compression.\n");
+
+	if (cfg->icu_output_buf)
+		debug_print("Warning: ICU compressed data buffer is set. This buffer is not used for an RDCU compression.\n");
+
+#ifdef SKIP_CMP_PAR_CHECK
+	return 0;
+#endif
+	return -cfg_invalid;
+}
+
+
+/**
+ * @brief setup of the different data buffers for an RDCU compression
+ *
+ * @param cfg			pointer to a compression configuration (created
+ *				with the rdcu_cfg_create() function)
+ * @param data_to_compress	pointer to the data to be compressed (if NULL no
+ *				data transfer to the RDCU)
+ * @param data_samples		length of the data to be compressed measured in
+ *				16-bit data samples (ignoring the collection header)
+ * @param model_of_data		pointer to model data buffer (only needed for
+ *				model compression mode, if NULL no model data
+ *				transfer to the RDCU)
+ * @param rdcu_data_adr		RDCU SRAM data to compress start address
+ * @param rdcu_model_adr	RDCU SRAM model start address (only need for
+ *				model compression mode)
+ * @param rdcu_new_model_adr	RDCU SRAM new/updated model start address(can be the
+ *				by the same as rdcu_model_adr for in-place model update)
+ * @param rdcu_buffer_adr	RDCU SRAM compressed data start address
+ * @param rdcu_buffer_lenght	length of the RDCU compressed data SRAM buffer
+ *				measured in 16-bit units (same as data_samples)
+ *
+ * @returns 0 if parameters are valid, non-zero if parameters are invalid
+ */
+
+int rdcu_cfg_buffers(struct cmp_cfg *cfg, uint16_t *data_to_compress,
+		     uint32_t data_samples, uint16_t *model_of_data,
+		     uint32_t rdcu_data_adr, uint32_t rdcu_model_adr,
+		     uint32_t rdcu_new_model_adr, uint32_t rdcu_buffer_adr,
+		     uint32_t rdcu_buffer_lenght)
+{
+	if (!cfg) {
+		debug_print("Error: pointer to the compression configuration structure is NULL.\n");
+		return -1;
 	}
 
-	if (cfg->icu_output_buf) {
-		printf("Warning: ICU compressed data buffer is set. This "
-		       "buffer is not used for an RDCU compression.\n");
-		cfg_warning++;
+	cfg->input_buf = data_to_compress;
+	cfg->samples = data_samples;
+	cfg->model_buf = model_of_data;
+	cfg->rdcu_data_adr = rdcu_data_adr;
+	cfg->rdcu_model_adr = rdcu_model_adr;
+	cfg->rdcu_new_model_adr = rdcu_new_model_adr;
+	cfg->rdcu_buffer_adr = rdcu_buffer_adr;
+	cfg->buffer_length = rdcu_buffer_lenght;
+
+	if (rdcu_cfg_buffers_is_invalid(cfg))
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * @brief check if the Golomb and spillover threshold parameter combination is
+ *	invalid for an RDCU compression
+ * @note also checked the adaptive Golomb and spillover threshold parameter combinations
+ *
+ * @param cfg	a pointer to a compression configuration
+ *
+ * @returns 0 if (adaptive) Golomb spill threshold parameter combinations are
+ *	valid, otherwise the configuration is invalid
+ */
+
+static int rdcu_cfg_imagette_is_invalid(const struct cmp_cfg *cfg)
+{
+	int cfg_invalid = 0;
+
+	if (cfg->golomb_par < MIN_IMA_GOLOMB_PAR ||
+	    cfg->golomb_par > MAX_IMA_GOLOMB_PAR) {
+		debug_print("Error: The selected Golomb parameter: %u is not supported. The Golomb parameter has to be between [%u, %u].\n",
+			    cfg->golomb_par, MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+		cfg_invalid++;
+	}
+
+	if (cfg->ap1_golomb_par < MIN_IMA_GOLOMB_PAR ||
+	    cfg->ap1_golomb_par > MAX_IMA_GOLOMB_PAR) {
+		debug_print("Error: The selected adaptive 1 Golomb parameter: %u is not supported. The Golomb parameter has to be between [%u, %u].\n",
+			    cfg->ap1_golomb_par, MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+		cfg_invalid++;
+	}
+
+	if (cfg->ap2_golomb_par < MIN_IMA_GOLOMB_PAR ||
+	    cfg->ap2_golomb_par > MAX_IMA_GOLOMB_PAR) {
+		debug_print("Error: The selected adaptive 2 Golomb parameter: %u is not supported. The Golomb parameter has to be between [%u, %u].\n",
+			    cfg->ap2_golomb_par, MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+		cfg_invalid++;
+	}
+
+	if (cfg->spill < MIN_IMA_SPILL) {
+		debug_print("Error: The selected spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n",
+			    cfg->spill, MIN_IMA_SPILL);
+		cfg_invalid++;
+	}
+
+	if (cfg->spill > cmp_ima_max_spill(cfg->golomb_par)) {
+		debug_print("Error: The selected spillover threshold value: %u is too large for the selected Golomb parameter: %u, the largest possible spillover value is: %u.\n",
+			    cfg->spill, cfg->golomb_par, cmp_ima_max_spill(cfg->golomb_par));
+		cfg_invalid++;
+	}
+
+	if (cfg->ap1_spill < MIN_IMA_SPILL) {
+		debug_print("Error: The selected adaptive 1 spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n",
+			    cfg->ap1_spill, MIN_IMA_SPILL);
+		cfg_invalid++;
+	}
+
+	if (cfg->ap1_spill > cmp_ima_max_spill(cfg->ap1_golomb_par)) {
+		debug_print("Error: The selected adaptive 1 spillover threshold value: %u is too large for the selected adaptive 1 Golomb parameter: %u, the largest possible adaptive 1 spillover value is: %u.\n",
+			    cfg->ap1_spill, cfg->ap1_golomb_par, cmp_ima_max_spill(cfg->ap1_golomb_par));
+		cfg_invalid++;
+	}
+
+	if (cfg->ap2_spill < MIN_IMA_SPILL) {
+		debug_print("Error: The selected adaptive 2 spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n",
+			    cfg->ap2_spill, MIN_IMA_SPILL);
+		cfg_invalid++;
+	}
+
+	if (cfg->ap2_spill > cmp_ima_max_spill(cfg->ap2_golomb_par)) {
+		debug_print("Error: The selected adaptive 2 spillover threshold value: %u is too large for the selected adaptive 2 Golomb parameter: %u, the largest possible adaptive 2 spillover value is: %u.\n",
+			    cfg->ap2_spill, cfg->ap2_golomb_par, cmp_ima_max_spill(cfg->ap2_golomb_par));
+		cfg_invalid++;
 	}
 
 #ifdef SKIP_CMP_PAR_CHECK
 	return 0;
 #endif
-	if (cfg_invalid)
-		return -cfg_invalid;
-	else
-		return cfg_warning;
+
+	return -cfg_invalid;
+}
+
+
+/**
+ * @brief set up the configuration parameters for an RDCU imagette compression
+ *
+ * @param cfg			pointer to a compression configuration (created
+ *				with the rdcu_cfg_create() function)
+ * @param golomb_par		imagette compression parameter
+ * @param spillover_par		imagette spillover threshold parameter
+ * @param ap1_golomb_par	adaptive 1 imagette compression parameter
+ * @param ap1_spillover_par	adaptive 1 imagette spillover threshold parameter
+ * @param ap2_golomb_par	adaptive 2 imagette compression parameter
+ * @param ap2_spillover_par	adaptive 2 imagette spillover threshold parameter
+ *
+ * @returns 0 if parameters are valid, non-zero if parameters are invalid
+ */
+
+int rdcu_cfg_imagette(struct cmp_cfg *cfg,
+		      uint32_t golomb_par, uint32_t spillover_par,
+		      uint32_t ap1_golomb_par, uint32_t ap1_spillover_par,
+		      uint32_t ap2_golomb_par, uint32_t ap2_spillover_par)
+{
+	if (!cfg) {
+		debug_print("Error: pointer to the compression configuration structure is NULL.\n");
+		return -1;
+	}
+
+	cfg->golomb_par = golomb_par;
+	cfg->spill = spillover_par;
+	cfg->ap1_golomb_par = ap1_golomb_par;
+	cfg->ap1_spill = ap1_spillover_par;
+	cfg->ap2_golomb_par = ap2_golomb_par;
+	cfg->ap2_spill = ap2_spillover_par;
+
+	if (rdcu_cfg_imagette_is_invalid(cfg))
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * @brief check if the compressor configuration is invalid for an RDCU compression,
+ *	see the user manual for more information (PLATO-UVIE-PL-UM-0001).
+ *
+ * @param cfg	pointer to a compression configuration contains all parameters
+ *	required for compression
+ *
+ * @returns 0 if parameters are valid, non-zero if parameters are invalid
+ */
+
+int rdcu_cmp_cfg_is_invalid(const struct cmp_cfg *cfg)
+{
+	int cfg_invalid = 0;
+
+	if (!cfg) {
+		debug_print("Error: pointer to the compression configuration structure is NULL.\n");
+		return -1;
+	}
+
+	if (!cfg->input_buf)
+		debug_print("Warning: The data to compress buffer is set to NULL. No data will be transferred to the rdcu_data_adr in the RDCU-SRAM.\n");
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		if (!cfg->model_buf)
+			debug_print("Warning: The model buffer is set to NULL. No model data will be transferred to the rdcu_model_adr in the RDCU-SRAM.\n");
+	}
+
+	if (cfg->input_buf && cfg->samples == 0)
+		debug_print("Warning: The samples parameter is set to 0. No data will be compressed.\n");
+
+	if (cfg->buffer_length == 0) {
+		debug_print("Error: The buffer_length is set to 0. There is no place to store the compressed data.\n");
+		cfg_invalid++;
+	}
+
+	if (rdcu_cfg_gen_par_is_invalid(cfg))
+		cfg_invalid++;
+	if (rdcu_cfg_buffers_is_invalid(cfg))
+		cfg_invalid++;
+	if (rdcu_cfg_imagette_is_invalid(cfg))
+		cfg_invalid++;
+
+	return -cfg_invalid;
 }
 
 
 /**
  * @brief set up RDCU compression register
  *
- * @param cfg  configuration contains all parameters required for compression
+ * @param cfg  pointer to a compression configuration contains all parameters
+ *	required for compression
  *
  * @returns 0 on success, error otherwise
  */
 
 int rdcu_set_compression_register(const struct cmp_cfg *cfg)
 {
-	if (rdcu_cmp_cfg_valid(cfg) < 0)
+	if (rdcu_cmp_cfg_is_invalid(cfg))
 		return -1;
 
 	/* first, set compression parameters in local mirror registers */
@@ -507,12 +676,11 @@ int rdcu_start_compression(void)
  *
  * @param cfg  configuration contains all parameters required for compression
  *
- * @note when using the 1d-differencing mode or the raw mode (cmp_mode = 0,2,4),
- *      the model parameters (model_value, model_buf, rdcu_model_adr) are ignored
- * @note the icu_output_buf will not be used for the RDCU compression
- * @note the overlapping of the different rdcu buffers is not checked
- * @note the validity of the cfg structure is checked before the compression is
- *	 started
+ * @note Before the rdcu_compress function can be used, an initialisation of
+ *	the RMAP library is required. This is achieved with the functions
+ *	rdcu_ctrl_init() and rdcu_rmap_init().
+ * @note The validity of the cfg structure is checked before the compression is
+ *	 started.
  *
  * @returns 0 on success, error otherwise
  */
@@ -593,7 +761,7 @@ int rdcu_read_cmp_status(struct cmp_status *status)
 
 
 /**
- * @brief read out the metadata of a RDCU compression
+ * @brief read out the metadata of an RDCU compression
  *
  * @param info  compression information contains the metadata of a compression
  *
@@ -637,9 +805,9 @@ int rdcu_read_cmp_info(struct cmp_info *info)
 		info->rdcu_new_model_adr_used = rdcu_get_new_model_addr_used();
 		info->samples_used = rdcu_get_samples_used();
 		info->rdcu_cmp_adr_used = rdcu_get_compr_data_start_addr();
-		info->cmp_size = rdcu_get_compr_data_size();
-		info->ap1_cmp_size = rdcu_get_compr_data_adaptive_1_size();
-		info->ap2_cmp_size = rdcu_get_compr_data_adaptive_2_size();
+		info->cmp_size = rdcu_get_compr_data_size_bit();
+		info->ap1_cmp_size = rdcu_get_compr_data_adaptive_1_size_bit();
+		info->ap2_cmp_size = rdcu_get_compr_data_adaptive_2_size_bit();
 		info->cmp_err = rdcu_get_compr_error();
 	}
 	return 0;
@@ -649,15 +817,14 @@ int rdcu_read_cmp_info(struct cmp_info *info)
 /**
  * @brief read the compressed bitstream from the RDCU SRAM
  *
- * @param info  compression information contains the metadata of a compression
- *
- * @param output_buf  the buffer to store the bitstream (if NULL, the required
- *		      size is returned)
+ * @param info			compression information contains the metadata of a compression
+ * @param compressed_data	the buffer to store the bitstream (if NULL, the
+ *				required size is returned)
  *
  * @returns the number of bytes read, < 0 on error
  */
 
-int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf)
+int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *compressed_data)
 {
 	uint32_t s;
 
@@ -667,7 +834,7 @@ int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf)
 	/* calculate the need bytes for the bitstream */
 	s = cmp_bit_to_4byte(info->cmp_size);
 
-	if (output_buf == NULL)
+	if (compressed_data == NULL)
 		return (int)s;
 
 	if (rdcu_sync_sram_to_mirror(info->rdcu_cmp_adr_used, s,
@@ -677,22 +844,22 @@ int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf)
 	/* wait for it */
 	sync();
 
-	return rdcu_read_sram(output_buf, info->rdcu_cmp_adr_used, s);
+	return rdcu_read_sram(compressed_data, info->rdcu_cmp_adr_used, s);
 }
 
 
 /**
- * @brief read the model from the RDCU SRAM
+ * @brief read the updated model from the RDCU SRAM
  *
- * @param info  compression information contains the metadata of a compression
+ * @param info		compression information contains the metadata of a compression
  *
- * @param model_buf  the buffer to store the model (if NULL, the required size
- *		     is returned)
+ * @param updated_model	the buffer to store the updated model (if NULL, the required size
+ *			is returned)
  *
  * @returns the number of bytes read, < 0 on error
  */
 
-int rdcu_read_model(const struct cmp_info *info, void *model_buf)
+int rdcu_read_model(const struct cmp_info *info, void *updated_model)
 {
 	uint32_t s;
 
@@ -700,9 +867,9 @@ int rdcu_read_model(const struct cmp_info *info, void *model_buf)
 		return -1;
 
 	/* calculate the need bytes for the model */
-	s = cmp_cal_size_of_data(info->samples_used, info->cmp_mode_used);
+	s = info->samples_used * IMA_SAM2BYT;
 
-	if (model_buf == NULL)
+	if (updated_model == NULL)
 		return (int)s;
 
 	if (rdcu_sync_sram_to_mirror(info->rdcu_new_model_adr_used, (s+3) & ~3U,
@@ -712,7 +879,7 @@ int rdcu_read_model(const struct cmp_info *info, void *model_buf)
 	/* wait for it */
 	sync();
 
-	return rdcu_read_sram(model_buf, info->rdcu_new_model_adr_used, s);
+	return rdcu_read_sram(updated_model, info->rdcu_new_model_adr_used, s);
 }
 
 
@@ -790,19 +957,17 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg,
 	if (last_info->cmp_err)
 		return -1;
 
-	/* TODO: check read write buffer overlapping */
-
 	rdcu_set_compression_register(cfg);
 
 	/* round up needed size must be a multiple of 4 bytes */
-	samples_4byte = (cfg->samples * SAM2BYT + 3) & ~3U;
+	samples_4byte = (cfg->samples * IMA_SAM2BYT + 3) & ~3U;
 
 	if (cfg->input_buf != NULL) {
 		uint32_t cmp_size_4byte;
 
 		/* now set the data in the local mirror... */
 		if (rdcu_write_sram_16(cfg->input_buf, cfg->rdcu_data_adr,
-				       cfg->samples * SAM2BYT) < 0)
+				       cfg->samples * IMA_SAM2BYT) < 0)
 			return -1;
 
 		/* calculate the need bytes for the bitstream */
@@ -823,7 +988,7 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg,
 				return -1;
 		}
 	} else {
-		printf("Warning: input_buf = NULL; input_buf is not written to the sram and compressed data is not read from the sram\n");
+		debug_print("Warning: input_buf = NULL; input_buf is not written to the sram and compressed data is not read from the SRAM\n");
 	}
 
 	/* read model and write model in parallel */
@@ -832,10 +997,10 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg,
 
 		/* set the model in the local mirror... */
 		if (rdcu_write_sram_16(cfg->model_buf, cfg->rdcu_model_adr,
-				       cfg->samples * SAM2BYT) < 0)
+				       cfg->samples * IMA_SAM2BYT) < 0)
 			return -1;
 
-		new_model_size_4byte = last_info->samples_used * SAM2BYT ;
+		new_model_size_4byte = last_info->samples_used * IMA_SAM2BYT;
 		if (rdcu_sync_sram_mirror_parallel(last_info->rdcu_new_model_adr_used,
 						   (new_model_size_4byte+3) & ~0x3U,
 						   cfg->rdcu_model_adr,
@@ -853,7 +1018,7 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg,
 	} else if (cfg->model_buf && model_mode_is_used(cfg->cmp_mode)) {
 		/* set the model in the local mirror... */
 		if (rdcu_write_sram_16(cfg->model_buf, cfg->rdcu_model_adr,
-				       cfg->samples * SAM2BYT) < 0)
+				       cfg->samples * IMA_SAM2BYT) < 0)
 			return -1;
 
 		if (rdcu_sync_mirror_to_sram(cfg->rdcu_model_adr, samples_4byte,
diff --git a/lib/cmp_support.c b/lib/cmp_support.c
index a9459718e1a8c79cc913e574e1072b268fff0f72..17deeed1809dd0c03be345763ed50b64953e5c8b 100644
--- a/lib/cmp_support.c
+++ b/lib/cmp_support.c
@@ -18,75 +18,15 @@
  */
 
 
-#include "../include/cmp_support.h"
-#include "../include/cmp_data_types.h"
-#include "../include/cmp_debug.h"
-
-
-/**
- * @brief Default configuration of the Compressor in model imagette mode.
- * @warning All ICU buffers are set to NULL. Samples and buffer_length are set to 0
- * @note see PLATO-IWF-PL-RS-0005 V1.1
- */
-
-
-const struct cmp_cfg DEFAULT_CFG_MODEL = {
-	MODE_MODEL_MULTI, /* cmp_mode */
-	4, /* golomb_par */
-	48, /* spill */
-	8, /* model_value */
-	0, /* round */
-	3, /* ap1_golomb_par */
-	35, /* ap1_spill */
-	5, /* ap2_golomb_par */
-	60, /* ap2_spill */
-	NULL, /* *input_buf */
-	0x000000, /* rdcu_data_adr */
-	NULL, /* *model_buf */
-	0x200000, /* rdcu_model_adr */
-	NULL, /* *icu_new_model_buf */
-	0x400000, /* rdcu_up_model_adr */
-	0, /* samples */
-	NULL, /* *icu_output_buf */
-	0x600000, /* rdcu_buffer_adr */
-	0x0 /* buffer_length */
-};
-
-
-/**
- * @brief Default configuration of the Compressor in 1d-differencing imagette mode.
- * @warning All ICU buffers are set to NULL. Samples and buffer_length are set to 0
- * @note see PLATO-IWF-PL-RS-0005 V1.1
- */
-
-const struct cmp_cfg DEFAULT_CFG_DIFF = {
-	MODE_DIFF_ZERO, /* cmp_mode */
-	7, /* golomb_par */
-	60, /* spill */
-	8, /* model_value */
-	0, /* round */
-	6, /* ap1_golomb_par */
-	48, /* ap1_spill */
-	8, /* ap2_golomb_par */
-	72, /* ap2_spill */
-	NULL, /* *input_buf */
-	0x000000, /* rdcu_data_adr */
-	NULL, /* *model_buf */
-	0x000000, /* rdcu_model_adr */
-	NULL, /* *icu_new_model_buf */
-	0x000000, /* rdcu_up_model_adr */
-	0, /* samples */
-	NULL, /* *icu_output_buf */
-	0x600000, /* rdcu_buffer_adr */
-	0x0 /* buffer_length */
-};
+#include <cmp_support.h>
+#include <cmp_debug.h>
 
 
 /**
  * @brief implementation of the logarithm base of floor(log2(x)) for integers
  * @note ilog_2(0) = -1 defined
  *
- * @param x input parameter
+ * @param x	input parameter
  *
  * @returns the result of floor(log2(x))
  */
@@ -101,10 +41,10 @@ int ilog_2(uint32_t x)
 
 
 /**
- * @brief Determining if an integer is a power of 2
+ * @brief determining if an integer is a power of 2
  * @note 0 is incorrectly considered a power of 2 here
  *
- * @param v we want to see if v is a power of 2
+ * @param v	we want to see if v is a power of 2
  *
  * @returns 1 if v is a power of 2, otherwise 0
  *
@@ -117,231 +57,274 @@ int is_a_pow_of_2(unsigned int v)
 }
 
 
+/**
+ * @brief check if the compression entity data product type is supported
+ *
+ * @param data_type	compression entity data product type to check
+ *
+ * @returns zero if data_type is invalid; non-zero if data_type is valid
+ */
+
+int cmp_data_type_valid(enum cmp_data_type data_type)
+{
+	if (data_type == DATA_TYPE_F_CAM_OFFSET)
+		debug_print("Error: DATA_TYPE_F_CAM_OFFSET is TBD and not implemented yet.\n");
+	if (data_type == DATA_TYPE_F_CAM_BACKGROUND)
+		debug_print("Error: DATA_TYPE_F_CAM_BACKGROUND is TBD  and not implemented yet.\n");
+
+	if (data_type <= DATA_TYPE_UNKNOWN || data_type > DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE)
+		return 0;
+
+	return 1;
+}
+
+
 /**
  * @brief check if a model mode is selected
  *
- * @param cmp_mode compression mode
+ * @param cmp_mode	compression mode
  *
- * @returns 1 when model mode is set, otherwise 0
+ * @returns 1 when the model mode is used, otherwise 0
  */
 
-int model_mode_is_used(unsigned int cmp_mode)
+int model_mode_is_used(enum cmp_mode cmp_mode)
 {
-	switch (cmp_mode) {
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_ZERO_F_FX_EFX:
-	case MODE_MODEL_ZERO_F_FX_NCOB:
-	case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_MODEL_MULTI_F_FX_EFX:
-	case MODE_MODEL_MULTI_F_FX_NCOB:
-	case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_ZERO_32:
-	case MODE_MODEL_MULTI_32:
+	if (cmp_mode == CMP_MODE_MODEL_ZERO ||
+	    cmp_mode == CMP_MODE_MODEL_MULTI)
 		return 1;
-		break;
-	default:
-		return 0;
-		break;
-	}
+
+	return 0;
 }
 
 
 /**
  * @brief check if a 1d-differencing mode is selected
  *
- * @param cmp_mode compression mode
+ * @param cmp_mode	compression mode
  *
- * @returns 1 when 1d-differencing mode is set, otherwise 0
+ * @returns 1 when the 1d-differencing mode is used, otherwise 0
  */
 
-int diff_mode_is_used(unsigned int cmp_mode)
+int diff_mode_is_used(enum cmp_mode cmp_mode)
 {
-	switch (cmp_mode) {
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_ZERO_F_FX_EFX:
-	case MODE_DIFF_ZERO_F_FX_NCOB:
-	case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI:
-	case MODE_DIFF_MULTI_S_FX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_F_FX:
-	case MODE_DIFF_MULTI_F_FX_EFX:
-	case MODE_DIFF_MULTI_F_FX_NCOB:
-	case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_32:
-	case MODE_DIFF_MULTI_32:
+	if (cmp_mode == CMP_MODE_DIFF_ZERO ||
+	    cmp_mode == CMP_MODE_DIFF_MULTI)
 		return 1;
-		break;
-	default:
-		return 0;
-		break;
-	}
+
+	return 0;
 }
 
 
 /**
  * @brief check if the raw mode is selected
  *
- * @param cmp_mode compression mode
+ * @param cmp_mode	compression mode
  *
- * @returns 1 when raw mode is set, otherwise 0
+ * @returns 1 when the raw mode is used, otherwise 0
  */
 
-int raw_mode_is_used(unsigned int cmp_mode)
+int raw_mode_is_used(enum cmp_mode cmp_mode)
+{
+	if (cmp_mode == CMP_MODE_RAW)
+		return 1;
+
+	return 0;
+}
+
+
+/**
+ * @brief check if the compression mode is supported by the RDCU compressor
+ *
+ * @param cmp_mode	compression mode
+ *
+ * @returns 1 when the compression mode is supported by the RDCU, otherwise 0
+ */
+
+int rdcu_supported_cmp_mode_is_used(enum cmp_mode cmp_mode)
 {
 	switch (cmp_mode) {
-	case MODE_RAW:
-	case MODE_RAW_S_FX:
-	case MODE_RAW_32:
+	case CMP_MODE_RAW:
+	case CMP_MODE_MODEL_ZERO:
+	case CMP_MODE_DIFF_ZERO:
+	case CMP_MODE_MODEL_MULTI:
+	case CMP_MODE_DIFF_MULTI:
 		return 1;
-		break;
+	case CMP_MODE_STUFF:
 	default:
 		return 0;
-		break;
 	}
+
 }
 
 
 /**
- * @brief check if the mode is supported by the RDCU compressor
+ * @brief check if the data product data type is supported by the RDCU compressor
  *
- * @param cmp_mode compression mode
+ * @param data_type	compression data product type
  *
- * @returns 1 when mode is supported by the RDCU, otherwise 0
+ * @returns 1 when the data type is supported by the RDCU, otherwise 0
  */
 
-int rdcu_supported_mode_is_used(unsigned int cmp_mode)
+int rdcu_supported_data_type_is_used(enum cmp_data_type data_type)
 {
-	switch (cmp_mode) {
-	case MODE_RAW:
-	case MODE_MODEL_ZERO:
-	case MODE_DIFF_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_MULTI:
+	switch (data_type) {
+	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
 		return 1;
-		break;
 	default:
 		return 0;
-		break;
 	}
 }
 
 
 /**
- * @brief check if the mode is available
+ * @brief check if the compression mode is supported for an ICU compression
  *
- * @param cmp_mode compression mode
+ * @param cmp_mode	compression mode
  *
- * @returns 1 when mode is available, otherwise 0
+ * @returns 1 when the compression mode is supported, otherwise 0
  */
 
-int cmp_mode_available(unsigned int cmp_mode)
+int cmp_mode_is_supported(enum cmp_mode cmp_mode)
 {
-	if (diff_mode_is_used(cmp_mode) ||
-	    model_mode_is_used(cmp_mode) ||
-	    raw_mode_is_used(cmp_mode))
+	switch (cmp_mode) {
+	case CMP_MODE_RAW:
+	case CMP_MODE_MODEL_ZERO:
+	case CMP_MODE_DIFF_ZERO:
+	case CMP_MODE_MODEL_MULTI:
+	case CMP_MODE_DIFF_MULTI:
+	case CMP_MODE_STUFF:
 		return 1;
-	else
-		return 0;
-
+	}
+	return 0;
 }
 
 
 /**
  * @brief check if zero escape symbol mechanism mode is used
  *
- * @param cmp_mode compression mode
+ * @param cmp_mode	compression mode
  *
  * @returns 1 when zero escape symbol mechanism is set, otherwise 0
  */
 
-int zero_escape_mech_is_used(unsigned int cmp_mode)
+int zero_escape_mech_is_used(enum cmp_mode cmp_mode)
 {
-	switch (cmp_mode) {
-	case MODE_MODEL_ZERO:
-	case MODE_DIFF_ZERO:
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_MODEL_ZERO_F_FX_EFX:
-	case MODE_DIFF_ZERO_F_FX_EFX:
-	case MODE_MODEL_ZERO_F_FX_NCOB:
-	case MODE_DIFF_ZERO_F_FX_NCOB:
-	case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_ZERO_32:
-	case MODE_DIFF_ZERO_32:
+	if (cmp_mode == CMP_MODE_MODEL_ZERO ||
+	    cmp_mode == CMP_MODE_DIFF_ZERO)
+		return 1;
+
+	return 0;
+}
+
+
+/**
+ * @brief check if multi escape symbol mechanism mode is used
+ *
+ * @param cmp_mode	compression mode
+ *
+ * @returns 1 when multi escape symbol mechanism is set, otherwise 0
+ */
+
+int multi_escape_mech_is_used(enum cmp_mode cmp_mode)
+{
+	if (cmp_mode == CMP_MODE_MODEL_MULTI ||
+	    cmp_mode == CMP_MODE_DIFF_MULTI)
+		return 1;
+
+	return 0;
+}
+
+
+/**
+ * @brief check if an imagette compression data type is used
+ * @note adaptive imagette compression data types included
+ *
+ * @param data_type	compression data type
+ *
+ * @returns 1 when data_type is an imagette data type, otherwise 0
+ */
+
+int cmp_imagette_data_type_is_used(enum cmp_data_type data_type)
+{
+	return rdcu_supported_data_type_is_used(data_type);
+}
+
+
+/**
+ * @brief check if an adaptive imagette compression data type is used
+ *
+ * @param data_type	compression data type
+ *
+ * @returns 1 when data_type is an adaptive imagette data type, otherwise 0
+ */
+
+int cmp_ap_imagette_data_type_is_used(enum cmp_data_type data_type)
+{
+	switch (data_type) {
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
 		return 1;
-		break;
 	default:
 		return 0;
-		break;
 	}
+}
+
+
+/**
+ * @brief check if a flux/center of brightness compression data type is used
+ *
+ * @param data_type	compression data type
+ *
+ * @returns 1 when data_type is a flux/center of brightness data type, otherwise 0
+ */
 
+int cmp_fx_cob_data_type_is_used(enum cmp_data_type data_type)
+{
+	switch (data_type) {
+	case DATA_TYPE_S_FX:
+	case DATA_TYPE_S_FX_EFX:
+	case DATA_TYPE_S_FX_NCOB:
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+	case DATA_TYPE_L_FX:
+	case DATA_TYPE_L_FX_EFX:
+	case DATA_TYPE_L_FX_NCOB:
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+	case DATA_TYPE_F_FX:
+	case DATA_TYPE_F_FX_EFX:
+	case DATA_TYPE_F_FX_NCOB:
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		return 1;
+	default:
+		return 0;
+	}
 }
 
 
 /**
- * @brief check if multi escape symbol mechanism mode is used
+ * @brief check if an auxiliary science compression data type is used
  *
- * @param cmp_mode compression mode
+ * @param data_type	compression data type
  *
- * @returns 1 when multi escape symbol mechanism is set, otherwise 0
+ * @returns 1 when data_type is an auxiliary science data type, otherwise 0
  */
 
-int multi_escape_mech_is_used(unsigned int cmp_mode)
+int cmp_aux_data_type_is_used(enum cmp_data_type data_type)
 {
-	switch (cmp_mode) {
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_MULTI:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-	case MODE_MODEL_MULTI_F_FX_EFX:
-	case MODE_DIFF_MULTI_F_FX_EFX:
-	case MODE_MODEL_MULTI_F_FX_NCOB:
-	case MODE_DIFF_MULTI_F_FX_NCOB:
-	case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_32:
-	case MODE_DIFF_MULTI_32:
+	switch (data_type) {
+	case DATA_TYPE_OFFSET:
+	case DATA_TYPE_BACKGROUND:
+	case DATA_TYPE_SMEARING:
+	case DATA_TYPE_F_CAM_OFFSET:
+	case DATA_TYPE_F_CAM_BACKGROUND:
 		return 1;
-		break;
 	default:
 		return 0;
-		break;
 	}
 }
 
@@ -349,8 +332,8 @@ int multi_escape_mech_is_used(unsigned int cmp_mode)
 /**
  * @brief method for lossy rounding
  *
- * @param value value to round
- * @param round round parameter
+ * @param value	the value to round
+ * @param round	rounding parameter
  *
  * @return rounded value
  */
@@ -364,8 +347,8 @@ unsigned int round_fwd(unsigned int value, unsigned int round)
 /**
  * @brief inverse method for lossy rounding
  *
- * @param value value to round back
- * @param round round parameter
+ * @param value	the value to round back
+ * @param round	rounding parameter
  *
  * @return back rounded value
  */
@@ -378,9 +361,8 @@ unsigned int round_inv(unsigned int value, unsigned int round)
 
 /**
  * @brief implantation of the model update equation
- *
  * @note check before that model_value is not greater than MAX_MODEL_VALUE
-
+ *
  * @param data		data to process
  * @param model		(current) model of the data to process
  * @param model_value	model weighting parameter
@@ -388,203 +370,502 @@ unsigned int round_inv(unsigned int value, unsigned int round)
  * @returns (new) updated model
  */
 
-unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int
-			  model_value)
+unsigned int cmp_up_model(unsigned int data, unsigned int model,
+			  unsigned int model_value, unsigned int round)
+
 {
+	uint64_t weighted_model, weighted_data;
+
+	/* round and round back input because for decompression the accurate
+	 * data values are not available
+	 */
+	data = round_inv(round_fwd(data, round), round);
 	/* cast uint64_t to prevent overflow in the multiplication */
-	uint64_t weighted_model = (uint64_t)model * model_value;
-	uint64_t weighted_data = (uint64_t)data * (MAX_MODEL_VALUE - model_value);
+	weighted_model = (uint64_t)model * model_value;
+	weighted_data = (uint64_t)data * (MAX_MODEL_VALUE - model_value);
 	/* truncation is intended */
 	return (unsigned int)((weighted_model + weighted_data) / MAX_MODEL_VALUE);
 }
 
 
 /**
- * @brief get the maximum valid spill threshold value for a given golomb_par
+ * @brief get the maximum valid spill threshold value for a RDCU HW imagette
+ *	compression in diff or model mode
  *
- * @param golomb_par Golomb parameter
- * @param cmp_mode   compression mode
+ * @param golomb_par	Golomb parameter
  *
- * @returns the highest still valid spill threshold value
+ * @returns the highest still valid spill threshold value for a diff of model
+ *	 mode compression; 0 if golomb_par is invalid
  */
 
-uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode)
+uint32_t cmp_ima_max_spill(unsigned int golomb_par)
 {
-	const uint32_t LUT_MAX_RDCU[MAX_RDCU_GOLOMB_PAR+1] = { 0, 8, 22, 35, 48,
+	/* the RDCU can only generate 16 bit long code words -> lower max spill needed */
+	const uint32_t LUT_MAX_RDCU[MAX_IMA_GOLOMB_PAR+1] = { 0, 8, 22, 35, 48,
 		60, 72, 84, 96, 107, 118, 129, 140, 151, 162, 173, 184, 194,
 		204, 214, 224, 234, 244, 254, 264, 274, 284, 294, 304, 314, 324,
 		334, 344, 353, 362, 371, 380, 389, 398, 407, 416, 425, 434, 443,
 		452, 461, 470, 479, 488, 497, 506, 515, 524, 533, 542, 551, 560,
 		569, 578, 587, 596, 605, 614, 623 };
 
-	if (golomb_par == 0)
+
+	if (golomb_par > MAX_IMA_GOLOMB_PAR)
 		return 0;
 
-	if (rdcu_supported_mode_is_used(cmp_mode)) {
-		if (golomb_par > MAX_RDCU_GOLOMB_PAR)
-			return 0;
+	return LUT_MAX_RDCU[golomb_par];
+}
 
-		return LUT_MAX_RDCU[golomb_par];
-	} else {
-		if (golomb_par > MAX_ICU_GOLOMB_PAR) {
-			return 0;
-		} else {
-			/* the ICU compressor can generate code words with a length of
-			 * maximal 32 bits.  */
-			unsigned int max_cw_bits = 32;
-			unsigned int cutoff = (1UL << (ilog_2(golomb_par)+1)) - golomb_par;
-			unsigned int max_n_sym_offset = max_cw_bits/2 - 1;
-			return (max_cw_bits-1-ilog_2(golomb_par))*golomb_par + cutoff -
-				max_n_sym_offset - 1;
+
+/**
+ * @brief get the maximum valid spill threshold value for a ICU SW compression
+ *	in diff or model mode
+ *
+ * @param cmp_par	compression parameter
+ *
+ * @returns the highest still valid spill threshold value for diff or model
+ *	mode compression; 0 if the cmp_par is not valid
+ */
+
+uint32_t cmp_icu_max_spill(unsigned int cmp_par)
+{
+	/* the ICU compressor can generate code words with a length of maximal 32 bits. */
+	unsigned int max_cw_bits = 32;
+	unsigned int cutoff = (1UL << (ilog_2(cmp_par)+1)) - cmp_par;
+	unsigned int max_n_sym_offset = max_cw_bits/2 - 1;
+
+	if (!cmp_par || cmp_par > MAX_ICU_GOLOMB_PAR)
+		return 0;
+
+	return (max_cw_bits-1-ilog_2(cmp_par))*cmp_par + cutoff
+		- max_n_sym_offset - 1;
+}
+
+
+/**
+ * @brief calculate the need bytes to hold a bitstream
+ *
+ * @param cmp_size_bit	compressed data size, measured in bits
+ *
+ * @returns the size in bytes to store the hole bitstream
+ * @note we round up the result to multiples of 4 bytes
+ */
+
+unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit)
+{
+	return (((cmp_size_bit + 7) / 8) + 3) & ~0x3UL;
+}
+
+
+/**
+ * @brief check if the compression data type, compression mode, model value and
+ *	the lossy rounding parameters are invalid for a ICU compression
+ *
+ * @param cfg	pointer to the compressor configuration
+ *
+ * @returns 0 if generic compression parameters are valid, otherwise invalid
+ */
+
+int cmp_cfg_icu_gen_par_is_invalid(const struct cmp_cfg *cfg)
+{
+	int cfg_invalid = 0;
+
+	if (!cfg)
+		return 0;
+
+	if (!cmp_data_type_valid(cfg->data_type)) {
+		debug_print("Error: selected compression data type is not supported.\n");
+		cfg_invalid++;
+	}
+
+	if (cfg->cmp_mode > CMP_MODE_STUFF) {
+		debug_print("Error: selected cmp_mode: %i is not supported.\n", cfg->cmp_mode);
+		cfg_invalid++;
+	}
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		if (cfg->model_value > MAX_MODEL_VALUE) {
+			debug_print("Error: selected model_value: %u is invalid. Largest supported value is: %u.\n",
+				    cfg->model_value, MAX_MODEL_VALUE);
+			cfg_invalid++;
 		}
 	}
+
+	if (cfg->round > MAX_ICU_ROUND) {
+		debug_print("Error: selected lossy parameter: %u is not supported. Largest supported value is: %u.\n",
+			    cfg->round, MAX_ICU_ROUND);
+		cfg_invalid++;
+	}
+
+	return cfg_invalid;
 }
 
 
 /**
- * @brief get a good spill threshold parameter for the selected Golomb parameter
- *	and compression mode
+ * @brief check if the buffer parameters are invalid
  *
- * @param golomb_par Golomb parameter
- * @param cmp_mode compression mode
+ * @param cfg	pointer to the compressor configuration
  *
- * @returns a good spill parameter (optimal for zero escape mechanism)
- * @warning icu compression not support yet!
+ * @returns 0 if the buffer parameters are valid, otherwise invalid
  */
 
-uint32_t cmp_get_good_spill(unsigned int golomb_par, unsigned int cmp_mode)
+int cmp_cfg_icu_buffers_is_invalid(const struct cmp_cfg *cfg)
 {
-	const uint32_t LUT_RDCU_MULIT[MAX_RDCU_GOLOMB_PAR+1] = {0, 8, 16, 23,
-		30, 36, 44, 51, 58, 64, 71, 77, 84, 90, 97, 108, 115, 121, 128,
-		135, 141, 148, 155, 161, 168, 175, 181, 188, 194, 201, 207, 214,
-		229, 236, 242, 250, 256, 263, 269, 276, 283, 290, 296, 303, 310,
-		317, 324, 330, 336, 344, 351, 358, 363, 370, 377, 383, 391, 397,
-		405, 411, 418, 424, 431, 452 };
-
-	if (zero_escape_mech_is_used(cmp_mode))
-		return get_max_spill(golomb_par, cmp_mode);
-
-	if (cmp_mode == MODE_MODEL_MULTI) {
-		if (golomb_par > MAX_RDCU_GOLOMB_PAR)
-			return 0;
-		else
-			return LUT_RDCU_MULIT[golomb_par];
+	int cfg_invalid = 0;
+
+	if (!cfg)
+		return 0;
+
+	if (cfg->input_buf == NULL) {
+		debug_print("Error: The data_to_compress buffer for the data to be compressed is NULL.\n");
+		cfg_invalid++;
 	}
 
-	if (cmp_mode == MODE_DIFF_MULTI)
-		return CMP_GOOD_SPILL_DIFF_MULTI;
+	if (cfg->samples == 0)
+		debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended.\n");
 
-	return 0;
+	if (cfg->icu_output_buf) {
+		if (cfg->buffer_length == 0 && cfg->samples != 0) {
+			debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data.\n");
+			cfg_invalid++;
+		}
+
+		if (raw_mode_is_used(cfg->cmp_mode) && cfg->buffer_length < cfg->samples) {
+			debug_print("Error: The compressed_data_len_samples is to small to hold the data form the data_to_compress.\n");
+			cfg_invalid++;
+		}
+
+		if (cfg->icu_output_buf == cfg->input_buf) {
+			debug_print("Error: The compressed_data buffer is the same as the data_to_compress buffer.\n");
+			cfg_invalid++;
+		}
+	}
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		if (cfg->model_buf == NULL) {
+			debug_print("Error: The model_of_data buffer for the model data is NULL.\n");
+			cfg_invalid++;
+		}
+
+		if (cfg->model_buf == cfg->input_buf) {
+			debug_print("Error: The model_of_data buffer is the same as the data_to_compress buffer.\n");
+			cfg_invalid++;
+		}
+
+		if (cfg->model_buf == cfg->icu_output_buf) {
+			debug_print("Error: The model_of_data buffer is the same as the compressed_data buffer.\n");
+			cfg_invalid++;
+		}
+
+		if (cfg->icu_new_model_buf) {
+			if (cfg->icu_new_model_buf == cfg->input_buf) {
+				debug_print("Error: The updated_model buffer is the same as the data_to_compress buffer.\n");
+				cfg_invalid++;
+			}
+
+			if (cfg->icu_new_model_buf == cfg->icu_output_buf) {
+				debug_print("Error: The compressed_data buffer is the same as the compressed_data buffer.\n");
+				cfg_invalid++;
+			}
+		}
+	}
+
+	return cfg_invalid;
 }
 
 
 /**
- * @brief calculate the size of a sample for the different compression modes
+ * @brief check if the combination of the different compression parameters is invalid
  *
- * @param cmp_mode compression mode
+ * @param cmp_par	compression parameter
+ * @param spill		spillover threshold parameter
+ * @param cmp_mode	compression mode
+ * @param data_type	compression data type
+ * @param par_name	string describing the use of the compression par. for
+ *			debug messages (can be NULL)
  *
- * @returns the size of a data sample in bytes for the selected compression
- *	mode;
+ * @returns 0 if the parameter combination is valid, otherwise the combination is invalid
  */
 
-size_t size_of_a_sample(unsigned int cmp_mode)
+static int cmp_pars_are_invalid(uint32_t cmp_par, uint32_t spill, enum cmp_mode cmp_mode,
+				enum cmp_data_type data_type, char *par_name)
 {
-	size_t sample_len;
+	int cfg_invalid = 0;
+	uint32_t min_golomb_par;
+	uint32_t max_golomb_par;
+	uint32_t min_spill;
+	uint32_t max_spill;
+
+	if (!par_name)
+		par_name = "";
+
+	/* The maximum compression parameter for imagette data are smaller to
+	 * fit into the imagette compression entity header */
+	if (cmp_imagette_data_type_is_used(data_type)) {
+		min_golomb_par = MIN_IMA_GOLOMB_PAR;
+		max_golomb_par = MAX_IMA_GOLOMB_PAR;
+		min_spill = MIN_IMA_SPILL;
+		max_spill = cmp_ima_max_spill(cmp_par);
+	} else {
+		min_golomb_par = MIN_ICU_GOLOMB_PAR;
+		max_golomb_par = MAX_ICU_GOLOMB_PAR;
+		min_spill = MIN_ICU_SPILL;
+		max_spill = cmp_icu_max_spill(cmp_par);
+	}
+
 
 	switch (cmp_mode) {
-	case MODE_RAW:
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_MULTI:
-		sample_len = sizeof(uint16_t);
+	case CMP_MODE_RAW:
+		/* no checks needed */
 		break;
-	case MODE_RAW_S_FX:
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		sample_len = sizeof(struct S_FX);
+	case CMP_MODE_DIFF_ZERO:
+	case CMP_MODE_DIFF_MULTI:
+	case CMP_MODE_MODEL_ZERO:
+	case CMP_MODE_MODEL_MULTI:
+		if (cmp_par < min_golomb_par || cmp_par > max_golomb_par) {
+			debug_print("Error: The selected %s compression parameter: %u is not supported. The compression parameter has to be between [%u, %u].\n",
+				    par_name, cmp_par, min_golomb_par, max_golomb_par);
+			cfg_invalid++;
+		}
+		if (spill < min_spill) {
+			debug_print("Error: The selected %s spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n",
+				    par_name, spill, min_spill);
+			cfg_invalid++;
+		}
+		if (spill > max_spill) {
+			debug_print("Error: The selected %s spillover threshold value: %u is too large for the selected %s compression parameter: %u, the largest possible spillover value in the selected compression mode is: %u.\n",
+				    par_name, spill, par_name, cmp_par, max_spill);
+			cfg_invalid++;
+		}
+
 		break;
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		sample_len = sizeof(struct S_FX_NCOB);
+	case CMP_MODE_STUFF:
+		if (cmp_par > MAX_STUFF_CMP_PAR) {
+			debug_print("Error: The selected %s stuff mode compression parameter: %u is too large, the largest possible value in the selected compression mode is: %u.\n",
+				    par_name, cmp_par, MAX_STUFF_CMP_PAR);
+			cfg_invalid++;
+		}
 		break;
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		sample_len = sizeof(struct S_FX_EFX_NCOB_ECOB);
+	default:
+		debug_print("Error: The compression mode is not supported.\n");
+		cfg_invalid++;
 		break;
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		sample_len = sizeof(struct F_FX);
+	}
+
+	return cfg_invalid;
+}
+
+
+/**
+ * @brief check if the imagette specific compression parameters are invalid
+ *
+ * @param cfg		pointer to the compressor configuration
+ * @param rdcu_check	set to non-zero if a check for a imagette RDCU compression
+ *			should be done; zero for imagette ICU compression
+ *
+ * @returns 0 if the imagette specific parameters are valid, otherwise invalid
+ */
+
+int cmp_cfg_imagette_is_invalid(const struct cmp_cfg *cfg, int rdcu_check)
+{
+	int cfg_invalid = 0;
+	enum cmp_mode cmp_mode;
+
+	if (!cfg)
+		return 0;
+
+	if (!cmp_imagette_data_type_is_used(cfg->data_type)) {
+		debug_print("Error: The compression data type is not an imagette compression data type.\n");
+		cfg_invalid++;
+	}
+
+	/* The RDCU needs valid compression parameters also in RAW_MODE */
+	if (rdcu_check && cfg->cmp_mode == CMP_MODE_RAW)
+		cmp_mode = CMP_MODE_MODEL_ZERO;
+	else
+		cmp_mode = cfg->cmp_mode;
+
+	cfg_invalid += cmp_pars_are_invalid(cfg->golomb_par, cfg->spill, cmp_mode,
+					    cfg->data_type, "imagette");
+
+	/* for the RDCU the adaptive parameters have to be always valid */
+	if (rdcu_check || cmp_ap_imagette_data_type_is_used(cfg->data_type)) {
+		cfg_invalid += cmp_pars_are_invalid(cfg->ap1_golomb_par, cfg->ap1_spill,
+				cmp_mode, cfg->data_type, "adaptive 1 imagette");
+		cfg_invalid += cmp_pars_are_invalid(cfg->ap2_golomb_par, cfg->ap2_spill,
+				cmp_mode, cfg->data_type, "adaptive 2 imagette");
+	}
+
+	return cfg_invalid;
+}
+
+
+/**
+ * @brief check if the flux/center of brightness specific compression parameters
+ *	are invalid
+ *
+ * @param cfg	pointer to the compressor configuration
+ *
+ * @returns 0 if the flux/center of brightness specific parameters are valid, otherwise invalid
+ */
+
+int cmp_cfg_fx_cob_is_invalid(const struct cmp_cfg *cfg)
+{
+	int cfg_invalid = 0;
+	int check_exp_flags = 0, check_ncob = 0, check_efx = 0, check_ecob = 0, check_var = 0;
+
+	if (!cfg)
+		return 0;
+
+	if (!cmp_fx_cob_data_type_is_used(cfg->data_type)) {
+		debug_print("Error: The compression data type is not a flux/center of brightness compression data type.\n");
+		cfg_invalid++;
+	}
+	/* flux parameter is needed for every fx_cob data_type */
+	cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_fx, cfg->spill_fx,
+					    cfg->cmp_mode, cfg->data_type, "flux");
+
+	switch (cfg->data_type) {
+	case DATA_TYPE_S_FX:
+		check_exp_flags = 1;
+		break;
+	case DATA_TYPE_S_FX_EFX:
+		check_exp_flags = 1;
+		check_efx = 1;
+		break;
+	case DATA_TYPE_S_FX_NCOB:
+		check_exp_flags = 1;
+		check_ncob = 1;
+		break;
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+		check_exp_flags = 1;
+		check_ncob = 1;
+		check_efx = 1;
+		check_ecob = 1;
+		break;
+	case DATA_TYPE_L_FX:
+		check_exp_flags = 1;
+		check_var = 1;
+		break;
+	case DATA_TYPE_L_FX_EFX:
+		check_exp_flags = 1;
+		check_efx = 1;
+		check_var = 1;
 		break;
-	case MODE_MODEL_ZERO_F_FX_EFX:
-	case MODE_MODEL_MULTI_F_FX_EFX:
-	case MODE_DIFF_ZERO_F_FX_EFX:
-	case MODE_DIFF_MULTI_F_FX_EFX:
-		sample_len = sizeof(struct F_FX_EFX);
+	case DATA_TYPE_L_FX_NCOB:
+		check_exp_flags = 1;
+		check_ncob = 1;
+		check_var = 1;
 		break;
-	case MODE_MODEL_ZERO_F_FX_NCOB:
-	case MODE_MODEL_MULTI_F_FX_NCOB:
-	case MODE_DIFF_ZERO_F_FX_NCOB:
-	case MODE_DIFF_MULTI_F_FX_NCOB:
-		sample_len = sizeof(struct F_FX_NCOB);
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+		check_exp_flags = 1;
+		check_ncob = 1;
+		check_efx = 1;
+		check_ecob = 1;
+		check_var = 1;
 		break;
-	case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB:
-		sample_len = sizeof(struct F_FX_EFX_NCOB_ECOB);
+	case DATA_TYPE_F_FX:
 		break;
-	case MODE_RAW_32:
-	case MODE_MODEL_ZERO_32:
-	case MODE_MODEL_MULTI_32:
-	case MODE_DIFF_ZERO_32:
-	case MODE_DIFF_MULTI_32:
-		sample_len = sizeof(uint32_t);
+	case DATA_TYPE_F_FX_EFX:
+		check_efx = 1;
+		break;
+	case DATA_TYPE_F_FX_NCOB:
+		check_ncob = 1;
+		break;
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		check_ncob = 1;
+		check_efx = 1;
+		check_ecob = 1;
 		break;
 	default:
-		debug_print("Error: Compression mode not supported.\n");
-		return 0;
+		cfg_invalid++;
 		break;
 	}
-	return sample_len;
+
+	if (check_exp_flags)
+		cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+			cfg->cmp_mode, cfg->data_type, "exposure flags");
+	if (check_ncob)
+		cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_ncob, cfg->spill_ncob,
+			cfg->cmp_mode, cfg->data_type, "center of brightness");
+	if (check_efx)
+		cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_efx, cfg->spill_efx,
+			cfg->cmp_mode, cfg->data_type, "extended flux");
+	if (check_ecob)
+		cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_ecob, cfg->spill_ecob,
+			cfg->cmp_mode, cfg->data_type, "extended center of brightness");
+	if (check_var)
+		cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_fx_cob_variance,
+			cfg->spill_fx_cob_variance, cfg->cmp_mode, cfg->data_type, "flux COB varianc");
+
+	return cfg_invalid;
 }
 
 
 /**
- * @brief calculate the need bytes to hold a bitstream
+ * @brief check if the auxiliary science specific compression parameters are invalid
  *
- * @param cmp_size_bit compressed data size, measured in bits
+ * @param cfg	pointer to the compressor configuration
  *
- * @returns the size in bytes to store the hole bitstream
- * @note we round up the result to multiples of 4 bytes
+ * @returns 0 if the auxiliary science specific parameters are valid, otherwise
+ *	invalid
+ * TODO: implemented DATA_TYPE_F_CAM_OFFSET and DATA_TYPE_F_CAM_BACKGROUND
  */
 
-unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit)
+int cmp_cfg_aux_is_invalid(const struct cmp_cfg *cfg)
 {
-	return (((cmp_size_bit + 7) / 8) + 3) & ~0x3UL;
+	int cfg_invalid = 0;
+
+	if (!cfg)
+		return 0;
+
+	if (!cmp_aux_data_type_is_used(cfg->data_type)) {
+		debug_print("Error: The compression data type is not an auxiliary science compression data type.\n");
+		cfg_invalid++;
+	}
+
+	cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_mean, cfg->spill_mean,
+					    cfg->cmp_mode, cfg->data_type, "mean");
+	cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_variance, cfg->spill_variance,
+					    cfg->cmp_mode, cfg->data_type, "variance");
+
+	/* if (cfg->data_type != DATA_TYPE_OFFSET && cfg->data_type != DATA_TYPE_F_CAM_OFFSET) */
+	if (cfg->data_type != DATA_TYPE_OFFSET)
+		cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+						    cfg->cmp_mode, cfg->data_type, "outlier pixls num");
+
+	return cfg_invalid;
 }
 
 
 /**
- * @brief calculate the need bytes for the data
+ * @brief check if a compression configuration is invalid
  *
- * @param samples number of data samples
- * @param cmp_mode used compression mode
+ * @param cfg	pointer to the compressor configuration
  *
- * @returns the size in bytes to store the data sample
+ * @returns 0 if the compression configuration is valid, otherwise invalid
  */
 
-unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode)
+int cmp_cfg_is_invalid(const struct cmp_cfg *cfg)
 {
-	return samples * size_of_a_sample(cmp_mode);
+	int cfg_invalid = 0;
+
+	if (!cfg)
+		return 0;
+
+	cfg_invalid += cmp_cfg_icu_gen_par_is_invalid(cfg);
+
+	cfg_invalid += cmp_cfg_icu_buffers_is_invalid(cfg);
+
+	if (cmp_imagette_data_type_is_used(cfg->data_type))
+		cfg_invalid += cmp_cfg_imagette_is_invalid(cfg, ICU_CHECK);
+	else if (cmp_fx_cob_data_type_is_used(cfg->data_type))
+		cfg_invalid += cmp_cfg_fx_cob_is_invalid(cfg);
+	else if (cmp_aux_data_type_is_used(cfg->data_type))
+		cfg_invalid += cmp_cfg_aux_is_invalid(cfg);
+	else
+		cfg_invalid++;
+
+	return cfg_invalid;
 }
 
 
@@ -593,14 +874,13 @@ unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode)
  *
  * @param cfg	compressor configuration contains all parameters required for
  *		compression
- *
  */
 
 void print_cmp_cfg(const struct cmp_cfg *cfg)
 {
 	size_t i;
 
-	printf("cmp_mode: %u\n", cfg->cmp_mode);
+	printf("cmp_mode: %i\n", cfg->cmp_mode);
 	printf("golomb_par: %u\n", cfg->golomb_par);
 	printf("spill: %u\n", cfg->spill);
 	printf("model_value: %u\n", cfg->model_value);
diff --git a/lib/decmp.c b/lib/decmp.c
index 4953f5d55566e47e1307cf423e626e5795850d48..3be77c96daeac25b6e63b8099ee09af53649679b 100644
--- a/lib/decmp.c
+++ b/lib/decmp.c
@@ -1,1522 +1,2196 @@
+/**
+ * @file   decmp.c
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2020
+ *
+ * @copyright GPLv2
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * @brief software decompression library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ *
+ * To decompress a compression entity (consisting of a compression entity header
+ * and the compressed data) use the decompress_cmp_entiy() function.
+ */
+
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <string.h>
 
-#include "../include/cmp_support.h"
-#include "../include/cmp_icu.h"
-#include "../include/cmp_data_types.h"
-#include "../include/byteorder.h"
-#include "../include/cmp_debug.h"
-
-
-double get_compression_ratio(const struct cmp_info *info)
-{
-	unsigned long orign_len_bits = info->samples_used * size_of_a_sample(info->cmp_mode_used) * CHAR_BIT;
-
-	return (double)orign_len_bits/(double)info->cmp_size;
-}
+#include "byteorder.h"
+#include "cmp_debug.h"
+#include "cmp_support.h"
+#include "cmp_data_types.h"
+#include "cmp_entity.h"
 
 
-void *malloc_decompressed_data(const struct cmp_info *info)
-{
-	size_t sample_len;
+#define MAX_CW_LEN 32 /* maximum Golomb code word bit length */
 
-	if (!info)
-		return NULL;
 
-	if (info->samples_used == 0)
-		return NULL;
+/* maximum used bits registry */
+extern struct cmp_max_used_bits max_used_bits;
 
-	sample_len = size_of_a_sample(info->cmp_mode_used);
+/* function pointer to a code word decoder function */
+typedef int (*decoder_ptr)(uint32_t, unsigned int, unsigned int, uint32_t *);
 
-	return malloc(info->samples_used * sample_len);
-}
+/* structure to hold a setup to encode a value */
+struct decoder_setup {
+	decoder_ptr decode_cw_f; /* pointer to the code word decoder (Golomb/Rice)*/
+	int (*decode_method_f)(uint32_t *decoded_value, int stream_pos,
+			       const struct decoder_setup *setup); /* pointer to the decoding function */
+	uint32_t *bitstream_adr; /* start address of the compressed data bitstream */
+	uint32_t max_stream_len; /* maximum length of the bitstream/icu_output_buf in bits */
+	uint32_t encoder_par1; /* encoding parameter 1 */
+	uint32_t encoder_par2; /* encoding parameter 2 */
+	uint32_t outlier_par; /* outlier parameter */
+	uint32_t lossy_par; /* lossy compression parameter */
+	uint32_t model_value; /* model value parameter */
+	uint32_t max_data_bits; /* how many bits are needed to represent the highest possible value */
+};
 
 
 /**
- * @brief decompression data pre-processing in RAW mode
- *
- * @note in RAW mode the data are uncompressed no pre_processing needed
+ * @brief count leading 1-bits
  *
- * @param  cmp_mode_used used compression mode
+ * @param value	input vale to count
  *
- * @returns 0 on success, error otherwise
+ * @returns the number of leading 1-bits in value, starting at the most
+ *	significant bit position
  */
 
-static int de_raw_pre_process(uint8_t cmp_mode_used)
+static unsigned int count_leading_ones(uint32_t value)
 {
-	if (!raw_mode_is_used(cmp_mode_used))
-		return -1;
+	if (value == 0xFFFFFFFF)
+		return 32;
 
-	return 0;
+	return __builtin_clz(~value);
 }
 
 
 /**
- * @brief model decompression pre-processing
+ * @brief decode a Rice code word
  *
- * @note change the data_buf in-place
+ * @param code_word	Rice code word bitstream starting at the MSB
+ * @param m		Golomb parameter (not used)
+ * @param log2_m	Rice parameter, must be the same used for encoding
+ * @param decoded_cw	pointer where decoded value is written
  *
- * @param data_buf	pointer to the data to process
- * @param model_buf	pointer to the model of the data to process
- * @param samples_used	the size of the data and model buffer in 16 bit units
- * @param model_value_used used model weighting parameter
- * @param round_used	used number of bits to round; if zero no rounding takes place
- *
- * @returns 0 on success, error otherwise
+ * @returns the length of the decoded code word in bits (NOT the decoded value);
+ *	0 on failure
  */
 
-static int de_model_16(uint16_t *data_buf, uint16_t *model_buf, uint32_t
-		       samples_used, uint8_t model_value_used, uint8_t
-		       round_used)
+static int rice_decoder(uint32_t code_word, unsigned int m, unsigned int log2_m,
+			uint32_t *decoded_cw)
 {
-	size_t i;
-	int err;
+	unsigned int q; /* quotient code */
+	unsigned int ql; /* length of the quotient code */
+	unsigned int r; /* remainder code */
+	unsigned int rl = log2_m; /* length of the remainder code */
+	unsigned int cw_len; /* length of the decoded code word in bits */
+
+	(void)m; /* we don't need the Golomb parameter */
 
-	if (!samples_used)
+	if (log2_m > 32) /* because m has 32 bits log2_m can not be bigger than 32 */
 		return 0;
 
-	if (!data_buf)
-		return -1;
+	q = count_leading_ones(code_word); /* decode unary coding */
+	ql = q + 1; /* Number of 1's + following 0 */
 
-	if (!model_buf)
-		return -1;
+	cw_len = rl + ql;
 
-	if (model_value_used > MAX_MODEL_VALUE)
-		return -1;
+	if (cw_len > 32) /* can only decode code words with maximum 32 bits */
+		return 0;
 
-	for (i = 0; i < samples_used; i++) {
-		/* overflow is intended */
-		data_buf[i] = (uint16_t)(data_buf[i] + round_fwd(model_buf[i],
-								  round_used));
-	}
+	code_word = code_word << ql;  /* shift quotient code out */
 
-	err = de_lossy_rounding_16(data_buf, samples_used, round_used);
-	if (err)
-		return -1;
+	/* Right shifting an integer by a number of bits equal or greater than
+	 * its size is undefined behavior */
+	if (rl == 0)
+		r = 0;
+	else
+		r = code_word >> (32 - rl);
 
-	for (i = 0; i < samples_used; i++) {
-		model_buf[i] = (uint16_t)cal_up_model(data_buf[i], model_buf[i],
-						      model_value_used);
-	}
-	return 0;
+	*decoded_cw = (q << rl) + r;
+
+	return cw_len;
 }
 
 
-static int de_model_S_FX(struct S_FX *data_buf, struct S_FX *model_buf, uint32_t
-		       samples_used, uint8_t model_value_used, uint8_t
-		       round_used)
-{
-	size_t i;
-	int err;
+/**
+ * @brief decode a Golomb code word
+ *
+ * @param code_word	Golomb code word bitstream starting at the MSB
+ * @param m		Golomb parameter (have to be bigger than 0)
+ * @param log2_m	is log_2(m) calculate outside function for better
+ *			performance
+ * @param decoded_cw	pointer where decoded value is written
+ *
+ * @returns the length of the decoded code word in bits (NOT the decoded value);
+ *	0 on failure
+ */
 
-	if (!samples_used)
-		return 0;
+static int golomb_decoder(uint32_t code_word, unsigned int m,
+			  unsigned int log2_m, uint32_t *decoded_cw)
+{
+	unsigned int q; /* quotient code */
+	unsigned int r1; /* remainder code group 1 */
+	unsigned int r2; /* remainder code group 2 */
+	unsigned int r; /* remainder code */
+	unsigned int rl; /* length of the remainder code */
+	unsigned int cutoff; /* cutoff between group 1 and 2 */
+	unsigned int cw_len; /* length of the decoded code word in bits */
 
-	if (!data_buf)
-		return -1;
+	q = count_leading_ones(code_word); /* decode unary coding */
 
-	if (!model_buf)
-		return -1;
+	rl = log2_m + 1;
+	code_word <<= (q+1);  /* shift quotient code out */
 
-	if (model_value_used > MAX_MODEL_VALUE)
-		return -1;
+	r2 = code_word >> (32 - rl);
+	r1 = r2 >> 1;
 
-	for (i = 0; i < samples_used; i++) {
-		/* overflow is intended */
-		struct S_FX round_model = model_buf[i];
+	cutoff = (1UL << rl) - m;
 
-		lossy_rounding_S_FX(&round_model, 1, round_used);
-		data_buf[i] = add_S_FX(data_buf[i], model_buf[i]);
+	if (r1 < cutoff) { /* group 1 */
+		cw_len = q + rl;
+		r = r1;
+	} else { /* group 2 */
+		cw_len = q + rl + 1;
+		r = r2 - cutoff;
 	}
 
-	err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used);
-	if (err)
-		return -1;
-
-	for (i = 0; i < samples_used; i++)
-		model_buf[i] = cal_up_model_S_FX(data_buf[i], model_buf[i],
-						 model_value_used);
+	if (cw_len > 32)
+		return 0;
 
-	return 0;
+	*decoded_cw = q*m + r;
+	return cw_len;
 }
 
 
 /**
- * @brief 1d-differencing decompression per-processing
+ * @brief select the decoder based on the used Golomb parameter
+ * @note if the Golomb parameter is a power of 2 we can use the faster Rice
+ *	decoder
  *
- * @param data_buf	pointer to the data to process
- * @param samples_used	the size of the data and model buffer in 16 bit units
- * @param round_used	used number of bits to round; if zero no rounding takes place
+ * @param golomb_par	Golomb parameter (have to be bigger than 0)
  *
- * @returns 0 on success, error otherwise
+ * @returns function pointer to the select decoder function; NULL on failure
  */
 
-static int de_diff_16(uint16_t *data_buf, uint32_t samples_used, uint8_t
-		      round_used)
+static decoder_ptr select_decoder(unsigned int golomb_par)
 {
-	size_t i;
-	int err;
-
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
-		return -1;
-
-	for (i = 1; i < samples_used; i++) {
-		/* overflow intended */
-		data_buf[i] = data_buf[i] + data_buf[i-1];
-	}
-
-	err = de_lossy_rounding_16(data_buf, samples_used, round_used);
-	if (err)
-		return -1;
+	if (!golomb_par)
+		return NULL;
 
-	return 0;
+	if (is_a_pow_of_2(golomb_par))
+		return &rice_decoder;
+	else
+		return &golomb_decoder;
 }
 
 
-static int de_diff_32(uint32_t *data_buf, uint32_t samples_used, uint8_t
-		      round_used)
-{
-	size_t i;
-	int err;
+/**
+ * @brief read a value of up to 32 bits from a bitstream
+ *
+ * @param p_value		pointer to the read value, the
+ *				read value will be converted to the system
+ *				endianness
+ * @param n_bits		number of bits to read from the bitstream
+ * @param bit_offset		bit index where the bits will be read, seen from
+ *				the very beginning of the bitstream
+ * @param bitstream_adr		this is the pointer to the beginning of the
+ *				bitstream
+ * @param max_stream_len	maximum length of the bitstream in bits *
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF
+ *	if the bitstream buffer is too small to read the value from the
+ *	bitstream
+ */
 
-	if (!samples_used)
-		return 0;
+static int get_n_bits32(uint32_t *p_value, unsigned int n_bits, int bit_offset,
+			uint32_t *bitstream_adr, unsigned int max_stream_len)
+{
+	uint32_t *local_adr;
+	unsigned int bitsLeft, bitsRight, localEndPos;
+	unsigned int mask;
+	int stream_len = (int)(n_bits + (unsigned int)bit_offset); /* overflow results in a negative return value */
 
-	if (!data_buf)
+	/*leave in case of erroneous input */
+	if (bit_offset < 0)
 		return -1;
+	if (n_bits == 0)
+		return -1;
+	if (n_bits > 32)
+		return -1;
+	if (!bitstream_adr)
+		return -1;
+	if (!p_value)
+		return -1;
+
+	/* Check if bitstream buffer is large enough */
+	if ((unsigned int)stream_len > max_stream_len) {
+		debug_print("Error: Buffer overflow detected.\n");
+		return CMP_ERROR_SMALL_BUF;
 
-	for (i = 1; i < samples_used; i++) {
-		/* overflow intended */
-		data_buf[i] = data_buf[i] + data_buf[i-1];
 	}
 
-	err = de_lossy_rounding_32(data_buf, samples_used, round_used);
-	if (err)
-		return -1;
+	/* separate the bit_offset into word offset (set local_adr pointer) and
+	 * local bit offset (bitsLeft)
+	 */
+	local_adr = bitstream_adr + (bit_offset >> 5);
+	bitsLeft = bit_offset & 0x1f;
 
-	return 0;
-}
+	localEndPos = bitsLeft + n_bits;
 
+	if (localEndPos <= 32) {
+		unsigned int shiftRight = 32 - n_bits;
 
-static int de_diff_S_FX(struct S_FX *data_buf, uint32_t samples_used, uint8_t
-			round_used)
-{
-	size_t i;
-	int err;
+		bitsRight = shiftRight - bitsLeft;
 
-	if (!samples_used)
-		return 0;
+		*(p_value) = cpu_to_be32(*(local_adr)) >> bitsRight;
 
-	if (!data_buf)
-		return -1;
+		mask = (0xffffffff >> shiftRight);
 
-	for (i = 1; i < samples_used; i++) {
-		/* overflow intended */
-		data_buf[i] = add_S_FX(data_buf[i], data_buf[i-1]);
-	}
+		*(p_value) &= mask;
+	} else {
+		unsigned int n1 = 32 - bitsLeft;
+		unsigned int n2 = n_bits - n1;
+		/* part 1 ; */
+		mask = 0xffffffff >> bitsLeft;
+		*(p_value) = cpu_to_be32(*(local_adr)) & mask;
+		*(p_value) <<= n2;
+		/*part 2: */
+		/* adjust address*/
+		local_adr += 1;
 
-	err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used);
-	if (err)
-		return -1;
+		bitsRight = 32 - n2;
+		*(p_value) |= cpu_to_be32(*(local_adr)) >> bitsRight;
+	}
 
-	return 0;
+	return stream_len;
 }
 
 
-static int de_diff_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples_used,
-			    uint8_t round_used)
+/**
+ * @brief decode a Golomb/Rice encoded code word from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
+
+static int decode_normal(uint32_t *decoded_value, int stream_pos,
+			 const struct decoder_setup *setup)
 {
-	size_t i;
-	int err;
+	uint32_t read_val;
+	unsigned int n_read_bits;
+	int stream_pos_read, cw_len;
 
-	if (!samples_used)
-		return 0;
+	/* check if we can read max_cw_len or less; we do not know how long the
+	 * code word actually is so we try to read the maximum cw length */
+	if ((unsigned int)stream_pos + 32 > setup->max_stream_len)
+		n_read_bits = setup->max_stream_len - (unsigned int)stream_pos;
+	else
+		n_read_bits = MAX_CW_LEN;
 
-	if (!data_buf)
-		return -1;
+	stream_pos_read = get_n_bits32(&read_val, n_read_bits, stream_pos,
+				       setup->bitstream_adr, setup->max_stream_len);
+	if (stream_pos_read < 0)
+		return stream_pos_read;
 
-	for (i = 1; i < samples_used; i++) {
-		/* overflow intended */
-		data_buf[i] = add_S_FX_EFX(data_buf[i], data_buf[i-1]);
-	}
+	/* if we read less than 32, we shift the bitstream so that it starts at the MSB */
+	read_val = read_val << (32 - n_read_bits);
 
-	err = de_lossy_rounding_S_FX_EFX(data_buf, samples_used, round_used);
-	if (err)
+	cw_len = setup->decode_cw_f(read_val, setup->encoder_par1,
+				    setup->encoder_par2, decoded_value);
+	if (cw_len <= 0)
+		return -1;
+	/* consistency check: code word length can not be bigger than the read bits */
+	if (cw_len > (int)n_read_bits)
 		return -1;
 
-	return 0;
+	return stream_pos + cw_len;
 }
 
 
-static int de_diff_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t samples_used,
-			     uint8_t round_used)
-{
-	size_t i;
-	int err;
+/**
+ * @brief decode a Golomb/Rice encoded code word with zero escape system
+ *	mechanism from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
 
-	if (!samples_used)
-		return 0;
+static int decode_zero(uint32_t *decoded_value, int stream_pos,
+		       const struct decoder_setup *setup)
+{
+	stream_pos = decode_normal(decoded_value, stream_pos, setup);
+	if (stream_pos < 0)
+		return stream_pos;
 
-	if (!data_buf)
+	/* consistency check: value lager than the outlier parameter should not
+	 * be Golomb/Rice encoded */
+	if (*decoded_value > setup->outlier_par)
 		return -1;
 
-	for (i = 1; i < samples_used; i++) {
-		/* overflow intended */
-		data_buf[i] = add_S_FX_NCOB(data_buf[i], data_buf[i-1]);
+	if (*decoded_value == 0) {
+		/* escape symbol mechanism was used; read unencoded value */
+		uint32_t unencoded_val;
+
+		stream_pos = get_n_bits32(&unencoded_val, setup->max_data_bits, stream_pos,
+					  setup->bitstream_adr, setup->max_stream_len);
+		if (stream_pos < 0)
+			return stream_pos;
+		/* consistency check: outliers must be bigger than the outlier_par */
+		if (unencoded_val < setup->outlier_par && unencoded_val != 0)
+			return -1;
+
+		*decoded_value = unencoded_val;
 	}
 
-	err = de_lossy_rounding_S_FX_NCOB(data_buf, samples_used, round_used);
-	if (err)
-		return -1;
+	(*decoded_value)--;
+	if (*decoded_value == 0xFFFFFFFF) /* catch underflow */
+		(*decoded_value) >>=  (32 - setup->max_data_bits);
 
-	return 0;
+	return stream_pos;
 }
 
 
-static int de_diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-				      uint32_t samples_used, uint8_t round_used)
+/**
+ * @brief decode a Golomb/Rice encoded code word with multi escape system
+ *	mechanism from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
+
+static int decode_multi(uint32_t *decoded_value, int stream_pos,
+			const struct decoder_setup *setup)
 {
-	size_t i;
-	int err;
+	stream_pos = decode_normal(decoded_value, stream_pos, setup);
+	if (stream_pos < 0)
+		return stream_pos;
 
-	if (!samples_used)
-		return 0;
+	if (*decoded_value >= setup->outlier_par) {
+		/* escape symbol mechanism was used; read unencoded value */
+		uint32_t unencoded_val;
+		unsigned int unencoded_len;
 
-	if (!data_buf)
-		return -1;
+		unencoded_len = (*decoded_value - setup->outlier_par + 1) * 2;
 
-	for (i = 1; i < samples_used; i++) {
-		/* overflow intended */
-		data_buf[i] = add_S_FX_EFX_NCOB_ECOB(data_buf[i], data_buf[i-1]);
+		stream_pos = get_n_bits32(&unencoded_val, unencoded_len, stream_pos,
+					  setup->bitstream_adr, setup->max_stream_len);
+		if (stream_pos >= 0)
+			*decoded_value = unencoded_val + setup->outlier_par;
 	}
-
-	err = de_lossy_rounding_S_FX_EFX_NCOB_ECOB(data_buf, samples_used,
-						   round_used);
-	if (err)
-		return -1;
-
-	return 0;
+	return stream_pos;
 }
 
 
-static int de_pre_process(void *decoded_data, void *de_model_buf,
-			  const struct cmp_info *info)
-{
-	if (!decoded_data)
-		return -1;
-
-	if (!info)
-		return -1;
-
-	if (info->samples_used == 0)
-		return 0;
+/**
+ * @brief get the value unencoded with setup->cmp_par_1 bits without any
+ *	additional changes from the bitstream
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ *
+ */
 
-	switch (info->cmp_mode_used) {
-	case MODE_RAW:
-	case MODE_RAW_S_FX:
-		return de_raw_pre_process(info->cmp_mode_used);
-		break;
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_MULTI:
-		return de_model_16((uint16_t *)decoded_data,
-				   (uint16_t *)de_model_buf, info->samples_used,
-				   info->model_value_used, info->round_used);
-		break;
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_MULTI:
-		return de_diff_16((uint16_t *)decoded_data, info->samples_used,
-				  info->round_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-		return de_model_S_FX((struct S_FX *)decoded_data,
-				   (struct S_FX *)de_model_buf,
-				   info->samples_used, info->model_value_used,
-				   info->round_used);
-		break;
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		return de_diff_S_FX((struct S_FX *)decoded_data,
-				    info->samples_used, info->round_used);
-		break;
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		return de_diff_S_FX_EFX((struct S_FX_EFX *)decoded_data,
-					info->samples_used, info->round_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-		return -1;
-		break;
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-		return de_diff_S_FX_NCOB((struct S_FX_NCOB *)decoded_data,
-					 info->samples_used, info->round_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-		return -1;
-		break;
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		return de_diff_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *)
-						  decoded_data,
-						  info->samples_used,
-						  info->round_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-		return -1;
-		break;
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		return de_diff_32((uint32_t *)decoded_data, info->samples_used,
-				  info->round_used);
-		break;
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-		return -1;
-		break;
-	default:
-		debug_print("Error: Compression mode not supported.\n");
-		break;
-	}
+static int decode_none(uint32_t *decoded_value, int stream_pos,
+		       const struct decoder_setup *setup)
+{
+	stream_pos = get_n_bits32(decoded_value, setup->encoder_par1, stream_pos,
+				  setup->bitstream_adr, setup->max_stream_len);
 
-	return -1;
+	return stream_pos;
 }
 
 
-static uint8_t de_map_to_pos_alg_8(uint8_t value_to_unmap)
+/**
+ * @brief remap an unsigned value back to a signed value
+ * @note this is the reverse function of map_to_pos()
+ *
+ * @param value_to_unmap	unsigned value to remap
+ *
+ * @returns the signed remapped value
+ */
+
+static uint32_t re_map_to_pos(uint32_t value_to_unmap)
 {
-	if (value_to_unmap & 0x1) /* if uneven */
-		return (value_to_unmap + 1) / -2;
-	else
+	if (value_to_unmap & 0x1) { /* if uneven */
+		if (value_to_unmap == 0xFFFFFFFF) /* catch overflow */
+			return 0x80000000;
+		return -((value_to_unmap + 1) / 2);
+	} else {
 		return value_to_unmap / 2;
+	}
 }
 
 
-static uint16_t de_map_to_pos_alg_16(uint16_t value_to_unmap)
+/**
+ * @brief decompress the next code word in the bitstream and decorate it with
+ *	the model
+ *
+ * @param decoded_value	pointer to the decoded value
+ * @param model		model of the decoded_value (0 if not used)
+ * @param stream_pos	start bit position code word to be decoded in the bitstream
+ * @param setup		pointer to the decoder setup
+ *
+ * @returns bit index of the next code word in the bitstream on success; returns
+ *	negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the
+ *	bitstream buffer is too small to read the value from the bitstream
+ */
+
+static int decode_value(uint32_t *decoded_value, uint32_t model,
+			int stream_pos, const struct decoder_setup *setup)
 {
-	if (value_to_unmap & 0x1) /* if uneven */
-		return (value_to_unmap + 1) / -2;
-	else
-		return value_to_unmap / 2;
-}
+	uint32_t mask = (~0U >> (32 - setup->max_data_bits)); /* mask the used bits */
 
+	/* decode the next value from the bitstream */
+	stream_pos = setup->decode_method_f(decoded_value, stream_pos, setup);
+	if (stream_pos <= 0)
+		return stream_pos;
 
-static uint32_t de_map_to_pos_alg_32(uint32_t value_to_unmap)
-{
+	if (setup->decode_method_f == decode_none)
+		/* we are done here in stuff mode */
+		return stream_pos;
 
-	if (value_to_unmap & 0x1) /* if uneven */
-		return ((int64_t)value_to_unmap + 1) / -2; /* typecast to prevent overflow */
-	else
-		return value_to_unmap / 2;
+	/* map the unsigned decode value back to a signed value */
+	*decoded_value = re_map_to_pos(*decoded_value);
+
+	/* decorate data the data with the model */
+	*decoded_value += round_fwd(model, setup->lossy_par);
+
+	/* we mask only the used bits in case there is an overflow when adding the model */
+	*decoded_value &= mask;
+
+	/* inverse step of the lossy compression */
+	*decoded_value = round_inv(*decoded_value, setup->lossy_par);
+
+	return stream_pos;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	16-bit buffer
+ * @brief configure a decoder setup structure to have a setup to decode a vale
  *
- * @note change the data_buf in-place
+ * @param setup		pointer to the decoder setup
+ * @param cmp_par	compression parameter
+ * @param spillover	spillover_par parameter
+ * @param lossy_par	lossy compression parameter
+ * @param max_data_bits	how many bits are needed to represent the highest possible value
+ * @param cfg		pointer to the compression configuration structure
  *
- * @param data_buf	pointer to the uint16_t data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
- *
- * @returns 0 on success, error otherwise
+ * @returns 0 on success; otherwise error
  */
 
-static int de_map_to_pos_16(uint16_t *data_buf, uint32_t samples_used, int
-			    zero_mode_used)
+static int configure_decoder_setup(struct decoder_setup *setup,
+				   uint32_t cmp_par, uint32_t spillover,
+				   uint32_t lossy_par, uint32_t max_data_bits,
+				   const struct cmp_cfg *cfg)
 {
-	size_t i;
-
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
+	if (multi_escape_mech_is_used(cfg->cmp_mode))
+		setup->decode_method_f = &decode_multi;
+	else if (zero_escape_mech_is_used(cfg->cmp_mode))
+		setup->decode_method_f = &decode_zero;
+	else if (cfg->cmp_mode == CMP_MODE_STUFF)
+		setup->decode_method_f = &decode_none;
+	else {
+		setup->decode_method_f = NULL;
+		debug_print("Error: Compression mode not supported.\n");
 		return -1;
+	}
 
-	for (i = 0; i < samples_used; i++) {
-		if (zero_mode_used)
-			data_buf[i] -= 1;
-
-		data_buf[i] = (uint16_t)de_map_to_pos_alg_16(data_buf[i]);
+	setup->bitstream_adr = cfg->icu_output_buf; /* start address of the compressed data bitstream */
+	if (cfg->buffer_length & 0x3) {
+		debug_print("Error: The length of the compressed data is not a multiple of 4 bytes.");
+		return -1;
 	}
+	setup->max_stream_len = (cfg->buffer_length) * CHAR_BIT;  /* maximum length of the bitstream/icu_output_buf in bits */
+	setup->encoder_par1 = cmp_par; /* encoding parameter 1 */
+	if (ilog_2(cmp_par) < 0)
+		return -1;
+	setup->encoder_par2 = ilog_2(cmp_par); /* encoding parameter 2 */
+	setup->outlier_par = spillover; /* outlier parameter */
+	setup->lossy_par = lossy_par; /* lossy compression parameter */
+	setup->model_value = cfg->model_value; /* model value parameter */
+	setup->max_data_bits = max_data_bits; /* how many bits are needed to represent the highest possible value */
+	setup->decode_cw_f = select_decoder(cmp_par);
+
 	return 0;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	32-bit buffer
- *
- * @note change the data_buf in-place
+ * @brief decompress imagette data
  *
- * @param data_buf	pointer to the uint16_t data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
  */
 
-static int de_map_to_pos_32(uint32_t *data_buf, uint32_t samples_used, int
-			    zero_mode_used)
+static int decompress_imagette(struct cmp_cfg *cfg)
 {
+	int err;
 	size_t i;
+	int stream_pos = 0;
+	struct decoder_setup setup;
+	uint16_t *decompressed_data = cfg->input_buf;
+	uint16_t *model_buf = cfg->model_buf;
+	uint16_t *up_model_buf = cfg->icu_new_model_buf;
+	uint32_t decoded_value = 0;
+	uint16_t model;
+
+	err = configure_decoder_setup(&setup, cfg->golomb_par, cfg->spill,
+				      cfg->round, max_used_bits.nc_imagette, cfg);
+	if (err)
+		return -1;
 
-	if (!samples_used)
-		return 0;
 
-	if (!data_buf)
-		return -1;
+	for (i = 0; i < cfg->samples; i++) {
+		if (model_mode_is_used(cfg->cmp_mode))
+			model = model_buf[i];
+		else
+			model = decoded_value;
 
-	for (i = 0; i < samples_used; i++) {
-		if (zero_mode_used)
-			data_buf[i] -= 1;
+		stream_pos = decode_value(&decoded_value, model, stream_pos, &setup);
+		if (stream_pos <= 0)
+			return stream_pos;
+		decompressed_data[i] = decoded_value;
 
-		data_buf[i] = (uint32_t)de_map_to_pos_alg_32(data_buf[i]);
+		if (up_model_buf) {
+			up_model_buf[i] = cmp_up_model(decoded_value, model,
+						       cfg->model_value, setup.lossy_par);
+		}
 	}
-	return 0;
+
+	return stream_pos;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	S_FX buffer
+ * @brief decompress the multi-entry packet header structure and sets the data,
+ *	model and up_model pointers to the data after the header
  *
- * @note change the data_buf in-place
+ * @param data		pointer to a pointer pointing to the data to be compressed
+ * @param model		pointer to a pointer pointing to the model of the data
+ * @param up_model	pointer to a pointer pointing to the updated model buffer
+ * @param cfg		pointer to the compression configuration structure
  *
- * @param data_buf	pointer to the S_FX data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @returns the bit length of the bitstream on success
  *
- * @returns 0 on success, error otherwise
+ * @note the (void **) cast relies on all pointer types having the same internal
+ *	representation which is common, but not universal; http://www.c-faq.com/ptrs/genericpp.html
  */
 
-static int de_map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples_used, int
-			      zero_mode_used)
+static int decompress_multi_entry_hdr(void **data, void **model, void **up_model,
+				      const struct cmp_cfg *cfg)
 {
-	size_t i;
-
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
+	if (cfg->buffer_length < MULTI_ENTRY_HDR_SIZE)
 		return -1;
 
-	for (i = 0; i < samples_used; i++) {
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS -= 1; */
-			data_buf[i].FX -= 1;
-		}
+	if (*data) {
+		if (cfg->icu_output_buf)
+			memcpy(*data, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE);
+		*data = (uint8_t *)*data + MULTI_ENTRY_HDR_SIZE;
+	}
 
-		data_buf[i].EXPOSURE_FLAGS =
-			de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX);
+	if (*model) {
+		if (cfg->icu_output_buf)
+			memcpy(*model, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE);
+		*model = (uint8_t *)*model + MULTI_ENTRY_HDR_SIZE;
 	}
-	return 0;
+
+	if (*up_model) {
+		if (cfg->icu_output_buf)
+			memcpy(*up_model, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE);
+		*up_model = (uint8_t *)*up_model + MULTI_ENTRY_HDR_SIZE;
+	}
+
+	return MULTI_ENTRY_HDR_SIZE * CHAR_BIT;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	S_FX_EFX buffer
+ * @brief decompress short normal light flux (S_FX) data
  *
- * @note change the data_buf in-place
+ * @param cfg	pointer to the compression configuration structure
  *
- * @param data_buf	pointer to the S_FX_EFX data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
- *
- * @returns 0 on success, error otherwise
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
  */
 
-static int de_map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t
-				  samples_used, int zero_mode_used)
+static int decompress_s_fx(const struct cmp_cfg *cfg)
 {
 	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx;
+	struct s_fx *data_buf = cfg->input_buf;
+	struct s_fx *model_buf = cfg->model_buf;
+	struct s_fx *up_model_buf = NULL;
+	struct s_fx *next_model_p;
+	struct s_fx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
 		return -1;
 
-	for (i = 0; i < samples_used; i++) {
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS -= 1; */
-			data_buf[i].FX -= 1;
-			data_buf[i].EFX -= 1;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
 		}
 
-		data_buf[i].EXPOSURE_FLAGS =
-			de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX);
-		data_buf[i].EFX = de_map_to_pos_alg_32(data_buf[i].EFX);
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	S_FX_NCOB buffer
+ * @brief decompress S_FX_EFX data
  *
- * @note change the data_buf in-place
+ * @param cfg	pointer to the compression configuration structure
  *
- * @param data_buf	pointer to the S_FX_NCOB data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
- *
- * @returns 0 on success, error otherwise
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
  */
 
-static int de_map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t
-				   samples_used, int zero_mode_used)
+static int decompress_s_fx_efx(const struct cmp_cfg *cfg)
 {
 	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_efx;
+	struct s_fx_efx *data_buf = cfg->input_buf;
+	struct s_fx_efx *model_buf = cfg->model_buf;
+	struct s_fx_efx *up_model_buf = NULL;
+	struct s_fx_efx *next_model_p;
+	struct s_fx_efx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.s_efx, cfg))
 		return -1;
 
-	for (i = 0; i < samples_used; i++) {
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS -= 1; */
-			data_buf[i].FX -= 1;
-			data_buf[i].NCOB_X -= 1;
-			data_buf[i].NCOB_Y -= 1;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
 		}
 
-		data_buf[i].EXPOSURE_FLAGS =
-			de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX);
-		data_buf[i].NCOB_X = de_map_to_pos_alg_32(data_buf[i].NCOB_X);
-		data_buf[i].NCOB_Y = de_map_to_pos_alg_32(data_buf[i].NCOB_Y);
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	S_FX_EFX_NCOB_ECOB buffer
+ * @brief decompress short S_FX_NCOB data
  *
- * @note change the data_buf in-place
+ * @param cfg	pointer to the compression configuration structure
  *
- * @param data_buf	pointer to the S_FX_EFX_NCOB_ECOB data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
- *
- * @returns 0 on success, error otherwise
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
  */
 
-static int de_map_to_pos_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
-					    uint32_t samples_used,
-					    int zero_mode_used)
+static int decompress_s_fx_ncob(const struct cmp_cfg *cfg)
 {
 	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob;
+	struct s_fx_ncob *data_buf = cfg->input_buf;
+	struct s_fx_ncob *model_buf = cfg->model_buf;
+	struct s_fx_ncob *up_model_buf = NULL;
+	struct s_fx_ncob *next_model_p;
+	struct s_fx_ncob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!samples_used)
-		return 0;
-
-	if (!data_buf)
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.s_ncob, cfg))
 		return -1;
 
-	for (i = 0; i < samples_used; i++) {
-		if (zero_mode_used) {
-			/* data_buf[i].EXPOSURE_FLAGS -= 1; */
-			data_buf[i].FX -= 1;
-			data_buf[i].NCOB_X -= 1;
-			data_buf[i].NCOB_Y -= 1;
-			data_buf[i].EFX -= 1;
-			data_buf[i].ECOB_X -= 1;
-			data_buf[i].ECOB_Y -= 1;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+							      cfg->model_value, setup_ncob.lossy_par);
 		}
 
-		data_buf[i].EXPOSURE_FLAGS =
-			de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS);
-		data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX);
-		data_buf[i].NCOB_X = de_map_to_pos_alg_32(data_buf[i].NCOB_X);
-		data_buf[i].NCOB_Y = de_map_to_pos_alg_32(data_buf[i].NCOB_Y);
-		data_buf[i].EFX = de_map_to_pos_alg_32(data_buf[i].EFX);
-		data_buf[i].ECOB_X = de_map_to_pos_alg_32(data_buf[i].ECOB_X);
-		data_buf[i].ECOB_Y = de_map_to_pos_alg_32(data_buf[i].ECOB_Y);
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range for a
- *	F_FX buffer
- *
- * @note change the data_buf in-place
+ * @brief decompress short S_FX_NCOB_ECOB data
  *
- * @param data_buf	pointer to the F_FX data buffer to process
- * @param samples_used	amount of data samples in the data_buf
- * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
  */
 
-static int de_map_to_pos_F_FX(uint32_t *data_buf, uint32_t samples_used, int
-			      zero_mode_used)
+static int decompress_s_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
 {
-	return de_map_to_pos_32(data_buf, samples_used, zero_mode_used);
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, setup_efx, setup_ecob;
+	struct s_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct s_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct s_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct s_fx_efx_ncob_ecob *next_model_p;
+	struct s_fx_efx_ncob_ecob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
+
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.s_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.s_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.s_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.s_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				    cfg->round, max_used_bits.s_ecob, cfg))
+		return -1;
+
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_x, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_y, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+							      cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+							      cfg->model_value, setup_ecob.lossy_par);
+		}
+
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
 }
 
 
 /**
- * @brief map the unsigned output of the pre-stage to a signed value range
- *
- * @note change the data_buf in-place
+ * @brief decompress fast normal light flux (F_FX) data
  *
- * @param decompressed_data	pointer to the data to process
- * @param info			compressor information contains information of
- *				an executed compression
+ * @param cfg	pointer to the compression configuration structure
  *
- * @returns 0 on success, error otherwise
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
  */
 
-static int de_map_to_pos(void *decompressed_data, const struct cmp_info *info)
+static int decompress_f_fx(const struct cmp_cfg *cfg)
 {
-	int zero_mode_used;
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx;
+	struct f_fx *data_buf = cfg->input_buf;
+	struct f_fx *model_buf = cfg->model_buf;
+	struct f_fx *up_model_buf = NULL;
+	struct f_fx *next_model_p;
+	struct f_fx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!info)
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
 		return -1;
 
-	if (info->samples_used == 0)
-		return 0;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
 
-	if (!decompressed_data)
-		return -1;
-
-	zero_mode_used = zero_escape_mech_is_used(info->cmp_mode_used);
-
-	switch (info->cmp_mode_used) {
-	case MODE_RAW:
-	case MODE_RAW_S_FX:
-		return 0; /* in raw mode no mapping is necessary */
-		break;
-	case MODE_MODEL_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_ZERO:
-	case MODE_DIFF_MULTI:
-		return de_map_to_pos_16((uint16_t *)decompressed_data,
-					info->samples_used, zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		return de_map_to_pos_S_FX((struct S_FX *)decompressed_data,
-					  info->samples_used, zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		return de_map_to_pos_S_FX_EFX((struct S_FX_EFX *)
-					      decompressed_data,
-					      info->samples_used,
-					      zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-		return de_map_to_pos_S_FX_NCOB((struct S_FX_NCOB *)
-					       decompressed_data,
-					       info->samples_used,
-					       zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		return de_map_to_pos_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *)
-							decompressed_data,
-							info->samples_used,
-							zero_mode_used);
-		break;
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		return de_map_to_pos_F_FX((uint32_t *)decompressed_data,
-					  info->samples_used, zero_mode_used);
-		break;
-	default:
-		debug_print("Error: Compression mode not supported.\n");
-		break;
-	}
-	return -1;
-}
+		if (up_model_buf)
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
 
+		if (i >= cfg->samples-1)
+			break;
 
-static unsigned int get_n_bits32(uint32_t *p_value, unsigned int bitOffset,
-				unsigned int nBits, const unsigned int *srcAddr,
-				size_t src_len_bit)
-{
-	const unsigned int *localAddr;
-	unsigned int bitsLeft, bitsRight, localEndPos;
-	unsigned int mask;
-	/*leave in case of erroneous input */
-	if (nBits == 0)
-		return 0;
-	if (nBits > 32)
-		return 0;
-	if (!srcAddr)
-		return 0;
-	if (!p_value)
-		return 0;
-	if ((bitOffset + nBits) > src_len_bit) {
-		debug_print("Error: Buffer overflow detected.\n");
-		return 0;
+		model = next_model_p[i];
 	}
-	/* separate the bitOffset into word offset (set localAddr pointer) and
-	 * local bit offset (bitsLeft)
-	 */
-
-	localAddr = srcAddr + (bitOffset >> 5);
-	bitsLeft = bitOffset & 0x1f;
-
-	localEndPos = bitsLeft + nBits;
-
-	if (localEndPos <= 32) {
-		unsigned int shiftRight = 32 - nBits;
-
-		bitsRight = shiftRight - bitsLeft;
+	return stream_pos;
+}
 
-		*(p_value) = *(localAddr) >> bitsRight;
 
-		mask = (0xffffffff >> shiftRight);
+/**
+ * @brief decompress F_FX_EFX data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
 
-		*(p_value) &= mask;
+static int decompress_f_fx_efx(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx, setup_efx;
+	struct f_fx_efx *data_buf = cfg->input_buf;
+	struct f_fx_efx *model_buf = cfg->model_buf;
+	struct f_fx_efx *up_model_buf = NULL;
+	struct f_fx_efx *next_model_p;
+	struct f_fx_efx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
 	} else {
-		unsigned int n1 = 32 - bitsLeft;
-		unsigned int n2 = nBits - n1;
-		/* part 1 ; */
-		mask = 0xffffffff >> bitsLeft;
-		*(p_value) = (*localAddr) & mask;
-		*(p_value) <<= n2;
-		/*part 2: */
-		/* adjust address*/
-		localAddr += 1;
-
-		bitsRight = 32 - n2;
-		*(p_value) |= *(localAddr) >> bitsRight;
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
 	}
-	return nBits;
-}
 
-static unsigned int count_leading_ones(unsigned int value)
-{
-	unsigned int n_ones = 0; /* number of leading 1s */
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.f_efx, cfg))
+		return -1;
 
-	while (1) {
-		unsigned int leading_bit;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+		}
 
-		leading_bit = value & 0x80000000;
-		if (!leading_bit)
+		if (i >= cfg->samples-1)
 			break;
-		else {
-			n_ones++;
-			value <<= 1;
-		}
+
+		model = next_model_p[i];
 	}
-	return n_ones;
+	return stream_pos;
 }
 
 
-static unsigned int Rice_decoder(uint32_t code_word, unsigned int m,
-				 unsigned int log2_m, unsigned int *decoded_cw)
-{
-	unsigned int q; /* quotient code */
-	unsigned int ql; /* length of the quotient code */
-	unsigned int r; /* remainder code */
-	unsigned int rl; /* length of the remainder code */
-	unsigned int cw_len; /* length of the decoded code word in bits */
-
-	(void)m;
-
-	q = count_leading_ones(code_word);
-	ql = q + 1; /* Number of 1's + following 0 */
-
-	rl = log2_m;
-
-	cw_len = rl + ql;
-
-	if (cw_len > 32) /* can only decode code words with maximum 32 bits */
-		return 0;
-
-	code_word = code_word << ql;  /* shift quotient code out */
-
-	/* Right shifting an integer by a number of bits equal orgreater than
-	 * its size is undefined behavior
-	 */
-	if (rl == 0)
-		r = 0;
-	else
-		r = code_word >> (32 - rl);
-
-	*decoded_cw = (q << log2_m) + r;
-
-	return cw_len;
-}
-
+/**
+ * @brief decompress short F_FX_NCOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
 
-static unsigned int Golomb_decoder(unsigned int code_word, unsigned int m,
-				   unsigned int log2_m, unsigned int
-				   *decoded_cw)
+static int decompress_f_fx_ncob(const struct cmp_cfg *cfg)
 {
-	unsigned int q; /* quotient code */
-	unsigned int r1; /* remainder code group 1 */
-	unsigned int r2; /* remainder code group 2 */
-	unsigned int r; /* remainder code */
-	unsigned int rl; /* length of the remainder code */
-	unsigned int cutoff; /* cutoff between group 1 and 2 */
-	unsigned int cw_len; /* length of the decoded code word in bits */
-
-	q = count_leading_ones(code_word);
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx, setup_ncob;
+	struct f_fx_ncob *data_buf = cfg->input_buf;
+	struct f_fx_ncob *model_buf = cfg->model_buf;
+	struct f_fx_ncob *up_model_buf = NULL;
+	struct f_fx_ncob *next_model_p;
+	struct f_fx_ncob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	rl = log2_m + 1;
-	code_word <<= (q+1);  /* shift quotient code out */
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.f_ncob, cfg))
+		return -1;
 
-	r2 = code_word >> (32 - rl);
-	r1 = r2 >> 1;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+							      cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+							      cfg->model_value, setup_ncob.lossy_par);
+		}
 
-	cutoff = (1UL << rl) - m;
+		if (i >= cfg->samples-1)
+			break;
 
-	if (r1 < cutoff) {
-		cw_len = q + rl;
-		r = r1;
-	} else {
-		cw_len = q + rl + 1;
-		r = r2 - cutoff;
+		model = next_model_p[i];
 	}
-
-	if (cw_len > 32)
-		return 0;
-
-	*decoded_cw = q*m + r;
-	return cw_len;
+	return stream_pos;
 }
 
 
-typedef unsigned int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *);
+/**
+ * @brief decompress short F_FX_NCOB_ECOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
 
-static decoder_ptr select_decoder(unsigned int golomb_par)
+static int decompress_f_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
 {
-	if (!golomb_par)
-		return NULL;
-
-	if (is_a_pow_of_2(golomb_par))
-		return &Rice_decoder;
-	else
-		return &Golomb_decoder;
-}
-
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_fx, setup_ncob, setup_efx, setup_ecob;
+	struct f_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct f_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct f_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct f_fx_efx_ncob_ecob *next_model_p;
+	struct f_fx_efx_ncob_ecob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-static int decode_raw(const void *compressed_data, const struct cmp_info
-			*info, void *const decompressed_data)
-{
-	if (!info)
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.f_fx, cfg))
 		return -1;
-	if (info->samples_used == 0)
-		return 0;
-	if (!compressed_data)
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.f_ncob, cfg))
 		return -1;
-	if (!decompressed_data)
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.f_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				    cfg->round, max_used_bits.f_ecob, cfg))
 		return -1;
 
-	if (info->samples_used*size_of_a_sample(info->cmp_mode_used)*CHAR_BIT
-	    != info->cmp_size) {
-		debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n");
-		return 1;
-	}
-	memcpy(decompressed_data, compressed_data, info->cmp_size/CHAR_BIT);
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos,
+					  &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_x, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_y, stream_pos,
+					  &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_y = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+				cfg->model_value, setup_ecob.lossy_par);
+		}
 
-	return 0;
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
+	}
+	return stream_pos;
 }
 
-static int decode_raw_16(const void *compressed_data, const struct cmp_info
-			*info, uint16_t *const decompressed_data)
+
+/**
+ * @brief decompress long normal light flux (L_FX) data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
+
+static int decompress_l_fx(const struct cmp_cfg *cfg)
 {
 	size_t i;
-	uint16_t *p = decompressed_data;
-	uint32_t read_pos = 0;
-	unsigned int read_bits;
-	uint32_t read_val;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_fx_var;
+	struct l_fx *data_buf = cfg->input_buf;
+	struct l_fx *model_buf = cfg->model_buf;
+	struct l_fx *up_model_buf = NULL;
+	struct l_fx *next_model_p;
+	struct l_fx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!info)
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
 		return -1;
-	if (info->samples_used == 0)
-		return 0;
-	if (!compressed_data)
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
 		return -1;
-	if (!decompressed_data)
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
 		return -1;
 
-	for (i = 0; i < info->samples_used; ++i) {
-		read_bits = get_n_bits32(&read_val, read_pos, 16,
-					 compressed_data, info->cmp_size);
-		if (!read_bits)
-			return -1;
-		read_pos += 16;
-		p[i] =read_val;
-	}
-	return 0;
-}
-
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance, stream_pos,
+					  &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+								   cfg->model_value, setup_fx_var.lossy_par);
+		}
 
-static int decode_raw_S_FX(const void *compressed_data, const struct cmp_info
-			   *info, struct S_FX *const decompressed_data)
-{
-	int err = decode_raw(compressed_data, info, decompressed_data);
-	if (err)
-		return err;
+		if (i >= cfg->samples-1)
+			break;
 
-#if defined(LITTLE_ENDIAN)
-	{
-		size_t i;
-		for (i = 0; i < info->samples_used; i++) {
-			decompressed_data[i].FX = cpu_to_be32(decompressed_data[i].FX);
-		}
+		model = next_model_p[i];
 	}
-#endif
-	return 0;
+	return stream_pos;
 }
 
-static unsigned int decode_normal(const void *compressed_data,
-				  const struct cmp_info *info,
-				  unsigned int read_pos,
-				  unsigned int max_cw_len,
-				  uint32_t *const decoded_val)
-{
-	decoder_ptr decoder;
-	unsigned int n_read_bits;
-	uint32_t read_val;
-	unsigned int n_bits;
-	unsigned int read_bits;
-	unsigned int log2_g;
-
-	if (!compressed_data)
-		return -1U;
-
-	if (!info)
-		return -1U;
-
-	if (!decoded_val)
-		return -1U;
-
-	if (read_pos > info->cmp_size)
-		return -1U;
-
-	if (max_cw_len > 32)
-		return -1U;
-
-	if (max_cw_len == 0)
-		return read_pos;
-
-	decoder = select_decoder(info->golomb_par_used);
-	if (!decoder)
-		return -1U;
-
-	if (read_pos + max_cw_len > info->cmp_size)   /* check buffer overflow */
-		n_read_bits = info->cmp_size - read_pos;
-	else
-		n_read_bits = max_cw_len;
-
-	read_bits = get_n_bits32(&read_val, read_pos, n_read_bits,
-				 compressed_data, info->cmp_size);
-	if (!read_bits)
-		return -1U;
-
-	read_val = read_val << (32 - n_read_bits);
-
-	log2_g = ilog_2(info->golomb_par_used);
-	n_bits = decoder(read_val, info->golomb_par_used, log2_g, decoded_val);
-
-	return read_pos + n_bits;
-}
 
+/**
+ * @brief decompress L_FX_EFX data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
 
-static unsigned int decode_zero(const void *compressed_data,
-				const struct cmp_info *info,
-				unsigned int read_pos, unsigned int max_cw_len,
-				uint32_t *const decoded_val)
+static int decompress_l_fx_efx(const struct cmp_cfg *cfg)
 {
-	if (!info)
-		return -1U;
-
-	if (info->samples_used == 0)
-		return read_pos;
-
-	if (!compressed_data)
-		return -1U;
-
-	if (!decoded_val)
-		return -1U;
-
-	if (read_pos > info->cmp_size)
-		return -1U;
-
-	if (max_cw_len > 32)
-		return -1U;
-
-	if (max_cw_len == 0)
-		return read_pos;
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_efx, setup_fx_var;
+	struct l_fx_efx *data_buf = cfg->input_buf;
+	struct l_fx_efx *model_buf = cfg->model_buf;
+	struct l_fx_efx *up_model_buf = NULL;
+	struct l_fx_efx *next_model_p;
+	struct l_fx_efx model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	read_pos = decode_normal(compressed_data, info, read_pos, max_cw_len,
-				 decoded_val);
-	if (read_pos == -1U)
-		return -1U;
-	if (*decoded_val >= info->spill_used) /* consistency check */
-		return -1U;
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.l_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
 
-	if (*decoded_val == 0) {/* escape symbol mechanism was used; read unencoded value */
-		unsigned int n_bits;
-		uint32_t unencoded_val;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance, stream_pos,
+					  &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+								 cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+							  cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+							   cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+								   cfg->model_value, setup_fx_var.lossy_par);
+		}
 
-		n_bits = get_n_bits32(&unencoded_val, read_pos, max_cw_len,
-				      compressed_data, info->cmp_size);
-		if (!n_bits)
-			return -1U;
-		if (unencoded_val < info->spill_used && unencoded_val != 0) /* consistency check */
-			return -1U;
+		if (i >= cfg->samples-1)
+			break;
 
-		*decoded_val = unencoded_val;
-		read_pos += n_bits;
+		model = next_model_p[i];
 	}
-	return read_pos;
+	return stream_pos;
 }
 
 
-static unsigned int decode_multi(const void *compressed_data,
-				 const struct cmp_info *info,
-				 unsigned int read_pos, unsigned int max_cw_len,
-				 uint32_t *const decoded_val)
-{
-	if (!info)
-		return -1U;
-
-	if (info->samples_used == 0)
-		return read_pos;
-
-	if (!compressed_data)
-		return -1U;
-
-	if (!decoded_val)
-		return -1U;
-
-	if (read_pos > info->cmp_size)
-		return -1U;
-
-	if (max_cw_len > 32)
-		return -1U;
-
-	if (max_cw_len == 0)
-		return read_pos;
-
-	read_pos = decode_normal(compressed_data, info, read_pos, max_cw_len,
-				 decoded_val);
-	if (read_pos == -1U)
-		return -1U;
+/**
+ * @brief decompress L_FX_NCOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
 
-	if (*decoded_val >= info->spill_used) {
-		/* escape symbol mechanism was used; read unencoded value */
-		unsigned int n_bits;
-		uint32_t unencoded_val;
-		unsigned int unencoded_len;
+static int decompress_l_fx_ncob(const struct cmp_cfg *cfg)
+{
+	size_t i;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob,
+			     setup_fx_var, setup_cob_var;
+	struct l_fx_ncob *data_buf = cfg->input_buf;
+	struct l_fx_ncob *model_buf = cfg->model_buf;
+	struct l_fx_ncob *up_model_buf = NULL;
+	struct l_fx_ncob *next_model_p;
+	struct l_fx_ncob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-		unencoded_len = (*decoded_val - info->spill_used + 1) * 2;
-		if (unencoded_len > max_cw_len) /* consistency check */
-			return -1U;
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.l_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_cob_variance, cfg))
+		return -1;
 
-		/* check buffer overflow */
-		if ((read_pos + unencoded_len) > info->cmp_size) {
-			/*TODO: debug message */
-			return -1U;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance,
+					  stream_pos, &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_x_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_x_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_y_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_y_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+			up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+			up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
 		}
-		n_bits = get_n_bits32(&unencoded_val, read_pos, unencoded_len,
-				      compressed_data, info->cmp_size);
-		if (!n_bits)
-			return -1U;
 
-		*decoded_val = unencoded_val + info->spill_used;
-		read_pos += n_bits;
+		if (i >= cfg->samples-1)
+			break;
+
+		model = next_model_p[i];
 	}
-	return read_pos;
+	return stream_pos;
 }
 
 
-static unsigned int decode_value(const void *compressed_data,
-				 const struct cmp_info *info,
-				 unsigned int read_pos,
-				 unsigned int max_cw_len, uint32_t *decoded_val)
-{
-	if (multi_escape_mech_is_used(info->cmp_mode_used))
-		return decode_multi(compressed_data, info, read_pos, max_cw_len,
-				    decoded_val);
-
-	if (zero_escape_mech_is_used(info->cmp_mode_used))
-		return decode_zero(compressed_data, info, read_pos, max_cw_len,
-				   decoded_val);
-	return -1U;
-}
-
+/**
+ * @brief decompress L_FX_EFX_NCOB_ECOB data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
 
-static int decode_16(const void *compressed_data, const struct cmp_info *info,
-		     uint16_t *decoded_data)
+static int decompress_l_fx_efx_ncob_ecob(const struct cmp_cfg *cfg)
 {
 	size_t i;
-	unsigned int read_pos = 0;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, setup_efx,
+			     setup_ecob, setup_fx_var, setup_cob_var;
+	struct l_fx_efx_ncob_ecob *data_buf = cfg->input_buf;
+	struct l_fx_efx_ncob_ecob *model_buf = cfg->model_buf;
+	struct l_fx_efx_ncob_ecob *up_model_buf = NULL;
+	struct l_fx_efx_ncob_ecob *next_model_p;
+	struct l_fx_efx_ncob_ecob model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!info)
+	if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags,
+				    cfg->round, max_used_bits.l_exp_flags, cfg))
 		return -1;
-
-	if (info->samples_used == 0)
-		return 0;
-
-	if (!decoded_data)
+	if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx,
+				    cfg->round, max_used_bits.l_fx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob,
+				    cfg->round, max_used_bits.l_ncob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx,
+				    cfg->round, max_used_bits.l_efx, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob,
+				    cfg->round, max_used_bits.l_ecob, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_fx_variance, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance,
+				    cfg->round, max_used_bits.l_cob_variance, cfg))
 		return -1;
 
-	for (i = 0; i < info->samples_used; i++) {
-		uint32_t decoded_val;
-
-		read_pos = decode_value(compressed_data, info, read_pos, 16,
-					&decoded_val);
-		if (read_pos == -1U) {
-			debug_print("Error: Compressed values could not be decoded.\n");
-			return -1;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.exp_flags,
+					  stream_pos, &setup_exp_flags);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].exp_flags = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx, stream_pos,
+					  &setup_fx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_x,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ncob_y,
+					  stream_pos, &setup_ncob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ncob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.efx, stream_pos,
+					  &setup_efx);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].efx = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_x,
+					  stream_pos, &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_x = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.ecob_y,
+					  stream_pos, &setup_ecob);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].ecob_y = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.fx_variance,
+					  stream_pos, &setup_fx_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].fx_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_x_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_x_variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.cob_y_variance,
+					  stream_pos, &setup_cob_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].cob_y_variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags,
+				cfg->model_value, setup_exp_flags.lossy_par);
+			up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx,
+				cfg->model_value, setup_fx.lossy_par);
+			up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y,
+				cfg->model_value, setup_ncob.lossy_par);
+			up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx,
+				cfg->model_value, setup_efx.lossy_par);
+			up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y,
+				cfg->model_value, setup_ecob.lossy_par);
+			up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance,
+				cfg->model_value, setup_fx_var.lossy_par);
+			up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
+			up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance,
+				cfg->model_value, setup_cob_var.lossy_par);
 		}
 
-		if (decoded_val > UINT16_MAX)
-			return -1;
-
-		decoded_data[i] = (uint16_t)decoded_val;
-	}
+		if (i >= cfg->samples-1)
+			break;
 
-	if (read_pos != info->cmp_size &&
-	    cmp_bit_to_4byte(read_pos) != cmp_bit_to_4byte(info->cmp_size)) {
-		debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n");
-		return 1;
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
-static int decode_S_FX(const void *compressed_data, const struct cmp_info *info,
-		       struct S_FX *decoded_data)
+/**
+ * @brief decompress N-CAM offset data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
+
+static int decompress_nc_offset(const struct cmp_cfg *cfg)
 {
 	size_t i;
-	unsigned int read_pos = 0;
-	struct cmp_info info_exp_flag;
-
-	info_exp_flag.golomb_par_used = GOLOMB_PAR_EXPOSURE_FLAGS;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_mean, setup_var;
+	struct nc_offset *data_buf = cfg->input_buf;
+	struct nc_offset *model_buf = cfg->model_buf;
+	struct nc_offset *up_model_buf = NULL;
+	struct nc_offset *next_model_p;
+	struct nc_offset model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!info)
+	if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				    cfg->round, max_used_bits.nc_offset_mean, cfg))
 		return -1;
-
-	if (info->samples_used == 0)
-		return 0;
-
-	if (!decoded_data)
+	if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				    cfg->round, max_used_bits.nc_offset_variance, cfg))
 		return -1;
 
-	info_exp_flag = *info;
-
-	for (i = 0; i < info->samples_used; i++) {
-		uint32_t decoded_val;
-
-		/* read_pos = decode_value(compressed_data, &info_exp_flag, read_pos, 8, */
-		/* 			&decoded_val); */
-		read_pos = decode_normal(compressed_data, &info_exp_flag, read_pos, 8,
-					 &decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		if (decoded_val > UINT8_MAX)
-			return -1;
-		decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.mean, stream_pos,
+					  &setup_mean);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.variance, stream_pos,
+					  &setup_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].variance = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean,
+				model.mean, cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance = cmp_up_model(data_buf[i].variance,
+				model.variance, cfg->model_value, setup_var.lossy_par);
+		}
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].FX = decoded_val;
-	}
+		if (i >= cfg->samples-1)
+			break;
 
-	if (read_pos != info->cmp_size) {
-		debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.");
-		return 1;
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
-static int decode_S_FX_EFX(const void *compressed_data, const struct cmp_info
-			   *info, struct S_FX_EFX *decoded_data)
+/**
+ * @brief decompress N-CAM background data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
+
+static int decompress_nc_background(const struct cmp_cfg *cfg)
 {
 	size_t i;
-	unsigned int read_pos = 0;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_mean, setup_var, setup_pix;
+	struct nc_background *data_buf = cfg->input_buf;
+	struct nc_background *model_buf = cfg->model_buf;
+	struct nc_background *up_model_buf = NULL;
+	struct nc_background *next_model_p;
+	struct nc_background model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!info)
+	if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				    cfg->round, max_used_bits.nc_background_mean, cfg))
 		return -1;
-
-	if (info->samples_used == 0)
-		return 0;
-
-	if (!decoded_data)
+	if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				    cfg->round, max_used_bits.nc_background_variance, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+				    cfg->round, max_used_bits.nc_background_outlier_pixels, cfg))
 		return -1;
 
-	for (i = 0; i < info->samples_used; i++) {
-		uint32_t decoded_val;
-
-		read_pos = decode_value(compressed_data, info, read_pos, 8,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		if (decoded_val > UINT8_MAX)
-			return -1;
-		decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val;
-
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].FX = decoded_val;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.mean, stream_pos,
+					  &setup_mean);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.variance, stream_pos,
+					  &setup_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].variance = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.outlier_pixels, stream_pos,
+					  &setup_pix);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].outlier_pixels = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean,
+				model.mean, cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance = cmp_up_model(data_buf[i].variance,
+				model.variance, cfg->model_value, setup_var.lossy_par);
+			up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels,
+				model.outlier_pixels, cfg->model_value, setup_pix.lossy_par);
+		}
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].EFX = decoded_val;
-	}
+		if (i >= cfg->samples-1)
+			break;
 
-	if (read_pos != info->cmp_size) {
-		debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n");
-		return 1;
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
-static int decode_S_FX_NCOB(const void *compressed_data, const struct cmp_info
-			    *info, struct S_FX_NCOB *decoded_data)
+/**
+ * @brief decompress N-CAM smearing data
+ *
+ * @param cfg	pointer to the compression configuration structure
+ *
+ * @returns bit position of the last read bit in the bitstream on success;
+ *	returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream
+ *	buffer is too small to read the value from the bitstream
+ */
+
+static int decompress_smearing(const struct cmp_cfg *cfg)
 {
 	size_t i;
-	unsigned int read_pos = 0;
+	int stream_pos = 0;
+	uint32_t decoded_value;
+	struct decoder_setup setup_mean, setup_var, setup_pix;
+	struct smearing *data_buf = cfg->input_buf;
+	struct smearing *model_buf = cfg->model_buf;
+	struct smearing *up_model_buf = NULL;
+	struct smearing *next_model_p;
+	struct smearing model;
+
+	if (model_mode_is_used(cfg->cmp_mode))
+		up_model_buf = cfg->icu_new_model_buf;
+
+	stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf,
+						(void **)&up_model_buf, cfg);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		model = model_buf[0];
+		next_model_p = &model_buf[1];
+	} else {
+		memset(&model, 0, sizeof(model));
+		next_model_p = data_buf;
+	}
 
-	if (!info)
+	if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean,
+				    cfg->round, max_used_bits.smearing_mean, cfg))
 		return -1;
-
-	if (info->samples_used == 0)
-		return 0;
-
-	if (!decoded_data)
+	if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance,
+				    cfg->round, max_used_bits.smearing_variance_mean, cfg))
+		return -1;
+	if (configure_decoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error,
+				    cfg->round, max_used_bits.smearing_outlier_pixels, cfg))
 		return -1;
 
-	for (i = 0; i < info->samples_used; i++) {
-		uint32_t decoded_val;
-
-		read_pos = decode_value(compressed_data, info, read_pos, 8,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		if (decoded_val > UINT8_MAX)
-			return -1;
-		decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val;
-
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].FX = decoded_val;
-
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].NCOB_X = decoded_val;
+	for (i = 0; ; i++) {
+		stream_pos = decode_value(&decoded_value, model.mean, stream_pos,
+					  &setup_mean);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.variance_mean, stream_pos,
+					  &setup_var);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].variance_mean = decoded_value;
+
+		stream_pos = decode_value(&decoded_value, model.outlier_pixels, stream_pos,
+					  &setup_pix);
+		if (stream_pos <= 0)
+			return stream_pos;
+		data_buf[i].outlier_pixels = decoded_value;
+
+		if (up_model_buf) {
+			up_model_buf[i].mean = cmp_up_model(data_buf[i].mean,
+				model.mean, cfg->model_value, setup_mean.lossy_par);
+			up_model_buf[i].variance_mean = cmp_up_model(data_buf[i].variance_mean,
+				model.variance_mean, cfg->model_value, setup_var.lossy_par);
+			up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels,
+				model.outlier_pixels, cfg->model_value, setup_pix.lossy_par);
+		}
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].NCOB_Y = decoded_val;
-	}
+		if (i >= cfg->samples-1)
+			break;
 
-	if (read_pos != info->cmp_size) {
-		debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n");
-		return 1;
+		model = next_model_p[i];
 	}
-	return 0;
+	return stream_pos;
 }
 
 
-static int decode_S_FX_EFX_NCOB_ECOB(const void *compressed_data,
-				     const struct cmp_info *info,
-				     struct S_FX_EFX_NCOB_ECOB *decoded_data)
+/**
+ * @brief decompress the data based on a compression configuration
+ *
+ * @param cfg	pointer to a compression configuration
+ *
+ * @note cfg->buffer_length is measured in bytes (instead of samples as by the
+ *	compression)
+ *
+ * @returns the size of the decompressed data on success; returns negative on failure
+ */
+
+static int decompressed_data_internal(struct cmp_cfg *cfg)
 {
-	size_t i;
-	unsigned int read_pos = 0;
+	int data_size, strem_len_bit = -1;
 
-	if (!info)
+	if (!cfg)
 		return -1;
 
-	if (info->samples_used == 0)
-		return 0;
-
-	if (!decoded_data)
+	if (!cfg->icu_output_buf)
 		return -1;
 
-	for (i = 0; i < info->samples_used; i++) {
-		uint32_t decoded_val;
+	data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);
+	if (!cfg->input_buf || !data_size)
+		return data_size;
 
-		read_pos = decode_value(compressed_data, info, read_pos, 8,
-					&decoded_val);
-		if (read_pos == -1U)
+	if (model_mode_is_used(cfg->cmp_mode))
+		if (!cfg->model_buf)
 			return -1;
-		if (decoded_val > UINT8_MAX)
-			return -1;
-		decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val;
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].FX = decoded_val;
+	if (cfg->cmp_mode == CMP_MODE_RAW) {
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
+		if ((unsigned int)data_size < cfg->buffer_length/CHAR_BIT)
 			return -1;
-		decoded_data[i].NCOB_X = decoded_val;
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].NCOB_Y = decoded_val;
+		if (cfg->input_buf) {
+			memcpy(cfg->input_buf, cfg->icu_output_buf, data_size);
+			if (cmp_input_big_to_cpu_endianness(cfg->input_buf, data_size, cfg->data_type))
+				return -1;
+			strem_len_bit = data_size * CHAR_BIT;
+		}
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].EFX = decoded_val;
+	} else {
+		switch (cfg->data_type) {
+		case DATA_TYPE_IMAGETTE:
+		case DATA_TYPE_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_SAT_IMAGETTE:
+		case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+		case DATA_TYPE_F_CAM_IMAGETTE:
+		case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+			strem_len_bit = decompress_imagette(cfg);
+			break;
+		case DATA_TYPE_S_FX:
+			strem_len_bit = decompress_s_fx(cfg);
+			break;
+		case DATA_TYPE_S_FX_EFX:
+			strem_len_bit = decompress_s_fx_efx(cfg);
+			break;
+		case DATA_TYPE_S_FX_NCOB:
+			strem_len_bit = decompress_s_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+			strem_len_bit = decompress_s_fx_efx_ncob_ecob(cfg);
+			break;
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].ECOB_X = decoded_val;
+		case DATA_TYPE_F_FX:
+			strem_len_bit = decompress_f_fx(cfg);
+			break;
+		case DATA_TYPE_F_FX_EFX:
+			strem_len_bit = decompress_f_fx_efx(cfg);
+			break;
+		case DATA_TYPE_F_FX_NCOB:
+			strem_len_bit = decompress_f_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+			strem_len_bit = decompress_f_fx_efx_ncob_ecob(cfg);
+			break;
 
-		read_pos = decode_value(compressed_data, info, read_pos, 32,
-					&decoded_val);
-		if (read_pos == -1U)
-			return -1;
-		decoded_data[i].ECOB_Y = decoded_val;
-	}
+		case DATA_TYPE_L_FX:
+			strem_len_bit = decompress_l_fx(cfg);
+			break;
+		case DATA_TYPE_L_FX_EFX:
+			strem_len_bit = decompress_l_fx_efx(cfg);
+			break;
+		case DATA_TYPE_L_FX_NCOB:
+			strem_len_bit = decompress_l_fx_ncob(cfg);
+			break;
+		case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+			strem_len_bit = decompress_l_fx_efx_ncob_ecob(cfg);
+			break;
 
-	if (read_pos != info->cmp_size) {
-		debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.");
-		return 1;
+		case DATA_TYPE_OFFSET:
+			strem_len_bit = decompress_nc_offset(cfg);
+			break;
+		case DATA_TYPE_BACKGROUND:
+			strem_len_bit = decompress_nc_background(cfg);
+			break;
+		case DATA_TYPE_SMEARING:
+			strem_len_bit = decompress_smearing(cfg);
+			break;
+
+		case DATA_TYPE_F_CAM_OFFSET:
+		case DATA_TYPE_F_CAM_BACKGROUND:
+		case DATA_TYPE_UNKNOWN:
+		default:
+			strem_len_bit = -1;
+			debug_print("Error: Compressed data type not supported.\n");
+			break;
+		}
 	}
-	return 0;
+	if (strem_len_bit <= 0)
+		return -1;
+
+	return data_size;
 }
 
 
-static int decode_data(const void *compressed_data, const struct cmp_info *info,
-		       void *decompressed_data)
+/**
+ * @brief decompress a compression entity
+ *
+ * @param ent			pointer to the compression entity to be decompressed
+ * @param model_of_data		pointer to model data buffer (can be NULL if no
+ *				model compression mode is used)
+ * @param updated_model		pointer to store the updated model for the next model
+ *				mode compression (can be the same as the model_of_data
+ *				buffer for in-place update or NULL if updated model is not needed)
+ * @param decompressed_data	pointer to the decompressed data buffer (can be NULL)
+ *
+ * @returns the size of the decompressed data on success; returns negative on failure
+ */
+
+int decompress_cmp_entiy(struct cmp_entity *ent, void *model_of_data,
+			 void *up_model_buf, void *decompressed_data)
 {
-	if (!info)
-		return -1;
+	int err;
+	struct cmp_cfg cfg = {0};
 
-	if (info->samples_used == 0)
-		return 0;
+	cfg.model_buf = model_of_data;
+	cfg.icu_new_model_buf = up_model_buf;
+	cfg.input_buf = decompressed_data;
 
-	if (!compressed_data)
+	if (!ent)
 		return -1;
 
-	if (!decompressed_data)
-		return -1;
-
-	switch (info->cmp_mode_used) {
-	case MODE_RAW:
-		return decode_raw_16(compressed_data, info, decompressed_data);
-		break;
-	case MODE_MODEL_ZERO:
-	case MODE_DIFF_ZERO:
-	case MODE_MODEL_MULTI:
-	case MODE_DIFF_MULTI:
-		return decode_16(compressed_data, info,
-				 (uint16_t *)decompressed_data);
-		break;
-	case MODE_RAW_S_FX:
-		return decode_raw_S_FX(compressed_data, info, decompressed_data);
-		break;
-	case MODE_MODEL_ZERO_S_FX:
-	case MODE_MODEL_MULTI_S_FX:
-	case MODE_DIFF_ZERO_S_FX:
-	case MODE_DIFF_MULTI_S_FX:
-		return decode_S_FX(compressed_data, info,
-				   (struct S_FX *)decompressed_data);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX:
-	case MODE_MODEL_MULTI_S_FX_EFX:
-	case MODE_DIFF_ZERO_S_FX_EFX:
-	case MODE_DIFF_MULTI_S_FX_EFX:
-		return decode_S_FX_EFX(compressed_data, info,
-				       (struct S_FX_EFX *)decompressed_data);
-		break;
-	case MODE_MODEL_ZERO_S_FX_NCOB:
-	case MODE_MODEL_MULTI_S_FX_NCOB:
-	case MODE_DIFF_ZERO_S_FX_NCOB:
-	case MODE_DIFF_MULTI_S_FX_NCOB:
-		return decode_S_FX_NCOB(compressed_data, info,
-					(struct S_FX_NCOB *)decompressed_data);
-		break;
-	case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB:
-	case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB:
-		return decode_S_FX_EFX_NCOB_ECOB(compressed_data, info,
-						 (struct S_FX_EFX_NCOB_ECOB *)
-						 decompressed_data);
-		break;
-#if 0
-	case MODE_MODEL_ZERO_F_FX:
-	case MODE_MODEL_MULTI_F_FX:
-	case MODE_DIFF_ZERO_F_FX:
-	case MODE_DIFF_MULTI_F_FX:
-		break;
-#endif
-	default:
-		debug_print("Error: Compression mode not supported.\n");
-		break;
+	err = cmp_ent_read_header(ent, &cfg);
+	if (err)
+		return -1;
 
-	}
-	return -1;
+	return decompressed_data_internal(&cfg);
 }
 
-/* model buffer is overwritten with updated model*/
 
-int decompress_data(const void *compressed_data, void *de_model_buf, const
-		    struct cmp_info *info, void *decompressed_data)
+/**
+ * @brief decompress RDCU compressed data without a compression entity header
+ *
+ * @param compressed_data	pointer to the RDCU compressed data (without a
+ *				compression entity header)
+ * @param model_of_data		pointer to model data buffer (can be NULL if no
+ *				model compression mode is used)
+ * @param updated_model		pointer to store the updated model for the next model
+ *				mode compression (can be the same as the model_of_data
+ *				buffer for in-place update or NULL if updated model is not needed)
+ * @param decompressed_data	pointer to the decompressed data buffer (can be NULL)
+ *
+ * @returns the size of the decompressed data on success; returns negative on failure
+ */
+
+int decompress_rdcu_data(uint32_t *compressed_data, const struct cmp_info *info,
+			 uint16_t *model_of_data, uint16_t *up_model_buf,
+			 uint16_t *decompressed_data)
+
 {
-	int err;
+	struct cmp_cfg cfg = {0};
 
 	if (!compressed_data)
 		return -1;
@@ -1527,26 +2201,19 @@ int decompress_data(const void *compressed_data, void *de_model_buf, const
 	if (info->cmp_err)
 		return -1;
 
-	if (model_mode_is_used(info->cmp_mode_used))
-		if (!de_model_buf)
-			return -1;
-	/* TODO: add ohter modes */
-
-	if (!decompressed_data)
-		return -1;
-
-
-	err = decode_data(compressed_data, info, decompressed_data);
-	if (err)
-		return err;
-
-	err = de_map_to_pos(decompressed_data, info);
-	if (err)
-		return err;
-
-	err = de_pre_process(decompressed_data, de_model_buf, info);
-	if (err)
-		return err;
-
-	return 0;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.model_buf = model_of_data;
+	cfg.icu_new_model_buf = up_model_buf;
+	cfg.input_buf = decompressed_data;
+
+	cfg.cmp_mode = info->cmp_mode_used;
+	cfg.model_value = info->model_value_used;
+	cfg.round = info->round_used;
+	cfg.spill = info->spill_used;
+	cfg.golomb_par = info->golomb_par_used;
+	cfg.samples = info->samples_used;
+	cfg.icu_output_buf = compressed_data;
+	cfg.buffer_length = cmp_bit_to_4byte(info->cmp_size);
+
+	return decompressed_data_internal(&cfg);
 }
diff --git a/lib/meson.build b/lib/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..f072ce4371b24f303ac3f51a607735870fd216f2
--- /dev/null
+++ b/lib/meson.build
@@ -0,0 +1,22 @@
+cmplib_sources = files([
+  'cmp_data_types.c',
+  'cmp_icu.c',
+  'cmp_support.c',
+  'rdcu_ctrl.c',
+  'rmap.c',
+  'cmp_entity.c',
+  'cmp_io.c',
+  'decmp.c',
+  'rdcu_pkt_to_file.c',
+  'cmp_guess.c',
+  'cmp_rdcu.c',
+  'rdcu_cmd.c',
+  'rdcu_rmap.c'
+])
+
+cmp_lib = static_library('cmp_lib',
+  sources : cmplib_sources,
+  include_directories : incdir,
+  c_args : ['-DDEBUGLEVEL=1'],
+#  install : 'true' # linking under windows mingw only works if this is set
+)
diff --git a/lib/rdcu_ctrl.c b/lib/rdcu_ctrl.c
index a1e3b0ffdf92197ebba433c04a4291b71c22df1a..6f743c68c09bc656bef11a941845d1d9cb7847ea 100644
--- a/lib/rdcu_ctrl.c
+++ b/lib/rdcu_ctrl.c
@@ -1305,44 +1305,97 @@ uint32_t rdcu_get_compr_data_start_addr(void)
 
 
 /**
- * @brief get compressed data size
+ * @brief get the need bytes for the given bits
+ *
+ * @param cmp_size_bit compressed data size, measured in bits
+ *
+ * @returns the size in bytes to store the compressed data
+ */
+
+static uint32_t rdcu_bit_to_byte(unsigned int cmp_size_bit)
+{
+	return ((cmp_size_bit + 7) / 8);
+}
+
+
+/**
+ * @brief get compressed data size in bits
  * @see RDCU-FRS-FN-0922
  *
  * @returns the compressed data size in bits
  */
 
-uint32_t rdcu_get_compr_data_size(void)
+uint32_t rdcu_get_compr_data_size_bit(void)
 {
 	return rdcu->compr_data_size;
 }
 
 
 /**
- * @brief get compressed data adaptive 1 size
+ * @brief get compressed data size in bytes
+ * @see RDCU-FRS-FN-0922
+ *
+ * @returns the compressed data size in bytes
+ */
+
+uint32_t rdcu_get_compr_data_size_byte(void)
+{
+	return rdcu_bit_to_byte(rdcu_get_compr_data_size_bit());
+}
+
+
+/**
+ * @brief get compressed data adaptive 1 size in bits
  * @see RDCU-FRS-FN-0932
  *
  * @returns the adaptive 1 compressed data size in bits
  */
 
-uint32_t rdcu_get_compr_data_adaptive_1_size(void)
+uint32_t rdcu_get_compr_data_adaptive_1_size_bit(void)
 {
 	return rdcu->compr_data_adaptive_1_size;
 }
 
 
 /**
- * @brief get compressed data adaptive 2 size
+ * @brief get compressed data adaptive 1 size in bytes
+ * @see RDCU-FRS-FN-0932
+ *
+ * @returns the adaptive 1 compressed data size in bytes
+ */
+
+uint32_t rdcu_get_compr_data_adaptive_1_size_byte(void)
+{
+	return rdcu_bit_to_byte(rdcu_get_compr_data_adaptive_1_size_bit());
+}
+
+
+/**
+ * @brief get compressed data adaptive 2 size in bits
  * @see RDCU-FRS-FN-0942
  *
  * @returns the adaptive 2 compressed data size in bits
  */
 
-uint32_t rdcu_get_compr_data_adaptive_2_size(void)
+uint32_t rdcu_get_compr_data_adaptive_2_size_bit(void)
 {
 	return rdcu->compr_data_adaptive_2_size;
 }
 
 
+/**
+ * @brief get compressed data adaptive 2 size in bytes
+ * @see RDCU-FRS-FN-0942
+ *
+ * @returns the adaptive 2 compressed data size in bytes
+ */
+
+uint32_t rdcu_get_compr_data_adaptive_2_size_byte(void)
+{
+	return rdcu_bit_to_byte(rdcu_get_compr_data_adaptive_2_size_bit());
+}
+
+
 /**
  * @brief get compression error code
  * @see RDCU-FRS-FN-0954
@@ -1606,7 +1659,7 @@ int rdcu_write_sram_16(uint16_t *buf, uint32_t addr, uint32_t size)
 	{
 		uint32_t i;
 
-		for (i = 0; i < size/sizeof(uint16_t); i++){
+		for (i = 0; i < size/sizeof(uint16_t); i++) {
 			uint16_t *sram_buf = (uint16_t *)&rdcu->sram[addr];
 
 			sram_buf[i] = cpu_to_be16(buf[i]);
@@ -1652,9 +1705,9 @@ int rdcu_write_sram_32(uint32_t *buf, uint32_t addr, uint32_t size)
 	{
 		uint32_t i;
 
-	for (i = 0; i < size/sizeof(uint32_t); i++){
-		uint32_t *sram_buf = (uint32_t *)&rdcu->sram[addr];
-	
+		for (i = 0; i < size/sizeof(uint32_t); i++) {
+			uint32_t *sram_buf = (uint32_t *)&rdcu->sram[addr];
+
 			sram_buf[i] = cpu_to_be32(buf[i]);
 		}
 	}
@@ -2466,14 +2519,12 @@ int rdcu_sync_sram_mirror_parallel(uint32_t rx_addr, uint32_t rx_size,
 
 int rdcu_ctrl_init(void)
 {
-	rdcu = (struct rdcu_mirror *) malloc(sizeof(struct rdcu_mirror));
-	if (!rdcu){
+	rdcu = (struct rdcu_mirror *) calloc(1, sizeof(struct rdcu_mirror));
+	if (!rdcu) {
 		printf("Error allocating memory for the RDCU mirror\n");
 		return -1;
 	}
 
-	memset(rdcu, 0, sizeof(struct rdcu_mirror));
-
 #if (__sparc__)
 	rdcu->sram =  (uint8_t *) 0x60000000;
 #else /* assume PC */
@@ -2485,7 +2536,7 @@ int rdcu_ctrl_init(void)
 	}
 #endif
 
-	memset(rdcu->sram, 0, RDCU_SRAM_SIZE);
-	
+	memset(rdcu->sram, 0, RDCU_SRAM_SIZE);  /* clear sram buffer */
+
 	return 0;
 }
diff --git a/lib/rdcu_pkt_to_file.c b/lib/rdcu_pkt_to_file.c
index 83074d70141cdcbc9b3ae6f196b802215cfd46fc..9e80125f0335a9576dc56194c79479155a906368 100644
--- a/lib/rdcu_pkt_to_file.c
+++ b/lib/rdcu_pkt_to_file.c
@@ -17,7 +17,7 @@
  *
  * This library provided a rmap_rx and rmap_tx function for the rdcu_rmap
  * library to write generated packets into text files.
- *
+ * @warning this part of the software is not intended to run on-board on the ICU.
  */
 
 #include <stdint.h>
@@ -28,11 +28,11 @@
 #include <errno.h>
 #include <sys/stat.h>
 
-#include "../include/rdcu_pkt_to_file.h"
-#include "../include/cmp_rdcu_extended.h"
-#include "../include/rdcu_rmap.h"
-#include "../include/rdcu_ctrl.h"
-#include "../include/rdcu_cmd.h"
+#include <rdcu_pkt_to_file.h>
+#include <cmp_rdcu_extended.h>
+#include <rdcu_rmap.h>
+#include <rdcu_ctrl.h>
+#include <rdcu_cmd.h>
 
 /* Name of directory were the RMAP packages are stored */
 static char tc_folder_dir[MAX_TC_FOLDER_DIR_LEN] = "TC_FILES";
@@ -52,7 +52,6 @@ void set_tc_folder_dir(const char *dir_name)
 	strncpy(tc_folder_dir, dir_name, sizeof(tc_folder_dir));
 	/*  Ensure null-termination. */
 	tc_folder_dir[sizeof(tc_folder_dir) - 1] = '\0';
-	return;
 }
 
 
@@ -292,8 +291,7 @@ static int read_rdcu_pkt_mode_cfg(uint8_t *icu_addr, uint8_t *rdcu_addr,
 	if (read_all < 0x7)
 		return -1;
 
-	printf("Use ICU_ADDR = %#02X, RDCU_ADDR = %#02X and MTU = %d for the "
-	       "RAMP packets.\n", *icu_addr, *rdcu_addr, *mtu);
+	printf("Use ICU_ADDR = %#02X, RDCU_ADDR = %#02X and MTU = %d for the RAMP packets.\n", *icu_addr, *rdcu_addr, *mtu);
 
 	return 0;
 }
@@ -313,8 +311,11 @@ int init_rmap_pkt_to_file(void)
 	uint8_t icu_addr, rdcu_addr;
 	int mtu;
 
-	if (read_rdcu_pkt_mode_cfg(&icu_addr, &rdcu_addr, &mtu))
-		return -1;
+	if (read_rdcu_pkt_mode_cfg(&icu_addr, &rdcu_addr, &mtu)) {
+		icu_addr = DEF_ICU_ADDR;
+		rdcu_addr = DEF_RDCU_ADDR;
+		mtu = DEF_MTU;
+	}
 	rdcu_ctrl_init();
 	rdcu_set_source_logical_address(icu_addr);
 	rdcu_set_destination_logical_address(rdcu_addr);
@@ -325,7 +326,7 @@ int init_rmap_pkt_to_file(void)
 
 
 /**
- * @brief generate the rmap packets to set up a RDCU compression
+ * @brief generate the rmap packets to set up an RDCU compression
  * @note note that the initialization function init_rmap_pkt_to_file() must be
  *	executed before
  * @note the configuration of the ICU_ADDR, RDCU_ADDR, MTU settings are in the
@@ -365,7 +366,7 @@ int gen_write_rdcu_pkts(const struct cmp_cfg *cfg)
 
 
 /**
- * @brief generate the rmap packets to read the result of a RDCU compression
+ * @brief generate the rmap packets to read the result of an RDCU compression
  * @note note that the initialization function init_rmap_pkt_to_file() must be
  *	executed before
  * @note the configuration of the ICU_ADDR, RDCU_ADDR, MTU settings are in the
@@ -436,7 +437,7 @@ int gen_read_rdcu_pkts(const struct cmp_info *info)
 
 
 /**
- * @brief generate the rmap packets to set up a RDCU compression, read the
+ * @brief generate the rmap packets to set up an RDCU compression, read the
  *	bitstream and the updated model in parallel to write the data to compressed
  *	and the model and start the compression
  * @note the compressed data are read from cfg->rdcu_buffer_adr with the length
diff --git a/lib/rdcu_rmap.c b/lib/rdcu_rmap.c
index f6035cb519815fc287e234dde2039d7c850088df..e4ec4b61952db0049c37d36914d5216c69c6aecf 100644
--- a/lib/rdcu_rmap.c
+++ b/lib/rdcu_rmap.c
@@ -70,7 +70,7 @@
 #include <rmap.h>
 #include <rdcu_rmap.h>
 
-
+#define RDCU_CONFIG_DEBUG 0
 
 static uint8_t rdcu_addr;
 static uint8_t icu_addr;
@@ -116,8 +116,8 @@ static size_t data_mtu;	/* maximum data transfer size per unit */
  * Every time a slot is retrieved, the "pending" counter is incremented to
  * have a fast indicator of the synchronisation status, i.e. if "pending"
  * is not set, the synchronisation procedure is complete and the local data may
- * be read, or the remote data has been written and further commands may may
- * be issued.
+ * be read, or the remote data has been written and further commands may be
+ * issued.
  *
  * The local (mirror) start address of the requested remote address is stored
  * into the same slot in the "local_addr" array, so we'll know where to put the
@@ -261,7 +261,7 @@ static int rdcu_process_rx(void)
 
 		cnt++;
 
-		if ((0))
+		if (RDCU_CONFIG_DEBUG)
 			rmap_parse_pkt(spw_pckt);
 
 		/* convert format */
@@ -276,25 +276,20 @@ static int rdcu_process_rx(void)
 		local_addr = trans_log_get_addr(rp->tr_id);
 
 		if (!local_addr) {
-			printf("warning: response packet received not in "
-			       "transaction log\n");
+			printf("Warning: response packet received not in transaction log\n");
 			rmap_erase_packet(rp);
 			continue;
 		}
 
-
 		if (rp->data_len & 0x3) {
-			printf("Error: response packet data size is not a "
-			       "multiple of 4, transaction dropped\n");
+			printf("Error: response packet data size is not a multiple of 4, transaction dropped\n");
 
 			trans_log_release_slot(rp->tr_id);
 			rmap_erase_packet(rp);
 			return -1;
 		}
 
-
 		if (rp->data_len) {
-
 			uint8_t crc8;
 
 			/* convert endianess if needed */
@@ -308,13 +303,9 @@ static int rdcu_process_rx(void)
 			}
 #endif /* __BYTE_ORDER__ */
 
-
 			crc8 = rmap_crc8(rp->data, rp->data_len);
-
 			if (crc8 != rp->data_crc) {
-
-				printf("Error: data CRC8 mismatch, data invalid or "
-				       "packet truncated. Transaction dropped\n");
+				printf("Error: data CRC8 mismatch, data invalid or packet truncated. Transaction dropped\n");
 
 				trans_log_release_slot(rp->tr_id);
 				rmap_erase_packet(rp);
@@ -353,7 +344,7 @@ int rdcu_submit_tx(const uint8_t *cmd,  int cmd_size,
 	if (!rmap_tx)
 		return -1;
 
-	if ((0))
+	if (RDCU_CONFIG_DEBUG)
 		printf("Transmitting RMAP command\n");
 
 	if (rmap_tx(cmd, cmd_size, dpath_len, data, data_size)) {
@@ -413,7 +404,7 @@ int rdcu_gen_cmd(uint16_t trans_id, uint8_t *cmd,
 		return n;
 	}
 
-	memset(cmd, 0, n);
+	memset(cmd, 0, n);  /* clear command buffer */
 
 	n = rmap_build_hdr(pkt, cmd);
 
@@ -476,8 +467,7 @@ int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd),
 
 	/* convert endianess if needed */
 #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-	if (data_len)
-	{
+	if (data_len) {
 		int i;
 		uint32_t *tmp_buf = alloca(data_len);
 		uint32_t *p = (uint32_t *) addr;
@@ -500,7 +490,7 @@ int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd),
 /**
  * @brief submit a data sync command
  *
- * @param fn a RDCU data transfer generation function
+ * @param fn an RDCU data transfer generation function
  * @param addr the remote address
  * @param data the local data address
  * @param data_len the length of the data payload
@@ -530,7 +520,7 @@ int rdcu_sync_data(int (*fn)(uint16_t trans_id, uint8_t *cmd,
 
 	slot = trans_log_grab_slot(data);
 	if (slot < 0) {
-		if ((0))
+		if (RDCU_CONFIG_DEBUG)
 			printf("Error: all slots busy!\n");
 		return 1;
 	}
@@ -782,7 +772,7 @@ int rdcu_rmap_sync_status(void)
 
 void rdcu_rmap_reset_log(void)
 {
-	memset(trans_log.in_use, 0, TRANS_LOG_SIZE);
+	memset(trans_log.in_use, 0, sizeof(trans_log.in_use));  /* clear in_use buffer */
 	trans_log.pending = 0;
 }
 
diff --git a/lib/rmap.c b/lib/rmap.c
index f8b6eb0c4a38226bc4f5cd270332033b97e1eb6f..703add595bb907340be3399759178229afa6db89 100644
--- a/lib/rmap.c
+++ b/lib/rmap.c
@@ -178,7 +178,7 @@ struct rmap_pkt *rmap_create_packet(void)
 	struct rmap_pkt *pkt;
 
 
-	pkt = (struct rmap_pkt *) calloc(sizeof(struct rmap_pkt), 1);
+	pkt = (struct rmap_pkt *) calloc(1, sizeof(struct rmap_pkt));
 	if (pkt)
 		pkt->proto_id = RMAP_PROTOCOL_ID;
 
@@ -206,7 +206,7 @@ void rmap_destroy_packet(struct rmap_pkt *pkt)
  * @param pkt a struct rmap_pkt
  *
  * @note this will attempt to deallocate any pointer references assigned by the
- * 	 user
+ *	 user
  * @warning use with care
  */
 
@@ -563,7 +563,7 @@ struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len)
 
 	pkt->src   = buf[RMAP_SRC_ADDR + n];
 	pkt->tr_id = ((uint16_t) buf[RMAP_TRANS_ID_BYTE0 + n] << 8) |
-	              (uint16_t) buf[RMAP_TRANS_ID_BYTE1 + n];
+		      (uint16_t) buf[RMAP_TRANS_ID_BYTE1 + n];
 
 	/* commands have a data address */
 	if (pkt->ri.cmd_resp) {
@@ -576,10 +576,9 @@ struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len)
 
 	/* all headers have data length unless they are a write reply */
 	if (!(!pkt->ri.cmd_resp && (pkt->ri.cmd & (RMAP_CMD_BIT_WRITE)))) {
-
 		pkt->data_len = ((uint32_t) buf[RMAP_DATALEN_BYTE0 + n] << 16) |
 				((uint32_t) buf[RMAP_DATALEN_BYTE1 + n] <<  8) |
-			         (uint32_t) buf[RMAP_DATALEN_BYTE2 + n];
+				 (uint32_t) buf[RMAP_DATALEN_BYTE2 + n];
 	}
 
 	pkt->hdr_crc  = buf[RMAP_HEADER_CRC];
@@ -587,7 +586,7 @@ struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len)
 	if (pkt->data_len) {
 		if (len < RMAP_DATA_START + n + pkt->data_len + 1) {  /* +1 for data CRC */
 			printf("buffer len is smaller than the contained RMAP packet; buf len: %u bytes vs RMAP: %zu bytes needed\n",
-				len , RMAP_DATA_START + n + pkt->data_len);
+				len, RMAP_DATA_START + n + pkt->data_len);
 			goto error;
 		}
 		if (len > RMAP_DATA_START + n + pkt->data_len + 1)  /* +1 for data CRC */
@@ -702,7 +701,7 @@ static void rmap_process_read_reply(uint8_t *pkt)
 	for (i = 0; i < len; i++)
 		printf("%02x:", pkt[RMAP_DATA_START + i]);
 
-	printf("\b \n");
+	printf("\b\n");
 }
 
 
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..53603eebf0b0e1af1fb963b45023abc37659c990
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,31 @@
+project('cmp_tool', 'c',
+  version : '0.09',
+  meson_version : '>= 0.56',
+  license : 'GPL-2.0',
+  default_options : ['warning_level=3', 'c_std=gnu99']
+)
+
+add_project_arguments('-DDEBUGLEVEL=1', language : 'c')
+
+if (host_machine.system() == 'windows' or host_machine.system() == 'cygwin') and meson.get_compiler('c').get_id() == 'gcc'
+  # by default, MinGW on win32 behaves as if it ignores __attribute__((packed)),
+  # you need to add -mno-ms-bitfields to make it work as expected.
+  # See: https://wintermade.it/blog/posts/__attribute__packed-on-windows-is-ignored-with-mingw.html
+  add_project_arguments('-mno-ms-bitfields', language : 'c')
+  add_global_link_arguments('-static', language: 'c')
+endif
+
+subdir('include')
+subdir('lib')
+
+main = files('cmp_tool.c')
+
+cmp_tool_exe = executable('cmp_tool',
+  sources : main,
+  include_directories : incdir,
+  link_with : cmp_lib,
+  install : 'true'
+)
+
+subdir('test')
+subdir('doc/doxygen')
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fe8670ef9356c298fd3cc2fe813aeca7165d35f5
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,2 @@
+option('argument_input_mode', type : 'boolean', value : false,
+  description : 'If set, the data file is set with the first argument and the model file with the second one')
diff --git a/mingw-w64-64.txt b/mingw-w64-64.txt
new file mode 100644
index 0000000000000000000000000000000000000000..773be92376afa65261c519bae973fca17e8e3cc9
--- /dev/null
+++ b/mingw-w64-64.txt
@@ -0,0 +1,24 @@
+[binaries]
+c = 'x86_64-w64-mingw32-gcc'
+cpp = 'x86_64-w64-mingw32-g++'
+objc = 'x86_64-w64-mingw32-gcc'
+ar = 'x86_64-w64-mingw32-ar'
+strip = 'x86_64-w64-mingw32-strip'
+pkgconfig = 'x86_64-w64-mingw32-pkg-config'
+windres = 'x86_64-w64-mingw32-windres'
+exe_wrapper = 'wine64'
+cmake = 'cmake'
+
+[host_machine]
+system = 'windows'
+cpu_family = 'x86_64'
+cpu = 'x86_64'
+endian = 'little'
+
+[cmake]
+
+CMAKE_BUILD_WITH_INSTALL_RPATH     = 'ON'
+CMAKE_FIND_ROOT_PATH_MODE_PROGRAM  = 'NEVER'
+CMAKE_FIND_ROOT_PATH_MODE_LIBRARY  = 'ONLY'
+CMAKE_FIND_ROOT_PATH_MODE_INCLUDE  = 'ONLY'
+CMAKE_FIND_ROOT_PATH_MODE_PACKAGE  = 'ONLY'
diff --git a/subprojects/unity.wrap b/subprojects/unity.wrap
new file mode 100644
index 0000000000000000000000000000000000000000..8cc488366197ec4f255d93fb4642367c88f5744b
--- /dev/null
+++ b/subprojects/unity.wrap
@@ -0,0 +1,8 @@
+[wrap-file]
+directory = Unity-2.5.2
+source_url = https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.5.2.tar.gz
+source_filename = Unity-2.5.2.tar.gz
+source_hash = 3786de6c8f389be3894feae4f7d8680a02e70ed4dbcce36109c8f8646da2671a
+
+[provide]
+unity = unity_dep
diff --git a/test/cmp_data_types/meson.build b/test/cmp_data_types/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..8de2ef86510c269ed1c3888c806c0a630133ec1c
--- /dev/null
+++ b/test/cmp_data_types/meson.build
@@ -0,0 +1,12 @@
+test_case = files('test_cmp_data_types.c')
+test_runner = test_runner_generator.process(test_case)
+
+test_cmp_icu = executable('test_cmp_data_types',
+   test_case, test_runner,
+   include_directories : incdir,
+   link_with : cmp_lib,
+   dependencies : unity_dep,
+   build_by_default : false
+)
+
+test('Compression Data Types Unit Tests', test_cmp_icu)
diff --git a/test/cmp_data_types/test_cmp_data_types.c b/test/cmp_data_types/test_cmp_data_types.c
new file mode 100644
index 0000000000000000000000000000000000000000..881f46a250f904a1fab14a685b7c2b315fc5553b
--- /dev/null
+++ b/test/cmp_data_types/test_cmp_data_types.c
@@ -0,0 +1,26 @@
+#include <stdint.h>
+
+#include "unity.h"
+#include "cmp_data_types.h"
+
+/**
+ * @test cmp_cal_size_of_data
+ */
+
+void test_cmp_cal_size_of_data(void)
+{
+	unsigned int s;
+
+	s = cmp_cal_size_of_data(1, DATA_TYPE_IMAGETTE);
+	TEST_ASSERT_EQUAL_UINT(sizeof(uint16_t), s);
+
+	s = cmp_cal_size_of_data(1, DATA_TYPE_F_FX);
+	TEST_ASSERT_EQUAL_UINT(sizeof(struct f_fx)+MULTI_ENTRY_HDR_SIZE, s);
+
+	/* overflow tests */
+	s = cmp_cal_size_of_data(0x1999999A, DATA_TYPE_BACKGROUND);
+	TEST_ASSERT_EQUAL_UINT(0, s);
+	s = cmp_cal_size_of_data(0x19999999, DATA_TYPE_BACKGROUND);
+	TEST_ASSERT_EQUAL_UINT(0, s);
+}
+
diff --git a/test/cmp_entity/meson.build b/test/cmp_entity/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..72219124fb502125bbe9482379c81097b9c148b5
--- /dev/null
+++ b/test/cmp_entity/meson.build
@@ -0,0 +1,12 @@
+test_case = files('test_cmp_entity.c')
+test_runner = test_runner_generator.process(test_case)
+
+test_cmp_entity = executable('test_cmp_data_types',
+   test_case, test_runner,
+   include_directories : incdir,
+   link_with : cmp_lib,
+   dependencies : unity_dep,
+   build_by_default : false
+)
+
+test('Compression Entity Unit Tests', test_cmp_entity)
diff --git a/test/cmp_entity/test_cmp_entity.c b/test/cmp_entity/test_cmp_entity.c
new file mode 100644
index 0000000000000000000000000000000000000000..8493e329333bf928bfe0a0dfd1ad666a28291d11
--- /dev/null
+++ b/test/cmp_entity/test_cmp_entity.c
@@ -0,0 +1,51 @@
+#include <unity.h>
+
+#include <cmp_entity.h>
+#include <cmp_io.h>
+
+void test_cmp_ent_get_data_buf(void)
+{
+	enum cmp_data_type data_type;/*TODO: implement: DATA_TYPE_F_CAM_OFFSET, DATA_TYPE_F_CAM_BACKGROUND */
+	struct cmp_entity ent = {0};
+	char *adr;
+	uint32_t s, hdr_size;
+
+	for (data_type = DATA_TYPE_IMAGETTE;
+	     data_type <=DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE;
+	     data_type++) {
+		s = cmp_ent_create(&ent, data_type, 0, 0);
+		TEST_ASSERT_NOT_EQUAL_INT(0, s);
+
+		adr = cmp_ent_get_data_buf(&ent);
+		TEST_ASSERT_NOT_NULL(adr);
+
+		hdr_size = cmp_ent_cal_hdr_size(data_type, 0);
+		TEST_ASSERT_EQUAL_INT(hdr_size, adr-(char *)&ent);
+	}
+
+	/* RAW mode test */
+	for (data_type = DATA_TYPE_IMAGETTE;
+	     data_type <=DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE;
+	     data_type++) {
+		s = cmp_ent_create(&ent, data_type, 1, 0);
+		TEST_ASSERT_NOT_EQUAL_INT(0, s);
+
+		adr = cmp_ent_get_data_buf(&ent);
+		TEST_ASSERT_NOT_NULL(adr);
+
+		hdr_size = cmp_ent_cal_hdr_size(data_type, 1);
+		TEST_ASSERT_EQUAL_INT(hdr_size, adr-(char *)&ent);
+	}
+
+	/* ent = NULL test */
+	adr = cmp_ent_get_data_buf(NULL);
+	TEST_ASSERT_NULL(adr);
+
+	/* compression data type not supported test */
+	s = cmp_ent_set_data_type(&ent, DATA_TYPE_UNKNOWN, 0);
+	TEST_ASSERT_FALSE(s);
+
+	adr = cmp_ent_get_data_buf(&ent);
+	TEST_ASSERT_NULL(adr);
+}
+
diff --git a/test/cmp_icu/meson.build b/test/cmp_icu/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..7c9b356ed371262c44ba3ef897861ee4c7d25cd2
--- /dev/null
+++ b/test/cmp_icu/meson.build
@@ -0,0 +1,40 @@
+test_case = files('test_cmp_icu.c')
+test_runner = test_runner_generator.process(test_case)
+
+test_cmp_icu = executable('test_cmp_icu',
+   test_case, test_runner,
+   include_directories : incdir,
+   link_with : cmp_lib,
+   dependencies : unity_dep,
+   build_by_default : false
+)
+
+test('cmp_icu Unit Tests', test_cmp_icu)
+
+
+test_case = files('test_cmp_decmp.c')
+test_runner = test_runner_generator.process(test_case)
+
+test_cmp_decmp = executable('test_cmp_decmp',
+   test_case, test_runner,
+   include_directories : incdir,
+   link_with : cmp_lib,
+   dependencies : unity_dep,
+   build_by_default : false
+)
+
+test('Compression Decompression Unit Tests', test_cmp_decmp)
+
+
+test_case = files('test_decmp.c')
+test_runner = test_runner_generator.process(test_case)
+
+test_decmp = executable('test_decmp',
+   test_case, test_runner,
+   include_directories : incdir,
+   link_with : cmp_lib,
+   dependencies : unity_dep,
+   build_by_default : false
+)
+
+test('Decompression Unit Tests', test_decmp)
diff --git a/test/cmp_icu/test_cmp_decmp.c b/test/cmp_icu/test_cmp_decmp.c
new file mode 100644
index 0000000000000000000000000000000000000000..9eb587e96c8a34379ac56e8bb5a452ef8a891fe4
--- /dev/null
+++ b/test/cmp_icu/test_cmp_decmp.c
@@ -0,0 +1,663 @@
+/**
+ * @file   test_cmp_decmp.c
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2022
+ *
+ * @copyright GPLv2
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * @brief random compression decompression test
+ * @detail We generate random data and compress them with random parameters.
+ *	After that we put the data in a compression entity. We decompress the
+ *	compression entity and compare the decompressed data with the original
+ *	data.
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <unity.h>
+
+#include <cmp_icu.h>
+#include <decmp.h>
+#include <cmp_data_types.h>
+
+#if defined __has_include
+#  if __has_include(<time.h>)
+#    include <time.h>
+#    include <unistd.h>
+#    define HAS_TIME_H 1
+#  endif
+#endif
+
+#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
+#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX)
+
+#define set_n_bits(n)  (n!=32?~(~0UL << (n)):0xFFFFFFFF)
+
+
+/**
+ * @brief  Seeds the pseudo-random number generator used by rand()
+ */
+
+void setUp(void)
+{
+	unsigned int seed;
+	static int n;
+
+#if HAS_TIME_H
+	seed = time(NULL) * getpid();
+#else
+	seed = 1;
+#endif
+
+	if (!n) {
+		n = 1;
+		srand(seed);
+		printf("seed: %u\n", seed);
+	}
+}
+
+
+/**
+ * @brief generate a uint32_t random number
+ *
+ * @return a "random" uint32_t value
+ * @see https://stackoverflow.com/a/33021408
+ */
+
+uint32_t rand32(void)
+{
+	int i;
+	uint32_t r = 0;
+
+	for (i = 0; i < 32; i += RAND_MAX_WIDTH) {
+		r <<= RAND_MAX_WIDTH;
+		r ^= (unsigned int) rand();
+	}
+	return r;
+}
+
+
+/**
+ * @brief generate a random number in a range
+ *
+ * @param min minimum value (inclusive)
+ * @param max maximum value (inclusive)
+ *
+ * @returns "random" numbers in the range [min, max]
+ *
+ * @see https://c-faq.com/lib/randrange.html
+ */
+
+uint32_t random_between(unsigned int min, unsigned int max)
+{
+	TEST_ASSERT(min < max);
+	if (max-min < RAND_MAX)
+		return min + rand() / (RAND_MAX / (max - min + 1ULL) + 1);
+	else
+		return min + rand32() / (UINT32_MAX / (max - min + 1ULL) + 1);
+}
+
+
+static void gen_ima_data(uint16_t *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i] = random_between(0, set_n_bits(max_used_bits.nc_imagette));
+	}
+}
+
+
+static void gen_offset_data(struct nc_offset *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].mean = random_between(0, set_n_bits(max_used_bits.nc_offset_mean));
+		data[i].variance = random_between(0, set_n_bits(max_used_bits.nc_offset_variance));
+	}
+}
+
+
+static void gen_background_data(struct nc_background *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].mean = random_between(0, set_n_bits(max_used_bits.nc_background_mean));
+		data[i].variance = random_between(0, set_n_bits(max_used_bits.nc_background_variance));
+		data[i].outlier_pixels = random_between(0, set_n_bits(max_used_bits.nc_background_outlier_pixels));
+	}
+}
+
+
+static void gen_smearing_data(struct smearing *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].mean = random_between(0, set_n_bits(max_used_bits.smearing_mean));
+		data[i].variance_mean = random_between(0, set_n_bits(max_used_bits.smearing_variance_mean));
+		data[i].outlier_pixels = random_between(0, set_n_bits(max_used_bits.smearing_outlier_pixels));
+	}
+}
+
+
+static void gen_s_fx_data(struct s_fx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+	}
+}
+
+
+static void gen_s_fx_efx_data(struct s_fx_efx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.s_efx));
+	}
+}
+
+
+static void gen_s_fx_ncob_data(struct s_fx_ncob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.s_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.s_ncob));
+	}
+}
+
+
+static void gen_s_fx_efx_ncob_ecob_data(struct s_fx_efx_ncob_ecob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.s_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.s_ncob));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.s_efx));
+		data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.s_ecob));
+		data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.s_ecob));
+	}
+}
+
+
+static void gen_f_fx_data(struct f_fx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+	}
+}
+
+
+static void gen_f_fx_efx_data(struct f_fx_efx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.f_efx));
+	}
+}
+
+
+static void gen_f_fx_ncob_data(struct f_fx_ncob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.f_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.f_ncob));
+	}
+}
+
+
+static void gen_f_fx_efx_ncob_ecob_data(struct f_fx_efx_ncob_ecob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.f_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.f_ncob));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.f_efx));
+		data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.f_ecob));
+		data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.f_ecob));
+	}
+}
+
+
+static void gen_l_fx_data(struct l_fx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+	}
+}
+
+
+static void gen_l_fx_efx_data(struct l_fx_efx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.l_efx));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+	}
+}
+
+
+static void gen_l_fx_ncob_data(struct l_fx_ncob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+		data[i].cob_x_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+		data[i].cob_y_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+	}
+}
+
+
+static void gen_l_fx_efx_ncob_ecob_data(struct l_fx_efx_ncob_ecob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.l_efx));
+		data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.l_ecob));
+		data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.l_ecob));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+		data[i].cob_x_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+		data[i].cob_y_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+	}
+}
+
+
+/**
+ * @brief generate random test data
+ *
+ * @param samples	number of random test samples
+ * @param data_type	compression data type of the test data
+ *
+ * @returns a pointer to the generated random test data
+ */
+
+void *generate_random_test_data(uint32_t samples, enum cmp_data_type data_type)
+{
+	size_t data_size = cmp_cal_size_of_data(samples, data_type);
+	void *data = malloc(data_size);
+	void *data_cpy = data;
+	uint8_t *p = data;
+
+	TEST_ASSERT_NOT_EQUAL_INT(data_size, 0);
+	TEST_ASSERT(data_size < (CMP_ENTITY_MAX_SIZE - NON_IMAGETTE_HEADER_SIZE));
+	TEST_ASSERT_NOT_NULL(data);
+
+	if (!rdcu_supported_data_type_is_used(data_type)) {
+		int i;
+		TEST_ASSERT(data_size > MULTI_ENTRY_HDR_SIZE);
+		for (i = 0; i < MULTI_ENTRY_HDR_SIZE; ++i) {
+			*p++ = random_between(0, UINT8_MAX);
+		}
+		data = p;
+	}
+
+	switch (data_type) {
+	case DATA_TYPE_IMAGETTE:
+	case DATA_TYPE_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_SAT_IMAGETTE:
+	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
+	case DATA_TYPE_F_CAM_IMAGETTE:
+	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
+		gen_ima_data(data, samples);
+		break;
+	case DATA_TYPE_OFFSET:
+		gen_offset_data(data, samples);
+		break;
+	case DATA_TYPE_BACKGROUND:
+		gen_background_data(data, samples);
+		break;
+	case DATA_TYPE_SMEARING:
+		gen_smearing_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX:
+		gen_s_fx_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX_EFX:
+		gen_s_fx_efx_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX_NCOB:
+		gen_s_fx_ncob_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+		gen_s_fx_efx_ncob_ecob_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX:
+		gen_l_fx_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX_EFX:
+		gen_l_fx_efx_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX_NCOB:
+		gen_l_fx_ncob_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+		gen_l_fx_efx_ncob_ecob_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX:
+		gen_f_fx_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX_EFX:
+		gen_f_fx_efx_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX_NCOB:
+		gen_f_fx_ncob_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		gen_f_fx_efx_ncob_ecob_data(data, samples);
+		break;
+	case DATA_TYPE_F_CAM_OFFSET: /* TODO: implement this */
+	case DATA_TYPE_F_CAM_BACKGROUND: /* TODO: implement this */
+	default:
+		TEST_FAIL();
+	}
+
+	return data_cpy;
+}
+
+
+/**
+ * @brief generate random compression configuration
+ *
+ * @param cfg	pointer to a compression configuration
+ *
+ */
+
+void generate_random_cmp_par(struct cmp_cfg *cfg)
+{
+	cfg->golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+	cfg->ap1_golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+	cfg->ap2_golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+
+	cfg->cmp_par_exp_flags = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_fx = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_ncob = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_efx = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_ecob = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_fx_cob_variance = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_mean = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_variance = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_pixels_error = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+
+
+	cfg->spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->golomb_par));
+	cfg->ap1_spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap1_golomb_par));
+	cfg->ap2_spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap2_golomb_par));
+
+	cfg->spill_exp_flags = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_exp_flags));
+	cfg->spill_fx = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx));
+	cfg->spill_ncob = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_ncob));
+	cfg->spill_efx = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_efx));
+	cfg->spill_ecob = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_ecob));
+	cfg->spill_fx_cob_variance = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx_cob_variance));
+	cfg->spill_mean = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_mean));
+	cfg->spill_variance = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_variance));
+	cfg->spill_pixels_error = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_pixels_error));
+#if 0
+	if (cfg->cmp_mode == CMP_MODE_STUFF) {
+		/* cfg->golomb_par = random_between(16, MAX_STUFF_CMP_PAR); */
+		cfg->golomb_par = 16;
+		cfg->ap1_golomb_par = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->ap2_golomb_par = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_exp_flags = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_fx = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_ncob = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_efx = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_ecob = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_fx_cob_variance = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_mean = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_variance = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_pixels_error = random_between(0, MAX_STUFF_CMP_PAR);
+		return;
+	}
+#endif
+}
+
+
+/**
+ * @brief compress the given configuration and decompress it afterwards; finally
+ *	compare the results
+ *
+ * @param cfg	pointer to a compression configuration
+ */
+
+void compression_decompression(struct cmp_cfg *cfg)
+{
+	int cmp_size_bits, s, error;
+	int data_size, cmp_data_size;
+	struct cmp_entity *ent;
+	void *decompressed_data;
+	static void *model_of_data;
+	void *updated_model = NULL;
+
+	TEST_ASSERT_NOT_NULL(cfg);
+
+	TEST_ASSERT_NULL(cfg->icu_output_buf);
+
+	data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);
+
+	/* create a compression entity */
+	cmp_data_size = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type);
+	cmp_data_size &= ~0x3; /* the size of the compressed data should be a multiple of 4 */
+	TEST_ASSERT_NOT_EQUAL_INT(0, cmp_data_size);
+
+	s = cmp_ent_create(NULL, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size);
+	TEST_ASSERT_NOT_EQUAL_INT(0, s);
+	ent = malloc(s); TEST_ASSERT_TRUE(ent);
+	s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size);
+	TEST_ASSERT_NOT_EQUAL_INT(0, s);
+
+	/* we put the coompressed data direct into the compression entity */
+	cfg->icu_output_buf = cmp_ent_get_data_buf(ent);
+	TEST_ASSERT_NOT_NULL(cfg->icu_output_buf);
+
+	/* now compress the data */
+	cmp_size_bits = icu_compress_data(cfg);
+	TEST_ASSERT(cmp_size_bits > 0);
+
+	/* put the compression parameters in the entity header */
+	error = cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits);
+	TEST_ASSERT_FALSE(error);
+
+	/* allocate the buffers for decompression */
+	TEST_ASSERT_NOT_EQUAL_INT(0, data_size);
+	s = decompress_cmp_entiy(ent, model_of_data, NULL, NULL);
+	decompressed_data = malloc(s); TEST_ASSERT_NOT_NULL(decompressed_data);
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		updated_model = malloc(data_size);
+		TEST_ASSERT_NOT_NULL(updated_model);
+	}
+
+	/* now we try to decompress the data */
+	s = decompress_cmp_entiy(ent, model_of_data, updated_model, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(data_size, s);
+	TEST_ASSERT_FALSE(memcmp(decompressed_data, cfg->input_buf, data_size));
+
+	if (model_mode_is_used(cfg->cmp_mode)) {
+		TEST_ASSERT_NOT_NULL(updated_model);
+		TEST_ASSERT_NOT_NULL(model_of_data);
+		TEST_ASSERT_FALSE(memcmp(updated_model, cfg->icu_new_model_buf, data_size));
+		memcpy(model_of_data, updated_model, data_size);
+	} else { /* non-model mode */
+		/* reset model */
+		free(model_of_data);
+		model_of_data = malloc(data_size);
+		memcpy(model_of_data, decompressed_data, data_size);
+	}
+
+	cfg->icu_output_buf = NULL;
+	free(ent);
+	free(decompressed_data);
+	free(updated_model);
+}
+
+
+#define CMP_BUFFER_FAKTOR 3 /* compression data buffer size / data to compress buffer size */
+
+/**
+ * @brief random compression decompression test
+ * @detail We generate random data and compress them with random parameters.
+ *	After that we put the data in a compression entity. We decompress the
+ *	compression entity and compare the decompressed data with the original
+ *	data.
+ * @test icu_compress_data
+ * @test decompress_cmp_entiy
+ */
+
+void test_random_compression_decompression(void)
+{
+	enum cmp_data_type data_type;
+	enum cmp_mode cmp_mode;
+	struct cmp_cfg cfg;
+	int cmp_buffer_size;
+
+	/* TODO: extend test for DATA_TYPE_F_CAM_BACKGROUND, DATA_TYPE_F_CAM_OFFSET  */
+	for (data_type = 1; data_type <= DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE; data_type++) {
+		/* printf("%s\n", data_type2string(data_type)); */
+		/* generate random data*/
+		uint32_t samples = random_between(1, 430179/CMP_BUFFER_FAKTOR);
+		uint32_t model_value = random_between(0, MAX_MODEL_VALUE);
+		void *data_to_compress1 = generate_random_test_data(samples, data_type);
+		void *data_to_compress2 = generate_random_test_data(samples, data_type);
+		void *updated_model = calloc(1, cmp_cal_size_of_data(samples, data_type));
+		/* for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_STUFF; cmp_mode++) { */
+		for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_DIFF_MULTI; cmp_mode++) {
+			/* printf("cmp_mode: %i\n", cmp_mode); */
+			cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value,
+						 CMP_LOSSLESS);
+			TEST_ASSERT_NOT_EQUAL_INT(cfg.data_type, DATA_TYPE_UNKNOWN);
+
+			generate_random_cmp_par(&cfg);
+
+			if (!model_mode_is_used(cmp_mode))
+				cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data_to_compress1,
+					samples, NULL, NULL, NULL, samples*CMP_BUFFER_FAKTOR);
+			else
+				cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data_to_compress2,
+					samples, data_to_compress1, updated_model, NULL, samples*CMP_BUFFER_FAKTOR);
+
+			TEST_ASSERT_EQUAL_INT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*samples, data_type));
+
+			compression_decompression(&cfg);
+		}
+		free(data_to_compress1);
+		free(data_to_compress2);
+		free(updated_model);
+	}
+}
+
+#define N_SAMPLES 5
+
+void test_random_compression_decompression2(void)
+{
+	struct cmp_cfg cfg;
+	struct cmp_info info = {0};
+	uint32_t cmp_buffer_size;
+	int s, i, cmp_size_bits;
+	void *compressed_data;
+	uint16_t *decompressed_data;
+	uint16_t data[N_SAMPLES] = {0, UINT16_MAX, INT16_MAX, 42, 23};
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 8, CMP_LOSSLESS);
+	TEST_ASSERT_NOT_EQUAL_INT(cfg.data_type, DATA_TYPE_UNKNOWN);
+
+	cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data, N_SAMPLES, NULL, NULL,
+					      NULL, N_SAMPLES*CMP_BUFFER_FAKTOR);
+	compressed_data = malloc(cmp_buffer_size);
+	cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data, N_SAMPLES, NULL, NULL,
+					      compressed_data, N_SAMPLES*CMP_BUFFER_FAKTOR);
+	TEST_ASSERT_EQUAL_INT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*N_SAMPLES, DATA_TYPE_IMAGETTE));
+
+	cmp_size_bits = icu_compress_data(&cfg);
+	TEST_ASSERT(cmp_size_bits > 0);
+	info.cmp_size = cmp_size_bits;
+	info.cmp_mode_used = (uint8_t)cfg.cmp_mode;
+	info.model_value_used = (uint8_t)cfg.model_value;
+	info.round_used = (uint8_t)cfg.round;
+	info.spill_used = cfg.spill;
+	info.golomb_par_used = cfg.golomb_par;
+	info.samples_used = cfg.samples;
+	info.rdcu_new_model_adr_used = cfg.rdcu_new_model_adr;
+	info.rdcu_cmp_adr_used = cfg.rdcu_buffer_adr;
+
+	s = decompress_rdcu_data(compressed_data, &info, NULL, NULL, NULL);
+	TEST_ASSERT(s > 0);
+	decompressed_data = malloc(s);
+	s = decompress_rdcu_data(compressed_data, &info, NULL, NULL, decompressed_data);
+	TEST_ASSERT(s > 0);
+
+	for (i = 0; i < N_SAMPLES; i++) {
+		TEST_ASSERT_EQUAL_HEX16(data[i], decompressed_data[i]);
+	}
+
+
+	free(compressed_data);
+	free(decompressed_data);
+}
diff --git a/test/cmp_icu/test_cmp_icu.c b/test/cmp_icu/test_cmp_icu.c
new file mode 100644
index 0000000000000000000000000000000000000000..65ab54581940e79ad902c1c272bd76c51604ab30
--- /dev/null
+++ b/test/cmp_icu/test_cmp_icu.c
@@ -0,0 +1,4376 @@
+#include <stdlib.h>
+
+#if defined __has_include
+#  if __has_include(<time.h>)
+#    include <time.h>
+#    include <unistd.h>
+#    define HAS_TIME_H 1
+#  endif
+#endif
+
+#include "unity.h"
+#include "cmp_icu.h"
+#include "../lib/cmp_icu.c" /* this is a hack to test static functions */
+
+/* TODO: test compression with samples = 0 and buffer_length = 0; */
+
+/**
+ * @brief  Seeds the pseudo-random number generator used by rand()
+ */
+
+void setUp(void)
+{
+	unsigned int seed;
+	static int n;
+
+#if HAS_TIME_H
+	seed = time(NULL) * getpid();
+#else
+	seed = 1;
+#endif
+
+	if (!n) {
+		n = 1;
+		srand(seed);
+		printf("seed: %u\n", seed);
+	}
+}
+
+
+/**
+ * @brief generate a random number
+ *
+ * @param min minimum value (inclusive)
+ * @param max maximum value (inclusive)
+ *
+ * @returns "random" numbers in the range [M, N]
+ *
+ * @see https://c-faq.com/lib/randrange.html
+ */
+
+int random_between(unsigned int min, unsigned int max)
+{
+	TEST_ASSERT(min < max);
+	TEST_ASSERT(max-min <= RAND_MAX);
+	return min + rand() / (RAND_MAX / (max - min + 1) + 1);
+}
+
+
+/**
+ * @test cmp_cfg_icu_create
+ */
+
+void test_cmp_cfg_icu_create(void)
+{
+	struct cmp_cfg cfg;
+	enum cmp_data_type data_type;
+	enum cmp_mode cmp_mode;
+	uint32_t model_value, lossy_par;
+	/* TODO: change that when DATA_TYPE_BACKGROUND and
+	 * DATA_TYPE_F_CAM_BACKGROUND are implemented */
+	const enum cmp_data_type biggest_data_type = DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE;
+
+	/* wrong data type tests */
+	data_type = DATA_TYPE_UNKNOWN; /* not valid data type */
+	cmp_mode = CMP_MODE_RAW;
+	model_value = 0;
+	lossy_par = CMP_LOSSLESS;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+	memset(&cfg, 0, sizeof(cfg));
+
+	data_type = biggest_data_type + 1; /* not valid data type */
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+	memset(&cfg, 0, sizeof(cfg));
+
+	data_type = biggest_data_type;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(biggest_data_type, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(CMP_MODE_RAW, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(0, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(0, cfg.round);
+	memset(&cfg, 0, sizeof(cfg));
+
+	/* this should work */
+	data_type = DATA_TYPE_IMAGETTE;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(CMP_MODE_RAW, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(0, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(0, cfg.round);
+	memset(&cfg, 0, sizeof(cfg));
+
+	/* wrong compression mode tests */
+	cmp_mode = CMP_MODE_STUFF + 1;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+	memset(&cfg, 0, sizeof(cfg));
+
+	cmp_mode = -1;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+	memset(&cfg, 0, sizeof(cfg));
+
+	/* this should work */
+	cmp_mode = CMP_MODE_STUFF;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(CMP_MODE_STUFF, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(0, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(0, cfg.round);
+	memset(&cfg, 0, sizeof(cfg));
+
+	/* wrong model_value tests */
+	cmp_mode = CMP_MODE_MODEL_MULTI; /* model value checks only active on model mode */
+	model_value = MAX_MODEL_VALUE + 1;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+
+	model_value = -1U;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+
+	/* this should work */
+	model_value = MAX_MODEL_VALUE;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(CMP_MODE_MODEL_MULTI, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(16, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(0, cfg.round);
+
+	/* no checks for model mode -> no model cmp_mode */
+	cmp_mode = CMP_MODE_STUFF;
+	model_value = MAX_MODEL_VALUE + 1;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(CMP_MODE_STUFF, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(MAX_MODEL_VALUE + 1, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(0, cfg.round);
+	model_value = MAX_MODEL_VALUE;
+
+	/* wrong lossy_par tests */
+	lossy_par = MAX_ICU_ROUND + 1;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+
+	lossy_par = -1U;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type);
+
+	/* this should work */
+	lossy_par = MAX_ICU_ROUND;
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(CMP_MODE_STUFF, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(16, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(3, cfg.round);
+
+	/* random test */
+	data_type = random_between(DATA_TYPE_IMAGETTE, biggest_data_type);
+	cmp_mode = random_between(CMP_MODE_RAW, CMP_MODE_STUFF);
+	model_value = random_between(0, MAX_MODEL_VALUE);
+	lossy_par = random_between(CMP_LOSSLESS, MAX_ICU_ROUND);
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par);
+	TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type);
+	TEST_ASSERT_EQUAL_INT(cmp_mode, cfg.cmp_mode);
+	TEST_ASSERT_EQUAL_INT(model_value, cfg.model_value);
+	TEST_ASSERT_EQUAL_INT(lossy_par, cfg.round);
+}
+
+
+/**
+ * @test cmp_cfg_icu_buffers
+ */
+
+void test_cmp_cfg_icu_buffers(void)
+{
+	struct cmp_cfg cfg;
+	void *data_to_compress;
+	uint32_t data_samples;
+	void *model_of_data;
+	void *updated_model;
+	uint32_t *compressed_data;
+	uint32_t compressed_data_len_samples;
+	size_t s;
+	uint16_t ima_data[4] = {42, 23, 0, 0xFFFF};
+	uint16_t ima_model[4] = {0xC, 0xA, 0xFF, 0xE};
+	uint16_t ima_up_model[4] = {0};
+	uint32_t cmp_data[2] = {0};
+
+	/* error case: unknown  data_type */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_UNKNOWN, CMP_MODE_DIFF_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	data_samples = 4;
+	model_of_data = NULL;
+	updated_model = NULL;
+	compressed_data = cmp_data;
+	compressed_data_len_samples = 4;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* error case: no data test */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_DIFF_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = NULL; /* no data set */
+	data_samples = 4;
+	model_of_data = NULL;
+	updated_model = NULL;
+	compressed_data = cmp_data;
+	compressed_data_len_samples = 4;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* now its should work */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_DIFF_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(8, s);
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(NULL, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.samples);
+	TEST_ASSERT_EQUAL(NULL, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length);
+
+	/* error case: model mode and no model */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	model_of_data = NULL;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* now its should work */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	model_of_data = ima_model;
+	updated_model = ima_model;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(8, s);
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.samples);
+	TEST_ASSERT_EQUAL(ima_model, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length);
+
+	/* error case: data == model */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	model_of_data = ima_data;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* error case: data == compressed_data */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	model_of_data = ima_model;
+	compressed_data = (void *)ima_data;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* error case: data == updated_model */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	model_of_data = ima_model;
+	updated_model = ima_data;
+	compressed_data = (void *)ima_data;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* error case: model == compressed_data */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	model_of_data = ima_model;
+	compressed_data = (void *)ima_model;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* error case: updated_model == compressed_data */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	model_of_data = ima_model;
+	updated_model = ima_up_model;
+	compressed_data = (void *)ima_up_model;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* warning case: samples = 0 */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_to_compress = ima_data;
+	data_samples = 0;
+	model_of_data = ima_model;
+	updated_model = ima_up_model;
+	compressed_data = cmp_data;
+	compressed_data_len_samples = 4;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(8, s);
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(0, cfg.samples);
+	TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length);
+	memset(&cfg, 0, sizeof(cfg));
+
+	/* error case: compressed_data_len_samples = 0 */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_samples = 4;
+	compressed_data_len_samples = 0;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* this should now work */
+	/* if data_samples = 0 -> compressed_data_len_samples = 0 is allowed */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_samples = 0;
+	compressed_data_len_samples = 0;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s); /* not an error, it is the size of the compressed data */
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(0, cfg.samples);
+	TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(0, cfg.buffer_length);
+
+	/* this should now work */
+	/* if compressed_data = NULL -> compressed_data_len_samples = 0 is allowed */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	data_samples = 4;
+	compressed_data = NULL;
+	compressed_data_len_samples = 0;
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s); /* not an error, it is the size of the compressed data */
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.samples);
+	TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(NULL, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(0, cfg.buffer_length);
+
+	/* error case: RAW mode compressed_data smaller than data_samples */
+	compressed_data = cmp_data;
+	compressed_data_len_samples = 3;
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+
+	/* this should now work */
+	compressed_data = NULL;
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(6, s);
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.samples);
+	TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(NULL, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(3, cfg.buffer_length);
+
+	/* this should also now work */
+	compressed_data = cmp_data;
+	compressed_data_len_samples = 4;
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(8, s);
+	TEST_ASSERT_EQUAL(ima_data, cfg.input_buf);
+	TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.samples);
+	TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf);
+	TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf);
+	TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length);
+
+	/* error case: cfg = NULL */
+	s = cmp_cfg_icu_buffers(NULL, data_to_compress, data_samples,
+				model_of_data, updated_model, compressed_data,
+				compressed_data_len_samples);
+	TEST_ASSERT_EQUAL_size_t(0, s);
+}
+
+
+/**
+ * @test cmp_cfg_icu_imagette
+ */
+
+void test_cmp_cfg_icu_imagette(void)
+{
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par;
+	uint32_t spillover_par;
+	enum cmp_data_type data_type;
+
+	int error;
+
+	/* lowest values 1d/model mode */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 0, CMP_LOSSLESS);
+	cmp_par = MIN_IMA_GOLOMB_PAR;
+	spillover_par = MIN_IMA_SPILL;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cfg.golomb_par, 1);
+	TEST_ASSERT_EQUAL_INT(cfg.spill, 2);
+
+	/* highest values 1d/model mode */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_CAM_IMAGETTE, CMP_MODE_DIFF_MULTI, 16, CMP_LOSSLESS);
+	cmp_par = MAX_IMA_GOLOMB_PAR;
+	spillover_par = cmp_ima_max_spill(cmp_par);
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cfg.golomb_par, MAX_IMA_GOLOMB_PAR);
+	TEST_ASSERT_EQUAL_INT(cfg.spill, cmp_ima_max_spill(MAX_IMA_GOLOMB_PAR));
+
+	/* wrong data type  test */
+	for (data_type = 0; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) {
+		cfg = cmp_cfg_icu_create(data_type, CMP_MODE_DIFF_MULTI, 16, CMP_LOSSLESS);
+		error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+		if (data_type == DATA_TYPE_IMAGETTE ||
+		    data_type == DATA_TYPE_SAT_IMAGETTE ||
+		    data_type == DATA_TYPE_F_CAM_IMAGETTE) {
+			TEST_ASSERT_FALSE(error);
+			TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type);
+			TEST_ASSERT_EQUAL_INT(cfg.golomb_par, MAX_IMA_GOLOMB_PAR);
+			TEST_ASSERT_EQUAL_INT(cfg.spill, cmp_ima_max_spill(MAX_IMA_GOLOMB_PAR));
+		} else {
+			TEST_ASSERT_TRUE(error);
+		}
+	}
+
+	/* model/1d MODE tests */
+
+	/* cmp_par to big */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_MULTI, 16, CMP_LOSSLESS);
+	cmp_par = MAX_IMA_GOLOMB_PAR + 1;
+	spillover_par = MIN_IMA_SPILL;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+	/* ignore in RAW MODE */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+
+	/* cmp_par to small */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_MULTI, 16, CMP_LOSSLESS);
+	cmp_par = MIN_IMA_GOLOMB_PAR - 1;
+	spillover_par = MIN_IMA_SPILL;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+	/* ignore in RAW MODE */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+
+	/* spillover_par to big */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_MULTI, 16, CMP_LOSSLESS);
+	cmp_par = MIN_IMA_GOLOMB_PAR;
+	spillover_par = cmp_ima_max_spill(cmp_par)+1;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+	/* ignore in RAW MODE */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+
+	/* spillover_par to small */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	cmp_par = MAX_IMA_GOLOMB_PAR;
+	spillover_par = MIN_IMA_SPILL -1 ;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+	/* ignore in RAW MODE */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS);
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+
+	/* CMP_MODE_STUFF tests */
+	spillover_par = ~0; /* is ignored */
+
+	/* highest values STUFF MODE */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_STUFF, ~0, CMP_LOSSLESS);
+	cmp_par = MAX_STUFF_CMP_PAR;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cfg.golomb_par, 32);
+
+	/* lowest values STUFF MODE */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_STUFF, ~0, CMP_LOSSLESS);
+	cmp_par = 0;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cfg.golomb_par, 0);
+
+	/* cmp_par to big */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_SAT_IMAGETTE, CMP_MODE_STUFF, ~0, CMP_LOSSLESS);
+	cmp_par = MAX_STUFF_CMP_PAR+1;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+
+	/* cfg = NULL test*/
+	error = cmp_cfg_icu_imagette(NULL, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+
+	/* invalid compression mode  test*/
+	cfg = cmp_cfg_icu_create(DATA_TYPE_SAT_IMAGETTE, CMP_MODE_STUFF+1, ~0, CMP_LOSSLESS);
+	cmp_par = MAX_STUFF_CMP_PAR+1;
+	error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par);
+	TEST_ASSERT_TRUE(error);
+}
+
+
+/**
+ * @test cmp_cfg_fx_cob
+ */
+
+void test_cmp_cfg_fx_cob(void)
+{
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = 2;
+	uint32_t spillover_exp_flags = 2;
+	uint32_t cmp_par_fx = 2;
+	uint32_t spillover_fx = 2;
+	uint32_t cmp_par_ncob = 2;
+	uint32_t spillover_ncob = 2;
+	uint32_t cmp_par_efx = 2;
+	uint32_t spillover_efx = 2;
+	uint32_t cmp_par_ecob = 2;
+	uint32_t spillover_ecob = 2;
+	uint32_t cmp_par_fx_cob_variance = 2;
+	uint32_t spillover_fx_cob_variance = 2;
+	int error;
+	enum cmp_data_type data_type;
+
+
+	/* wrong data type test */
+	for (data_type = 0; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) {
+		cfg = cmp_cfg_icu_create(data_type, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+		error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+				       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+				       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+				       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+		if (data_type == DATA_TYPE_S_FX ||
+		    data_type == DATA_TYPE_S_FX_EFX ||
+		    data_type == DATA_TYPE_S_FX_NCOB ||
+		    data_type == DATA_TYPE_S_FX_EFX_NCOB_ECOB ||
+		    data_type == DATA_TYPE_L_FX ||
+		    data_type == DATA_TYPE_L_FX_EFX ||
+		    data_type == DATA_TYPE_L_FX_NCOB ||
+		    data_type == DATA_TYPE_L_FX_EFX_NCOB_ECOB ||
+		    data_type == DATA_TYPE_F_FX ||
+		    data_type == DATA_TYPE_F_FX_EFX ||
+		    data_type == DATA_TYPE_F_FX_NCOB ||
+		    data_type == DATA_TYPE_F_FX_EFX_NCOB_ECOB) {
+			TEST_ASSERT_FALSE(error);
+			TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_fx);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_fx);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_exp_flags);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_exp_flags);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_efx);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_efx);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_ncob);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_ncob);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_ecob);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_ecob);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_fx_cob_variance);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_fx_cob_variance);
+		} else {
+			TEST_ASSERT_TRUE(error);
+		}
+	}
+
+	/* cfg == NULL test */
+	error = cmp_cfg_fx_cob(NULL, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+	/* test DATA_TYPE_S_FX */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = ~0; /* invalid parameter */
+	spillover_ncob = ~0; /* invalid parameter */
+	cmp_par_efx = ~0; /* invalid parameter */
+	spillover_efx = ~0; /* invalid parameter */
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+
+	/* invalid spillover_exp_flags parameter */
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags)+1;
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+	/* invalid cmp_par_fx parameter */
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR - 1;
+	spillover_fx = MIN_ICU_SPILL;
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* test DATA_TYPE_S_FX_EFX */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX, CMP_MODE_MODEL_ZERO, 0, 1);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = ~0; /* invalid parameter */
+	spillover_ncob = ~0; /* invalid parameter */
+	cmp_par_efx = 23;
+	spillover_efx = 42;
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx);
+	TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx);
+
+	/* invalid spillover_efx parameter */
+	spillover_efx = 0;
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* test DATA_TYPE_S_FX_NCOB */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_NCOB, CMP_MODE_MODEL_ZERO, 0, 1);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = 19;
+	spillover_ncob = 5;
+	cmp_par_efx = ~0; /* invalid parameter */
+	spillover_efx = ~0; /* invalid parameter */
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob);
+	TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob);
+
+	/* invalid cmp_par_ncob parameter */
+	cmp_par_ncob = 0;
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* test DATA_TYPE_S_FX_EFX_NCOB_ECOB */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = 19;
+	spillover_ncob = 5;
+	cmp_par_efx = 23;
+	spillover_efx = 42;
+	cmp_par_ecob = MAX_ICU_GOLOMB_PAR;
+	spillover_ecob = MIN_ICU_SPILL;
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob);
+	TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob);
+	TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx);
+	TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ecob, cfg.cmp_par_ecob);
+	TEST_ASSERT_EQUAL_INT(spillover_ecob, cfg.spill_ecob);
+
+	/* invalid cmp_par_ecob parameter */
+	cmp_par_ecob = -1U;
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* DATA_TYPE_L_FX */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = ~0; /* invalid parameter */
+	spillover_ncob = ~0; /* invalid parameter */
+	cmp_par_efx = ~0; /* invalid parameter */
+	spillover_efx = ~0; /* invalid parameter */
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = 30;
+	spillover_fx_cob_variance = 8;
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance);
+	TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance);
+
+	/* invalid spillover_fx_cob_variance parameter */
+	spillover_fx_cob_variance = 1;
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* DATA_TYPE_L_FX_EFX */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = ~0; /* invalid parameter */
+	spillover_ncob = ~0; /* invalid parameter */
+	cmp_par_efx = 23;
+	spillover_efx = 42;
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = 30;
+	spillover_fx_cob_variance = 8;
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx);
+	TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance);
+	TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance);
+
+
+	/* DATA_TYPE_L_FX_NCOB */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_NCOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = 19;
+	spillover_ncob = 5;
+	cmp_par_efx = ~0; /* invalid parameter */
+	spillover_efx = ~0; /* invalid parameter */
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = 30;
+	spillover_fx_cob_variance = 8;
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob);
+	TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance);
+	TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance);
+
+
+	/* DATA_TYPE_L_FX_EFX_NCOB_ECOB */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = 19;
+	spillover_ncob = 5;
+	cmp_par_efx = 23;
+	spillover_efx = 42;
+	cmp_par_ecob = MAX_ICU_GOLOMB_PAR;
+	spillover_ecob = MIN_ICU_SPILL;
+	cmp_par_fx_cob_variance = 30;
+	spillover_fx_cob_variance = 8;
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags);
+	TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags);
+	TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx);
+	TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob);
+	TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ecob, cfg.cmp_par_ecob);
+	TEST_ASSERT_EQUAL_INT(spillover_ecob, cfg.spill_ecob);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance);
+	TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance);
+
+
+	/* DATA_TYPE_F_FX */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = ~0; /* invalid parameter */
+	spillover_exp_flags = ~0; /* invalid parameter */
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = ~0; /* invalid parameter */
+	spillover_ncob = ~0; /* invalid parameter */
+	cmp_par_efx = ~0; /* invalid parameter */
+	spillover_efx = ~0; /* invalid parameter */
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+
+
+	/* DATA_TYPE_F_FX_EFX */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = ~0; /* invalid parameter */
+	spillover_exp_flags = ~0; /* invalid parameter */
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = ~0; /* invalid parameter */
+	spillover_ncob = ~0; /* invalid parameter */
+	cmp_par_efx = 23;
+	spillover_efx = 42;
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx);
+	TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx);
+
+
+	/* DATA_TYPE_F_FX_NCOB */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_NCOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = ~0; /* invalid parameter */
+	spillover_exp_flags = ~0; /* invalid parameter */
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = MIN_ICU_GOLOMB_PAR;
+	spillover_ncob = cmp_icu_max_spill(cmp_par_ncob);
+	cmp_par_efx = ~0; /* invalid parameter */
+	spillover_efx = ~0; /* invalid parameter */
+	cmp_par_ecob = ~0; /* invalid parameter */
+	spillover_ecob = ~0; /* invalid parameter */
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob);
+	TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob);
+
+
+	/* DATA_TYPE_F_FX_EFX_NCOB_ECOB */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_exp_flags = ~0; /* invalid parameter */
+	spillover_exp_flags = ~0; /* invalid parameter */
+	cmp_par_fx = MIN_ICU_GOLOMB_PAR;
+	spillover_fx = MIN_ICU_SPILL;
+	cmp_par_ncob = MIN_ICU_GOLOMB_PAR;
+	spillover_ncob = cmp_icu_max_spill(cmp_par_ncob);
+	cmp_par_efx = 23;
+	spillover_efx = 42;
+	cmp_par_ecob = MAX_ICU_GOLOMB_PAR;
+	spillover_ecob = MIN_ICU_SPILL;
+	cmp_par_fx_cob_variance = ~0; /* invalid parameter */
+	spillover_fx_cob_variance = ~0; /* invalid parameter */
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx);
+	TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob);
+	TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob);
+	TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx);
+	TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx);
+	TEST_ASSERT_EQUAL_INT(cmp_par_ecob, cfg.cmp_par_ecob);
+	TEST_ASSERT_EQUAL_INT(spillover_ecob, cfg.spill_ecob);
+}
+
+/**
+ * @test cmp_cfg_aux
+ */
+
+void test_cmp_cfg_aux(void)
+{	struct cmp_cfg cfg;
+	uint32_t cmp_par_mean = 2;
+	uint32_t spillover_mean = 2;
+	uint32_t cmp_par_variance = 2;
+	uint32_t spillover_variance = 2;
+	uint32_t cmp_par_pixels_error = 2;
+	uint32_t spillover_pixels_error = 2;
+	int error;
+	enum cmp_data_type data_type;
+
+	/* wrong data type test */
+	for (data_type = 0; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) {
+		cfg = cmp_cfg_icu_create(data_type, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS);
+		error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+				    cmp_par_variance, spillover_variance,
+				    cmp_par_pixels_error, spillover_pixels_error);
+		if (data_type == DATA_TYPE_OFFSET ||
+		    data_type == DATA_TYPE_BACKGROUND ||
+		    data_type == DATA_TYPE_SMEARING
+		    /* data_type == DATA_TYPE_F_CAM_OFFSET || */
+		    /* data_type == DATA_TYPE_F_CAM_BACKGROUND */
+		    ) {
+			TEST_ASSERT_FALSE(error);
+			TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_mean);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_mean);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_variance);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_variance);
+			TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_pixels_error);
+			TEST_ASSERT_EQUAL_INT(2, cfg.spill_pixels_error);
+		} else {
+			TEST_ASSERT_TRUE(error);
+		}
+	}
+
+	/* cfg == NULL test */
+	error = cmp_cfg_aux(NULL, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* DATA_TYPE_OFFSET */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_OFFSET, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_mean = MIN_ICU_GOLOMB_PAR;
+	spillover_mean = cmp_icu_max_spill(MIN_ICU_GOLOMB_PAR);
+	cmp_par_variance = MIN_ICU_GOLOMB_PAR;
+	spillover_variance = MIN_ICU_SPILL;
+	cmp_par_pixels_error = ~0;
+	spillover_pixels_error = ~0;
+
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_mean);
+	TEST_ASSERT_EQUAL_INT(cmp_icu_max_spill(MIN_ICU_GOLOMB_PAR), cfg.spill_mean);
+	TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_variance);
+	TEST_ASSERT_EQUAL_INT(2, cfg.spill_variance);
+
+	/* This should fail */
+	cmp_par_mean = MIN_ICU_GOLOMB_PAR-1;
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* DATA_TYPE_BACKGROUND */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_BACKGROUND, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_mean = MAX_ICU_GOLOMB_PAR;
+	spillover_mean = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	cmp_par_variance = MIN_ICU_GOLOMB_PAR;
+	spillover_variance = MIN_ICU_SPILL;
+	cmp_par_pixels_error = 42;
+	spillover_pixels_error = 23;
+
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(MAX_ICU_GOLOMB_PAR, cfg.cmp_par_mean);
+	TEST_ASSERT_EQUAL_INT(cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR), cfg.spill_mean);
+	TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_variance);
+	TEST_ASSERT_EQUAL_INT(MIN_ICU_SPILL, cfg.spill_variance);
+	TEST_ASSERT_EQUAL_INT(42, cfg.cmp_par_pixels_error);
+	TEST_ASSERT_EQUAL_INT(23, cfg.spill_pixels_error);
+
+	/* This should fail */
+	cmp_par_variance = MIN_ICU_GOLOMB_PAR-1;
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_TRUE(error);
+
+
+	/* DATA_TYPE_SMEARING */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_SMEARING, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	cmp_par_mean = MAX_ICU_GOLOMB_PAR;
+	spillover_mean = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	cmp_par_variance = MIN_ICU_GOLOMB_PAR;
+	spillover_variance = MIN_ICU_SPILL;
+	cmp_par_pixels_error = 42;
+	spillover_pixels_error = 23;
+
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL_INT(MAX_ICU_GOLOMB_PAR, cfg.cmp_par_mean);
+	TEST_ASSERT_EQUAL_INT(cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR), cfg.spill_mean);
+	TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_variance);
+	TEST_ASSERT_EQUAL_INT(MIN_ICU_SPILL, cfg.spill_variance);
+	TEST_ASSERT_EQUAL_INT(42, cfg.cmp_par_pixels_error);
+	TEST_ASSERT_EQUAL_INT(23, cfg.spill_pixels_error);
+
+	/* This should fail */
+	spillover_pixels_error = cmp_icu_max_spill(42)+1;
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_TRUE(error);
+
+#if 0
+TODO: implemented F_CAM DATA_TYPE_F_CAM_OFFSET and DATA_TYPE_F_CAM_BACKGROUND
+	/* DATA_TYPE_F_CAM_OFFSET */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_CAM_OFFSET, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+	/* DATA_TYPE_F_CAM_BACKGROUND */
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_CAM_BACKGROUND, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS);
+#endif
+}
+
+
+/**
+ * @test map_to_pos
+ */
+
+void test_map_to_pos(void)
+{
+	uint32_t value_to_map;
+	uint32_t max_data_bits;
+	uint32_t mapped_value;
+
+	/* test mapping 32 bits values */
+	max_data_bits = 32;
+
+	value_to_map = 0;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(0, mapped_value);
+
+	value_to_map = -1U;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(1, mapped_value);
+
+	value_to_map = 1;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(2, mapped_value);
+
+	value_to_map = 42;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(84, mapped_value);
+
+	value_to_map = INT32_MAX;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_HEX(UINT32_MAX-1, mapped_value);
+
+	value_to_map = INT32_MIN;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_HEX(UINT32_MAX, mapped_value);
+
+	/* test mapping 16 bits values */
+	max_data_bits = 16;
+
+	value_to_map = -1U;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(1, mapped_value);
+
+	/* test mapping 6 bits values */
+	max_data_bits = 6;
+
+	value_to_map = 0;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(0, mapped_value);
+
+	value_to_map = -1U;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(1, mapped_value);
+
+	value_to_map = UINT32_MAX;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(1, mapped_value);
+
+	value_to_map = -1U & 0x3FU;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(1, mapped_value);
+
+	value_to_map = 63;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(1, mapped_value);
+
+	value_to_map = 1;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(2, mapped_value);
+
+	value_to_map = 31;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(62, mapped_value);
+
+	value_to_map = -33U; /* aka 31 */
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(62, mapped_value);
+
+	value_to_map = -32U;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(63, mapped_value);
+
+	value_to_map = 32;
+	mapped_value = map_to_pos(value_to_map, max_data_bits);
+	TEST_ASSERT_EQUAL_INT(63, mapped_value);
+}
+
+
+/**
+ * @test put_n_bits32
+ */
+
+#define SDP_PB_N 3
+
+
+static void init_PB32_arrays(uint32_t *z, uint32_t *o)
+{
+	uint32_t i;
+
+	/* init testarray with all 0 and all 1 */
+	for (i = 0; i < SDP_PB_N; i++) {
+		z[i] = 0;
+		o[i] = 0xffffffff;
+	}
+}
+
+
+void test_put_n_bits32(void)
+{
+	uint32_t v, n;
+	int o, rval; /* return value */
+	uint32_t testarray0[SDP_PB_N];
+	uint32_t testarray1[SDP_PB_N];
+	const uint32_t l = sizeof(testarray0) * CHAR_BIT;
+
+	/* hereafter, the value is v,
+	 * the number of bits to write is n,
+	 * the offset of the bit is o,
+	 * the max length the bitstream in bits is l
+	 */
+
+	init_PB32_arrays(testarray0, testarray1);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+	TEST_ASSERT(testarray0[2] == 0);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	TEST_ASSERT(testarray1[2] == 0xffffffff);
+
+	/*** n=0 ***/
+
+	/* do not write, left border */
+	v = 0; n = 0; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(0, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(0, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(0, rval);
+
+	v = 0xffffffff; n = 0; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(0, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(0, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(0, rval);
+
+	/* do not write, right border */
+	v = 0; n = 0; o = l;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(l, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(l, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(l, rval);
+
+	/* test value = 0xffffffff; N = 0 */
+	v = 0xffffffff; n = 0; o = l;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(l, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(l, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(l, rval);
+
+	/*** n=1 ***/
+
+	/* left border, write 0 */
+	v = 0; n = 1; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(1, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(1, rval);
+	TEST_ASSERT(testarray1[0] == 0x7fffffff);
+
+	/* left border, write 1 */
+	v = 1; n = 1; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(1, rval);
+	TEST_ASSERT(testarray0[0] == 0x80000000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(1, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+
+	/* left border, write 32 */
+	v = 0xf0f0abcd; n = 32; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 32);
+	TEST_ASSERT(testarray0[0] == 0xf0f0abcd);
+	TEST_ASSERT(testarray0[1] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 32);
+	TEST_ASSERT(testarray1[0] == 0xf0f0abcd);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* middle, write 2 bits */
+	v = 3; n = 2; o = 29;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 31);
+	TEST_ASSERT(testarray0[0] == 0x6);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT_EQUAL_INT(rval, 31);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/*** n=5, unsegmented ***/
+
+	/* left border, write 0 */
+	v = 0; n = 5; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 5);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT(testarray1[0] == 0x07ffffff);
+	TEST_ASSERT_EQUAL_INT(rval, 5);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* left border, write 11111 */
+	v = 0x1f; n = 5; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 5);
+	TEST_ASSERT(testarray0[0] == 0xf8000000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 5);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* middle, write 0 */
+	v = 0; n = 5; o = 7;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 12);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 12);
+	TEST_ASSERT(testarray1[0] == 0xfe0fffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* middle, write 11111 */
+	v = 0x1f; n = 5; o = 7;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 12);
+	TEST_ASSERT(testarray0[0] == 0x01f00000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 12);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* right, write 0 */
+	v = 0; n = 5; o = 91;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 96);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+	TEST_ASSERT(testarray0[0] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 96);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	TEST_ASSERT(testarray1[2] == 0xffffffe0);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* right, write 11111 */
+	v = 0x1f; n = 5; o = 91;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 96);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+	TEST_ASSERT(testarray0[2] == 0x0000001f);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 96);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	TEST_ASSERT(testarray1[2] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* 32 bit, write 0 */
+	v = 0; n = 32; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 32);
+	TEST_ASSERT(testarray0[0] == 0x00000000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 32);
+	TEST_ASSERT(testarray1[0] == 0x00000000);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* 32 bit, write -1 */
+	v = 0xffffffff; n = 32; o = 0;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 32);
+	TEST_ASSERT(testarray0[0] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 32);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* SEGMENTED cases */
+	/* 5 bit, write 0 */
+	v = 0; n = 5; o = 62;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 67);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+	TEST_ASSERT(testarray0[2] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 67);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xfffffffc);
+	TEST_ASSERT(testarray1[2] == 0x1fffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* 5 bit, write 1f */
+	v = 0x1f; n = 5; o = 62;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 67);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 3);
+	TEST_ASSERT(testarray0[2] == 0xe0000000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 67);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	TEST_ASSERT(testarray1[2] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* 32 bit, write 0 */
+	v = 0; n = 32; o = 1;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 33);
+	TEST_ASSERT(testarray0[0] == 0x00000000);
+	TEST_ASSERT(testarray0[1] == 0x00000000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 33);
+	TEST_ASSERT(testarray1[0] == 0x80000000);
+	TEST_ASSERT(testarray1[1] == 0x7fffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* 32 bit, write -1 */
+	v = 0xffffffff; n = 32; o = 1;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, 33);
+	TEST_ASSERT(testarray0[0] == 0x7fffffff);
+	TEST_ASSERT(testarray0[1] == 0x80000000);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(rval, 33);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/* test NULL buffer */
+	v = 0; n = 0; o = 0;
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(rval, 0);
+
+	v = 0; n = 1; o = 0;
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(rval, 1);
+
+	v = 0; n = 5; o = 31;
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(rval, 36);
+
+	v = 0; n = 2; o = 95;
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(rval, 97); /* rval can be longer than l */
+
+	/* value larger than n allows */
+	v = 0x7f; n = 6; o = 10;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(16, rval);
+	TEST_ASSERT(testarray0[0] == 0x003f0000);
+	TEST_ASSERT(testarray0[1] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(16, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(16, rval);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	v = 0xffffffff; n = 6; o = 10;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(16, rval);
+	TEST_ASSERT(testarray0[0] == 0x003f0000);
+	TEST_ASSERT(testarray0[1] == 0);
+
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(16, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(16, rval);
+	/* re-init input arrays after clobbering */
+	init_PB32_arrays(testarray0, testarray1);
+
+	/*** error cases ***/
+	/* n too large */
+	v = 0x0; n = 33; o = 1;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(rval, -1);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(rval, -1);
+
+	/* try to put too much in the bitstream */
+	v = 0x1; n = 1; o = 96;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+	TEST_ASSERT(testarray0[2] == 0);
+
+	/* this should work (if bitstream=NULL no length check) */
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(97, rval);
+
+	/* offset lager than max_stream_len(l) */
+	v = 0x0; n = 32; o = INT32_MAX;
+	rval = put_n_bits32(v, n, o, testarray1, l);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, rval);
+	TEST_ASSERT(testarray1[0] == 0xffffffff);
+	TEST_ASSERT(testarray1[1] == 0xffffffff);
+	TEST_ASSERT(testarray1[2] == 0xffffffff);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT(rval < 0);
+
+	/* negative offset */
+	v = 0x0; n = 0; o = -1;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(-1, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(-1, rval);
+
+	v = 0x0; n = 0; o = -2;
+	rval = put_n_bits32(v, n, o, testarray0, l);
+	TEST_ASSERT_EQUAL_INT(-1, rval);
+	TEST_ASSERT(testarray0[0] == 0);
+	TEST_ASSERT(testarray0[1] == 0);
+
+	rval = put_n_bits32(v, n, o, NULL, l);
+	TEST_ASSERT_EQUAL_INT(-1, rval);
+}
+
+
+/**
+ * @test rice_encoder
+ */
+
+void test_rice_encoder(void)
+{
+	uint32_t value, g_par, log2_g_par, cw, cw_len;
+	const uint32_t MAX_GOLOMB_PAR = 0x80000000;
+
+	/* test minimum Golomb parameter */
+	value = 0; log2_g_par = (uint32_t)ilog_2(MIN_ICU_GOLOMB_PAR); g_par = 1U << log2_g_par; cw = ~0U;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(1, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 31;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, cw);
+
+	/* test some arbitrary values */
+	value = 0; log2_g_par = 4; g_par = 1U << log2_g_par; cw = ~0U;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(5, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 1;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(5, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x1, cw);
+
+	value = 42;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(7, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x6a, cw);
+
+	value = 446;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFEE, cw);
+
+	value = 447;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFEF, cw);
+
+	/* test maximum Golomb parameter for rice_encoder */
+	value = 0; log2_g_par = (uint32_t)ilog_2(MAX_GOLOMB_PAR); g_par = 1U << log2_g_par; cw = ~0U;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 1;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x1, cw);
+
+	value = 0x7FFFFFFE;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x7FFFFFFE, cw);
+
+	value = 0x7FFFFFFF;
+	cw_len = rice_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, cw);
+}
+
+
+/**
+ * @test golomb_encoder
+ */
+
+void test_golomb_encoder(void)
+{
+	uint32_t value, g_par, log2_g_par, cw, cw_len;
+	const uint32_t MAX_GOLOMB_PAR = 0x80000000;
+
+	/* test minimum Golomb parameter */
+	value = 0; g_par = MIN_ICU_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(1, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 31;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, cw);
+
+
+	/* test some arbitrary values with g_par = 16 */
+	value = 0; g_par = 16; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(5, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 1;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(5, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x1, cw);
+
+	value = 42;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(7, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x6a, cw);
+
+	value = 446;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFEE, cw);
+
+	value = 447;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFEF, cw);
+
+
+	/* test some arbitrary values with g_par = 3 */
+	value = 0; g_par = 3; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(2, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 1;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(3, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x2, cw);
+
+	value = 42;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(16, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFC, cw);
+
+	value = 44;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(17, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x1FFFB, cw);
+
+	value = 88;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFA, cw);
+
+	value = 89;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFB, cw);
+
+
+	/* test maximum Golomb parameter for golomb_encoder */
+	value = 0; g_par = MAX_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x0, cw);
+
+	value = 1; g_par = MAX_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x1, cw);
+
+	value = 0x7FFFFFFE;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x7FFFFFFE, cw);
+
+	value = 0x7FFFFFFF;
+	cw_len = golomb_encoder(value, g_par, log2_g_par, &cw);
+	TEST_ASSERT_EQUAL_INT(32, cw_len);
+	TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, cw);
+}
+
+
+/**
+ * @test encode_value_zero
+ */
+
+void test_encode_value_zero(void)
+{
+	uint32_t data, model;
+	int stream_len;
+	struct encoder_setupt setup = {0};
+	uint32_t bitstream[3] = {0};
+
+	/* setup the setup */
+	setup.encoder_par1 = 1;
+	setup.encoder_par2 = (uint32_t)ilog_2(setup.encoder_par1);
+	setup.spillover_par = 32;
+	setup.max_data_bits = 32;
+	setup.generate_cw_f = rice_encoder;
+	setup.bitstream_adr = bitstream;
+	setup.max_stream_len = sizeof(bitstream) * CHAR_BIT;
+
+	stream_len = 0;
+
+	data = 0; model = 0;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(2, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x80000000, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+
+	data = 5; model = 0;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(14, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xBFF80000, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+
+	data = 2; model = 7;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(25, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+
+	/* zero escape mechanism */
+	data = 100; model = 42;
+	/* (100-42)*2+1=117 -> cw 0 + 0x0000_0000_0000_0075 */
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(58, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00001D40, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+
+	/* test overflow */
+	data = INT32_MIN; model = 0;
+	/* (INT32_MIN)*-2-1+1=0(overflow) -> cw 0 + 0x0000_0000_0000_0000 */
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(91, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00001D40, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+
+	/* small buffer error */
+	data = 23; model = 26;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len);
+
+	/* reset bitstream to all bits set */
+	bitstream[0] = ~0U;
+	bitstream[1] = ~0U;
+	bitstream[2] = ~0U;
+	stream_len = 0;
+
+	/* we use now values with maximum 6 bits */
+	setup.max_data_bits = 6;
+
+	/* lowest value before zero encoding */
+	data = 53; model = 38;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(32, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]);
+
+	/* lowest value with zero encoding */
+	data = 0; model = 16;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(39, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x41FFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]);
+
+	/* maximum positive value to encode */
+	data = 31; model = 0;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(46, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x40FFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]);
+
+	/* maximum negative value to encode */
+	data = 0; model = 32;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(53, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x40FC07FF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]);
+
+	/* small buffer error when creating the zero escape symbol*/
+	bitstream[0] = 0;
+	bitstream[1] = 0;
+	bitstream[2] = 0;
+	stream_len = 32;
+	setup.max_stream_len = 32;
+	data = 31; model = 0;
+	stream_len = encode_value_zero(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[2]);
+}
+
+
+/**
+ * @test encode_value_multi
+ */
+
+void test_encode_value_multi(void)
+{
+	uint32_t data, model;
+	int stream_len;
+	struct encoder_setupt setup = {0};
+	uint32_t bitstream[4] = {0};
+
+	/* setup the setup */
+	setup.encoder_par1 = 1;
+	setup.encoder_par2 = (uint32_t)ilog_2(setup.encoder_par1);
+	setup.spillover_par = 16;
+	setup.max_data_bits = 32;
+	setup.generate_cw_f = golomb_encoder;
+	setup.bitstream_adr = bitstream;
+	setup.max_stream_len = sizeof(bitstream) * CHAR_BIT;
+
+	stream_len = 0;
+
+	data = 0; model = 0;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(1, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]);
+
+	data = 0; model = 1;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(3, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x40000000, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]);
+
+	data = 1+23; model = 0+23;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(6, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x58000000, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]);
+
+	/* highest value without multi outlier encoding */
+	data = 0+42; model = 8+42;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(22, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x5BFFF800, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]);
+
+	/* lowest value with multi outlier encoding */
+	data = 8+42; model = 0+42;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(41, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x5BFFFBFF, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFC000000, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]);
+
+	/* highest value with multi outlier encoding */
+	data = INT32_MIN; model = 0;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(105, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0x5BFFFBFF, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFC7FFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0xFF7FFFFF, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0xF7800000, bitstream[3]);
+
+	/* small buffer error */
+	data = 0; model = 38;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len);
+
+	/* small buffer error when creating the multi escape symbol*/
+	bitstream[0] = 0;
+	bitstream[1] = 0;
+	setup.max_stream_len = 32;
+
+	stream_len = 32;
+	data = 31; model = 0;
+	stream_len = encode_value_multi(data, model, stream_len, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[1]);
+}
+
+
+/**
+ * @test encode_value
+ */
+
+void test_encode_value(void)
+{
+	struct encoder_setupt setup = {0};
+	uint32_t bitstream[4] = {0};
+	uint32_t data, model;
+	int cmp_size;
+
+	setup.encode_method_f = encode_value_none;
+	setup.bitstream_adr = bitstream;
+	setup.max_stream_len = 128;
+	cmp_size = 0;
+
+	/* test 32 bit input */
+	setup.encoder_par1 = 32;
+	setup.max_data_bits = 32;
+	setup.lossy_par = 0;
+
+	data = 0; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(32, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[3]);
+
+	data = UINT32_MAX; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(64, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[3]);
+
+	/* test rounding */
+	setup.lossy_par = 1;
+	data = UINT32_MAX; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(96, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[3]);
+
+	setup.lossy_par = 2;
+	data = 0x3; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(128, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]);
+
+	/* small buffer error bitstream can not hold more data*/
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size);
+
+	/* reset bitstream */
+	bitstream[0] = 0;
+	bitstream[1] = 0;
+	bitstream[2] = 0;
+	bitstream[3] = 0;
+	cmp_size = 0;
+
+	/* test 31 bit input */
+	setup.encoder_par1 = 31;
+	setup.max_data_bits = 31;
+	setup.lossy_par = 0;
+
+	data = 0; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(31, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[3]);
+
+	data = 0x7FFFFFFF; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(62, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0x00000001, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFC, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[3]);
+
+	/* round = 1 */
+	setup.lossy_par = 1;
+	data = UINT32_MAX; model = UINT32_MAX;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(93, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0x00000001, bitstream[0]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFFFFF8, bitstream[2]);
+	TEST_ASSERT_EQUAL_HEX(0, bitstream[3]);
+
+	/* data are bigger than max_data_bits */
+	setup.lossy_par = 0;
+	data = UINT32_MAX; model = 0;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_size);
+
+	/* model are bigger than max_data_bits */
+	setup.lossy_par = 0;
+	cmp_size = 93;
+	data = 0; model = UINT32_MAX;
+	cmp_size = encode_value(data, model, cmp_size, &setup);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_size);
+}
+
+
+/**
+ * @test cmp_get_max_used_bits
+ * TODO: move this test
+ */
+
+void test_cmp_get_max_used_bits(void)
+{
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.nc_imagette, MAX_USED_NC_IMAGETTE_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.saturated_imagette, MAX_USED_SATURATED_IMAGETTE_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_imagette, MAX_USED_FC_IMAGETTE_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.f_fx, MAX_USED_F_FX_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.f_efx, MAX_USED_F_EFX_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.f_ncob, MAX_USED_F_NCOB_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.f_ecob, MAX_USED_F_ECOB_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.s_exp_flags, MAX_USED_S_FX_EXPOSURE_FLAGS_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.s_fx, MAX_USED_S_FX_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.s_efx, MAX_USED_S_EFX_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.s_ncob, MAX_USED_S_NCOB_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.s_ecob, MAX_USED_S_ECOB_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.l_fx_variance, MAX_USED_L_FX_VARIANCE_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.l_efx, MAX_USED_L_EFX_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.l_ncob, MAX_USED_L_NCOB_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.l_ecob, MAX_USED_L_ECOB_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.l_cob_variance, MAX_USED_L_COB_VARIANCE_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.nc_offset_mean, MAX_USED_NC_OFFSET_MEAN_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.nc_offset_variance, MAX_USED_NC_OFFSET_VARIANCE_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.nc_background_mean, MAX_USED_NC_BACKGROUND_MEAN_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.nc_background_variance, MAX_USED_NC_BACKGROUND_VARIANCE_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.nc_background_outlier_pixels, MAX_USED_NC_BACKGROUND_OUTLIER_PIXELS_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.smearing_mean, MAX_USED_SMEARING_MEAN_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.smearing_variance_mean, MAX_USED_SMEARING_VARIANCE_MEAN_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.smearing_outlier_pixels, MAX_USED_SMEARING_OUTLIER_PIXELS_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_offset_mean, MAX_USED_FC_OFFSET_MEAN_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_offset_variance, MAX_USED_FC_OFFSET_VARIANCE_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_offset_pixel_in_error, MAX_USED_FC_OFFSET_PIXEL_IN_ERROR_BITS);
+
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_background_mean, MAX_USED_FC_BACKGROUND_MEAN_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_background_variance, MAX_USED_FC_BACKGROUND_VARIANCE_BITS);
+	TEST_ASSERT_EQUAL_INT(max_used_bits.fc_background_outlier_pixels, MAX_USED_FC_BACKGROUND_OUTLIER_PIXELS_BITS);
+}
+
+
+/**
+ * @test configure_encoder_setup
+ */
+
+void test_configure_encoder_setup(void)
+{
+	struct encoder_setupt setup;
+	uint32_t cmp_par;
+	uint32_t spillover;
+	uint32_t lossy_par;
+	uint32_t max_data_bits;
+	struct cmp_cfg cfg;
+	int error;
+
+	/* test Golomb encoder zero escape mechanism */
+	cmp_par = 42;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 15;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_MODEL_ZERO;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL(golomb_encoder, setup.generate_cw_f); /* pointer to the code word encoder */
+	TEST_ASSERT_EQUAL(encode_value_zero, setup.encode_method_f); /* pointer to the encoding function */
+	TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */
+	TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */
+	TEST_ASSERT_EQUAL_INT(42, setup.encoder_par1); /* encoding parameter 1 */
+	TEST_ASSERT_EQUAL_INT(5, setup.encoder_par2); /* encoding parameter 2 */
+	TEST_ASSERT_EQUAL_INT(23, setup.spillover_par); /* outlier parameter */
+	TEST_ASSERT_EQUAL_INT(0, setup.lossy_par); /* lossy compression parameter */
+	TEST_ASSERT_EQUAL_INT(15, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */
+	memset(&setup, 0, sizeof(setup));
+
+	/* test Rice encoder multi escape mechanism */
+	cmp_par = 32;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 32;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_MULTI;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL(rice_encoder, setup.generate_cw_f); /* pointer to the code word encoder */
+	TEST_ASSERT_EQUAL(encode_value_multi, setup.encode_method_f); /* pointer to the encoding function */
+	TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */
+	TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */
+	TEST_ASSERT_EQUAL_INT(32, setup.encoder_par1); /* encoding parameter 1 */
+	TEST_ASSERT_EQUAL_INT(5, setup.encoder_par2); /* encoding parameter 2 */
+	TEST_ASSERT_EQUAL_INT(23, setup.spillover_par); /* outlier parameter */
+	TEST_ASSERT_EQUAL_INT(0, setup.lossy_par); /* lossy compression parameter */
+	TEST_ASSERT_EQUAL_INT(32, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */
+	memset(&setup, 0, sizeof(setup));
+
+	/* test CMP_MODE_STUFF */
+	cmp_par = 32;
+	spillover = ~0;
+	lossy_par = 1;
+	max_data_bits = 32;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_STUFF;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL(NULL, setup.generate_cw_f); /* pointer to the code word encoder */
+	TEST_ASSERT_EQUAL(encode_value_none, setup.encode_method_f); /* pointer to the encoding function */
+	TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */
+	TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */
+	TEST_ASSERT_EQUAL_INT(32, setup.encoder_par1); /* encoding parameter 1 */
+	TEST_ASSERT_EQUAL_INT(0, setup.encoder_par2); /* encoding parameter 2 */
+	TEST_ASSERT_EQUAL_INT(0, setup.spillover_par); /* outlier parameter */
+	TEST_ASSERT_EQUAL_INT(1, setup.lossy_par); /* lossy compression parameter */
+	TEST_ASSERT_EQUAL_INT(32, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */
+	memset(&setup, 0, sizeof(setup));
+
+	/* test max_used_bits = 33 */
+	cmp_par = 32;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 33;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_MULTI;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_TRUE(error);
+	memset(&setup, 0, sizeof(setup));
+
+	/* cmp_par = 0 test */
+	cmp_par = 0;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 32;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_MULTI;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_TRUE(error);
+	memset(&setup, 0, sizeof(setup));
+
+	/* cmp_par = 0 test STUFF MODE this should work*/
+	cmp_par = 0;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 32;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_STUFF;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_FALSE(error);
+	TEST_ASSERT_EQUAL(NULL, setup.generate_cw_f); /* pointer to the code word encoder */
+	TEST_ASSERT_EQUAL(encode_value_none, setup.encode_method_f); /* pointer to the encoding function */
+	TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */
+	TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */
+	TEST_ASSERT_EQUAL_INT(0, setup.encoder_par1); /* encoding parameter 1 */
+	TEST_ASSERT_EQUAL_INT(0, setup.encoder_par2); /* encoding parameter 2 */
+	TEST_ASSERT_EQUAL_INT(0, setup.spillover_par); /* outlier parameter */
+	TEST_ASSERT_EQUAL_INT(0, setup.lossy_par); /* lossy compression parameter */
+	TEST_ASSERT_EQUAL_INT(0, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */
+	memset(&setup, 0, sizeof(setup));
+
+	/* cmp_mode = STUFF_MODE +1  */
+	cmp_par = 32;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 1;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_STUFF+1;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_TRUE(error);
+	memset(&setup, 0, sizeof(setup));
+
+	/* setup = NULL test */
+	cmp_par = 42;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 15;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_MODEL_ZERO;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(NULL, cmp_par, spillover,lossy_par,
+					max_data_bits, &cfg);
+	TEST_ASSERT_TRUE(error);
+	memset(&setup, 0, sizeof(setup));
+
+	/* cfg = NULL test */
+	cmp_par = 42;
+	spillover = 23;
+	lossy_par = 0;
+	max_data_bits = 15;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_MODEL_ZERO;
+	cfg.icu_output_buf = (void *)123;
+	cfg.buffer_length = 2;
+	error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par,
+					max_data_bits, NULL);
+	TEST_ASSERT_TRUE(error);
+	memset(&setup, 0, sizeof(setup));
+}
+
+
+/**
+ * @test compress_imagette
+ */
+
+void test_compress_imagette_diff(void)
+{
+	uint16_t data[] = {0xFFFF, 1, 0, 42, 0x8000, 0x7FFF, 0xFFFF};
+	uint32_t output_buf[3] = {0xFFFF, 0xFFFF, 0xFFFF};
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_ZERO;
+	cfg.input_buf = data;
+	cfg.samples = 7;
+	cfg.golomb_par = 1;
+	cfg.spill = 8;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 7;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(66, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0xDF6002AB, be32_to_cpu(output_buf[0]));
+	TEST_ASSERT_EQUAL_HEX(0xFEB70000, be32_to_cpu(output_buf[1]));
+	TEST_ASSERT_EQUAL_HEX(0x00000000, be32_to_cpu(output_buf[2]));
+}
+
+
+/**
+ * @test compress_imagette
+ */
+
+void test_compress_imagette_model(void)
+{
+	uint16_t data[]  = {0x0000, 0x0001, 0x0042, 0x8000, 0x7FFF, 0xFFFF, 0xFFFF};
+	uint16_t model[] = {0x0000, 0xFFFF, 0xF301, 0x8FFF, 0x0000, 0xFFFF, 0x0000};
+	uint16_t model_up[7] = {0};
+	uint32_t output_buf[3] = {0xFFFF, 0xFFFF, 0xFFFF};
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_MODEL_MULTI;
+	cfg.input_buf = data;
+	cfg.model_buf = model;
+	cfg.icu_new_model_buf = model_up;
+	cfg.samples = 7;
+	cfg.golomb_par = 3;
+	cfg.spill = 8;
+	cfg.model_value = 8;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 8;
+
+	cmp_size = icu_compress_data(&cfg);
+
+	TEST_ASSERT_EQUAL_INT(76, cmp_size);
+	TEST_ASSERT_EQUAL_HEX(0x2BDB4F5E, be32_to_cpu(output_buf[0]));
+	TEST_ASSERT_EQUAL_HEX(0xDFF5F9FF, be32_to_cpu(output_buf[1]));
+	TEST_ASSERT_EQUAL_HEX(0xEC200000, be32_to_cpu(output_buf[2]));
+
+	TEST_ASSERT_EQUAL_HEX(0x0000, model_up[0]);
+	TEST_ASSERT_EQUAL_HEX(0x8000, model_up[1]);
+	TEST_ASSERT_EQUAL_HEX(0x79A1, model_up[2]);
+	TEST_ASSERT_EQUAL_HEX(0x87FF, model_up[3]);
+	TEST_ASSERT_EQUAL_HEX(0x3FFF, model_up[4]);
+	TEST_ASSERT_EQUAL_HEX(0xFFFF, model_up[5]);
+	TEST_ASSERT_EQUAL_HEX(0x7FFF, model_up[6]);
+
+
+	/* error case: model mode without model data */
+	cfg.model_buf = NULL; /* this is the error */
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL(-1, cmp_size);
+}
+
+
+/**
+ * @test compress_imagette
+ */
+
+void test_compress_imagette_stuff(void)
+{
+	uint16_t data[] = {0x0, 0x1, 0x23, 0x42, 0x8000, 0x7FFF, 0xFFFF};
+	uint32_t output_buf[4] = {0};
+	struct cmp_cfg cfg = {0};
+
+	int cmp_size;
+	uint8_t output_buf_exp[] = {
+		0x00, 0x00, 0x00, 0x01,
+		0x00, 0x23, 0x00, 0x42,
+		0x80, 0x00, 0x7F, 0xFF,
+		0xFF, 0xFF, 0x00, 0x00};
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_STUFF;
+	cfg.input_buf = data;
+	cfg.samples = 7;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 8;
+	cfg.golomb_par = 16; /* how many used bits has the maximum data value */
+
+	cmp_size = icu_compress_data(&cfg);
+
+	uint32_t *output_buf_exp_32 = (uint32_t *)output_buf_exp;
+	TEST_ASSERT_EQUAL_INT(7*16, cmp_size);
+	TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[0], output_buf[0]);
+	TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[1], output_buf[1]);
+	TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[2], output_buf[2]);
+	TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[3], output_buf[3]);
+}
+
+
+/**
+ * @test compress_imagette
+ */
+
+void test_compress_imagette_raw(void)
+{
+	uint16_t data[] = {0x0, 0x1, 0x23, 0x42, INT16_MIN, INT16_MAX, UINT16_MAX};
+	uint16_t output_buf[7] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.model_buf = NULL;
+	cfg.input_buf = data;
+	cfg.samples = 7;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 7;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(7*16, cmp_size);
+	TEST_ASSERT_EQUAL_HEX16(0x0, be16_to_cpu(output_buf[0]));
+	TEST_ASSERT_EQUAL_HEX16(0x1, be16_to_cpu(output_buf[1]));
+	TEST_ASSERT_EQUAL_HEX16(0x23, be16_to_cpu(output_buf[2]));
+	TEST_ASSERT_EQUAL_HEX16(0x42, be16_to_cpu(output_buf[3]));
+	TEST_ASSERT_EQUAL_HEX16(INT16_MIN, be16_to_cpu(output_buf[4]));
+	TEST_ASSERT_EQUAL_HEX16(INT16_MAX, be16_to_cpu(output_buf[5]));
+	TEST_ASSERT_EQUAL_HEX16(UINT16_MAX, be16_to_cpu(output_buf[6]));
+
+
+	/* compressed data buf = NULL test */
+	memset(&cfg, 0, sizeof(struct cmp_cfg));
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.input_buf = data;
+	cfg.samples = 7;
+	cfg.icu_output_buf = NULL;
+	cfg.buffer_length = 7;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(7*16, cmp_size);
+
+
+	/* error case: input_buf = NULL */
+	memset(&cfg, 0, sizeof(struct cmp_cfg));
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.input_buf = NULL; /* no data to compress */
+	cfg.samples = 7;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 7;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_size);
+
+
+	/* error case: compressed data buffer to small */
+	memset(&cfg, 0, sizeof(struct cmp_cfg));
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.input_buf = data;
+	cfg.samples = 7;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 6; /* the buffer is to small */
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size);
+}
+
+
+/**
+ * @test compress_imagette
+ */
+
+void test_compress_imagette_error_cases(void)
+{
+	uint16_t data[] = {0xFFFF, 1, 0, 42, 0x8000, 0x7FFF, 0xFFFF};
+	uint32_t output_buf[2] = {0xFFFF, 0xFFFF};
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_ZERO;
+	cfg.input_buf = NULL;
+	cfg.samples = 0;  /* nothing to compress */
+	cfg.golomb_par = 1;
+	cfg.spill = 8;
+	cfg.icu_output_buf = NULL;
+	cfg.buffer_length = 0;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(0, cmp_size);
+
+
+	/* compressed data buffer to small test */
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_ZERO;
+	cfg.input_buf = data;
+	cfg.samples = 7;
+	cfg.golomb_par = 1;
+	cfg.spill = 8;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 4;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size);
+
+
+	/* error in setup */
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+	max_used_bits.nc_imagette = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_ZERO;
+	cfg.input_buf = data;
+	cfg.samples = 2;
+	cfg.golomb_par = 1;
+	cfg.spill = 8;
+	cfg.icu_output_buf = (uint32_t *)output_buf;
+	cfg.buffer_length = 4;
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_size);
+}
+
+
+/**
+ * @test compress_multi_entry_hdr
+ */
+
+void test_compress_multi_entry_hdr(void)
+{
+	int stream_len;
+	uint8_t data[MULTI_ENTRY_HDR_SIZE];
+	uint8_t model[MULTI_ENTRY_HDR_SIZE];
+	uint8_t up_model[MULTI_ENTRY_HDR_SIZE];
+	uint8_t cmp_data[MULTI_ENTRY_HDR_SIZE];
+	uint8_t *data_p = NULL;
+	uint8_t *model_p = NULL;
+	uint8_t *up_model_p = NULL;
+
+	memset(data, 0x42, sizeof(data));
+
+	/* no data; no cmp_data no model test */
+	/* no data; no model; no up_model; no cmp_data */
+	stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p,
+					      (void **)&up_model_p, NULL);
+	TEST_ASSERT_EQUAL_INT(96, stream_len);
+
+	/* no model; no up_model */
+	data_p = data;
+	stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p,
+					      (void **)&up_model_p, cmp_data);
+	TEST_ASSERT_EQUAL_INT(96, stream_len);
+	TEST_ASSERT_FALSE(memcmp(cmp_data, data, MULTI_ENTRY_HDR_SIZE));
+	TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE);
+
+	/* no up_model */
+	memset(cmp_data, 0, sizeof(cmp_data));
+	data_p = data;
+	model_p = model;
+	up_model_p = NULL;
+	stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p,
+					      (void **)&up_model_p, cmp_data);
+	TEST_ASSERT_EQUAL_INT(96, stream_len);
+	TEST_ASSERT_FALSE(memcmp(cmp_data, data, MULTI_ENTRY_HDR_SIZE));
+	TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE);
+	TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE);
+
+	/* all buffer test */
+	memset(cmp_data, 0, sizeof(cmp_data));
+	data_p = data;
+	model_p = model;
+	up_model_p = up_model;
+	stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p,
+					      (void **)&up_model_p, cmp_data);
+	TEST_ASSERT_EQUAL_INT(96, stream_len);
+	TEST_ASSERT_FALSE(memcmp(cmp_data, data, MULTI_ENTRY_HDR_SIZE));
+	TEST_ASSERT_FALSE(memcmp(up_model, data, MULTI_ENTRY_HDR_SIZE));
+	TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE);
+	TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE);
+	TEST_ASSERT_EQUAL(up_model_p-up_model, MULTI_ENTRY_HDR_SIZE);
+
+	/* all buffer test; no cmp_data */
+	memset(cmp_data, 0, sizeof(cmp_data));
+	data_p = data;
+	model_p = model;
+	up_model_p = up_model;
+	stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p,
+					      (void **)&up_model_p, NULL);
+	TEST_ASSERT_EQUAL_INT(96, stream_len);
+	TEST_ASSERT_FALSE(memcmp(up_model, data, MULTI_ENTRY_HDR_SIZE));
+	TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE);
+	TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE);
+	TEST_ASSERT_EQUAL(up_model_p-up_model, MULTI_ENTRY_HDR_SIZE);
+
+	/* no data, use up_model test */
+	memset(cmp_data, 0, sizeof(cmp_data));
+	data_p = NULL;
+	model_p = model;
+	up_model_p = up_model;
+	stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p,
+					      (void **)&up_model_p, NULL);
+	TEST_ASSERT_EQUAL_INT(96, stream_len);
+	TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE);
+	TEST_ASSERT_EQUAL(up_model_p-up_model, MULTI_ENTRY_HDR_SIZE);
+}
+
+
+void test_compress_s_fx_raw(void)
+{
+	struct s_fx data[7];
+	struct cmp_cfg cfg = {0};
+	int cmp_size, cmp_size_exp;
+	size_t i;
+
+	cfg.data_type = DATA_TYPE_S_FX;
+	cfg.model_buf = NULL;
+	cfg.samples = 7;
+	cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	cfg.buffer_length = 7;
+	cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.icu_output_buf);
+	TEST_ASSERT_NOT_NULL(cfg.input_buf);
+
+	data[0].exp_flags = 0x0;
+	data[0].fx = 0x0;
+	data[1].exp_flags = 0x1;
+	data[1].fx = 0x1;
+	data[2].exp_flags = 0x2;
+	data[2].fx = 0x23;
+	data[3].exp_flags = 0x3;
+	data[3].fx = 0x42;
+	data[4].exp_flags = 0x0;
+	data[4].fx = INT32_MIN;
+	data[5].exp_flags = 0x3;
+	data[5].fx = INT32_MAX;
+	data[6].exp_flags = 0x1;
+	data[6].fx = UINT32_MAX;
+
+	struct multi_entry_hdr *hdr = cfg.input_buf;
+	memset(hdr, 0x42, sizeof(struct multi_entry_hdr));
+	memcpy(hdr->entry, data, sizeof(data));
+
+	cmp_size = icu_compress_data(&cfg);
+
+	cmp_size_exp = (sizeof(data) + sizeof(struct multi_entry_hdr)) * CHAR_BIT;
+	TEST_ASSERT_EQUAL_INT(cmp_size_exp, cmp_size);
+
+	for (i = 0; i < ARRAY_SIZE(data); i++) {
+		hdr = (struct multi_entry_hdr *)cfg.icu_output_buf;
+		struct s_fx *p = (struct s_fx *)hdr->entry;
+
+		TEST_ASSERT_EQUAL_HEX(data[i].exp_flags, p[i].exp_flags);
+		TEST_ASSERT_EQUAL_HEX(data[i].fx, cpu_to_be32(p[i].fx));
+	}
+}
+
+
+void test_compress_s_fx_staff(void)
+{
+	struct s_fx data[5];
+	struct cmp_cfg cfg = {0};
+	int cmp_size, cmp_size_exp;
+	struct multi_entry_hdr *hdr;
+	uint32_t *cmp_data;
+
+	/* setup configuration */
+	cfg.data_type = DATA_TYPE_S_FX;
+	cfg.cmp_mode = CMP_MODE_STUFF;
+	cfg.samples = 5;
+	cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.input_buf);
+	cfg.buffer_length = 5;
+	cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.icu_output_buf);
+	cfg.cmp_par_exp_flags = 2;
+	cfg.cmp_par_fx = 21;
+
+	/* generate input data */
+	hdr = cfg.input_buf;
+	/* use dummy data for the header */
+	memset(hdr, 0x42, sizeof(struct multi_entry_hdr));
+	data[0].exp_flags = 0x0;
+	data[0].fx = 0x0;
+	data[1].exp_flags = 0x1;
+	data[1].fx = 0x1;
+	data[2].exp_flags = 0x2;
+	data[2].fx = 0x23;
+	data[3].exp_flags = 0x3;
+	data[3].fx = 0x42;
+	data[4].exp_flags = 0x0;
+	data[4].fx = 0x001FFFFF;
+	memcpy(hdr->entry, data, sizeof(data));
+
+	cmp_size = icu_compress_data(&cfg);
+
+	cmp_size_exp = 5 * (2 + 21) + MULTI_ENTRY_HDR_SIZE * CHAR_BIT;
+	TEST_ASSERT_EQUAL_INT(cmp_size_exp, cmp_size);
+	TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE));
+	hdr = (void *)cfg.icu_output_buf;
+	cmp_data = (uint32_t *)hdr->entry;
+	TEST_ASSERT_EQUAL_HEX(0x00000080, be32_to_cpu(cmp_data[0]));
+	TEST_ASSERT_EQUAL_HEX(0x00060001, be32_to_cpu(cmp_data[1]));
+	TEST_ASSERT_EQUAL_HEX(0x1E000423, be32_to_cpu(cmp_data[2]));
+	TEST_ASSERT_EQUAL_HEX(0xFFFFE000, be32_to_cpu(cmp_data[3]));
+
+	free(cfg.input_buf);
+	free(cfg.icu_output_buf);
+}
+
+
+void test_compress_s_fx_model_multi(void)
+{
+	struct s_fx data[6], model[6];
+	struct s_fx *up_model_buf;
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+	struct multi_entry_hdr *hdr;
+	uint32_t *cmp_data;
+	struct cmp_max_used_bits max_used_bits;
+
+	/* setup configuration */
+	cfg.data_type = DATA_TYPE_S_FX;
+	cfg.cmp_mode = CMP_MODE_MODEL_MULTI;
+	cfg.model_value = 11;
+	cfg.samples = 6;
+	cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.input_buf);
+	cfg.model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.model_buf);
+	cfg.icu_new_model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.icu_new_model_buf);
+	cfg.buffer_length = 6;
+	cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.icu_output_buf);
+	cfg.cmp_par_exp_flags = 1;
+	cfg.spill_exp_flags = 8;
+	cfg.cmp_par_fx = 3;
+	cfg.spill_fx = 35;
+
+
+	/* generate input data */
+	hdr = cfg.input_buf;
+	/* use dummy data for the header */
+	memset(hdr, 0x42, sizeof(struct multi_entry_hdr));
+	data[0].exp_flags = 0x0;
+	data[0].fx = 0x0;
+	data[1].exp_flags = 0x1;
+	data[1].fx = 0x1;
+	data[2].exp_flags = 0x2;
+	data[2].fx = 0x23;
+	data[3].exp_flags = 0x3;
+	data[3].fx = 0x42;
+	data[4].exp_flags = 0x0;
+	data[4].fx = 0x001FFFFF;
+	data[5].exp_flags = 0x0;
+	data[5].fx = 0x0;
+	memcpy(hdr->entry, data, sizeof(data));
+
+	/* generate model data */
+	hdr = cfg.model_buf;
+	/* use dummy data for the header */
+	memset(hdr, 0x41, sizeof(struct multi_entry_hdr));
+	model[0].exp_flags = 0x0;
+	model[0].fx = 0x0;
+	model[1].exp_flags = 0x3;
+	model[1].fx = 0x1;
+	model[2].exp_flags = 0x0;
+	model[2].fx = 0x42;
+	model[3].exp_flags = 0x0;
+	model[3].fx = 0x23;
+	model[4].exp_flags = 0x3;
+	model[4].fx = 0x0;
+	model[5].exp_flags = 0x2;
+	model[5].fx = 0x001FFFFF;
+	memcpy(hdr->entry, model, sizeof(model));
+
+	max_used_bits = cmp_get_max_used_bits();
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 21;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cmp_size = icu_compress_data(&cfg);
+
+	TEST_ASSERT_EQUAL_INT(166, cmp_size);
+	TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE));
+	cmp_data = &cfg.icu_output_buf[MULTI_ENTRY_HDR_SIZE/sizeof(uint32_t)];
+	TEST_ASSERT_EQUAL_HEX(0x1C77FFA6, be32_to_cpu(cmp_data[0]));
+	TEST_ASSERT_EQUAL_HEX(0xAFFF4DE5, be32_to_cpu(cmp_data[1]));
+	TEST_ASSERT_EQUAL_HEX(0xCC000000, be32_to_cpu(cmp_data[2]));
+
+	hdr = cfg.icu_new_model_buf;
+	up_model_buf = (struct s_fx *)hdr->entry;
+	TEST_ASSERT_FALSE(memcmp(hdr, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE));
+	TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[0].exp_flags);
+	TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[0].fx);
+	TEST_ASSERT_EQUAL_HEX(0x2, up_model_buf[1].exp_flags);
+	TEST_ASSERT_EQUAL_HEX(0x1, up_model_buf[1].fx);
+	TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[2].exp_flags);
+	TEST_ASSERT_EQUAL_HEX(0x38, up_model_buf[2].fx);
+	TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[3].exp_flags);
+	TEST_ASSERT_EQUAL_HEX(0x2C, up_model_buf[3].fx);
+	TEST_ASSERT_EQUAL_HEX(0x2, up_model_buf[4].exp_flags);
+	TEST_ASSERT_EQUAL_HEX(0x9FFFF, up_model_buf[4].fx);
+	TEST_ASSERT_EQUAL_HEX(0x1, up_model_buf[5].exp_flags);
+	TEST_ASSERT_EQUAL_HEX(0x15FFFF, up_model_buf[5].fx);
+
+	free(cfg.input_buf);
+	free(cfg.model_buf);
+	free(cfg.icu_new_model_buf);
+	free(cfg.icu_output_buf);
+}
+
+
+#if 0
+void todo_est_compress_s_fx_efx_model_multi(void)
+{
+	uint32_t i;
+	struct s_fx_efx data[6], model[6];
+	struct s_fx_efx *up_model_buf;
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+	struct multi_entry_hdr *hdr;
+	uint32_t *cmp_data;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	/* define max_used_bits */
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 21;
+	max_used_bits.s_efx = 21;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	/* setup configuration */
+	cfg.data_type = DATA_TYPE_S_FX_EFX;
+	cfg.cmp_mode = CMP_MODE_MODEL_MULTI;
+	cfg.model_value = 16;
+	cfg.samples = 6;
+	cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.input_buf);
+	cfg.model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.model_buf);
+	cfg.icu_new_model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.icu_new_model_buf);
+	cfg.buffer_length = 6;
+	cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type));
+	TEST_ASSERT_NOT_NULL(cfg.icu_output_buf);
+	cfg.cmp_par_exp_flags = 1;
+	cfg.spill_exp_flags = 8;
+	cfg.cmp_par_fx = 3;
+	cfg.spill_fx = 35;
+	cfg.cmp_par_efx = 4;
+	cfg.spill_efx = 35;
+
+
+	/* generate input data */
+	hdr = cfg.input_buf;
+	/* use dummy data for the header */
+	memset(hdr, 0x42, sizeof(struct multi_entry_hdr));
+	data[0].exp_flags = 0x0;
+	data[0].fx = 0x0;
+	data[0].efx = 0x0;
+	data[1].exp_flags = 0x1;
+	data[1].fx = 0x1;
+	data[1].efx = 0;
+	data[2].exp_flags = 0x2;
+	data[2].fx = 0x23;
+	data[2].efx = 0;
+	data[3].exp_flags = 0x3;
+	data[3].fx = 0x42;
+	data[3].efx = 0;
+	data[4].exp_flags = 0x0;
+	data[4].fx = 0x001FFFFF;
+	data[4].efx = 0;
+	data[5].exp_flags = 0x0;
+	data[5].fx = 0x0;
+	data[5].efx = 0;
+	memcpy(hdr->entry, data, sizeof(data));
+
+	/* generate model data */
+	hdr = cfg.model_buf;
+	/* use dummy data for the header */
+	memset(hdr, 0x41, sizeof(struct multi_entry_hdr));
+	model[0].exp_flags = 0x0;
+	model[0].fx = 0x0;
+	model[0].efx = 0x1FFFFF;
+	model[1].exp_flags = 0x3;
+	model[1].fx = 0x1;
+	model[1].efx = 0x1FFFFF;
+	model[2].exp_flags = 0x0;
+	model[2].fx = 0x42;
+	model[2].efx = 0x1FFFFF;
+	model[3].exp_flags = 0x0;
+	model[3].fx = 0x23;
+	model[3].efx = 0x1FFFFF;
+	model[4].exp_flags = 0x3;
+	model[4].fx = 0x0;
+	model[4].efx = 0x1FFFFF;
+	model[5].exp_flags = 0x2;
+	model[5].fx = 0x001FFFFF;
+	model[5].efx = 0x1FFFFF;
+	memcpy(hdr->entry, model, sizeof(model));
+
+	cmp_size = icu_compress_data(&cfg);
+#if 0
+	TEST_ASSERT_EQUAL_INT(166, cmp_size);
+	TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE));
+	cmp_data = &cfg.icu_output_buf[MULTI_ENTRY_HDR_SIZE/sizeof(uint32_t)];
+	TEST_ASSERT_EQUAL_HEX(0x1C77FFA6, be32_to_cpu(cmp_data[0]));
+	TEST_ASSERT_EQUAL_HEX(0xAFFF4DE5, be32_to_cpu(cmp_data[1]));
+	TEST_ASSERT_EQUAL_HEX(0xCC000000, be32_to_cpu(cmp_data[2]));
+
+#endif
+	hdr = cfg.icu_new_model_buf;
+	up_model_buf = (struct s_fx *)hdr->entry;
+	TEST_ASSERT_FALSE(memcmp(hdr, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE));
+	for (i = 0; i < cfg.samples; i++) {
+		TEST_ASSERT_EQUAL(model[i].exp_flags, up_model_buf[i].exp_flags);
+		TEST_ASSERT_EQUAL(model[i].fx, up_model_buf[i].fx);
+		TEST_ASSERT_EQUAL(model[i].efx, up_model_buf[i].efx);
+	}
+
+
+	free(cfg.input_buf);
+	free(cfg.model_buf);
+	free(cfg.icu_new_model_buf);
+	free(cfg.icu_output_buf);
+}
+#endif
+
+
+/**
+ * @test compress_s_fx
+ */
+
+void test_compress_s_fx_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_exp_flags = 6;
+	uint32_t cmp_par_fx = 2;
+	uint32_t spillover_fx = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct s_fx *data_p = (struct s_fx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 21;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL,
+						   NULL, (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* test if data are higher than max used bits value */
+	data_p[0].fx = 0x200000; /* has more than 21 bits (max_used_bits.s_fx) */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	/* compressed data are to small for the compressed_data buffer */
+	max_used_bits.s_exp_flags = 8;
+	max_used_bits.s_fx= 32;
+	cmp_set_max_used_bits(&max_used_bits);
+	memset(data_to_compress, 0xff, sizeof(data_to_compress));
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits);
+
+	max_used_bits.s_exp_flags = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.s_exp_flags = 32;
+	max_used_bits.s_fx= 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_s_fx_efx
+ */
+
+void test_compress_s_fx_efx_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = 2;
+	uint32_t spillover_exp_flags = 6;
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_efx = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_efx = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+2*sizeof(struct s_fx_efx)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx_efx)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct s_fx_efx *data_p= (struct s_fx_efx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 21;
+	max_used_bits.s_efx = 16;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, cmp_par_efx, spillover_efx,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 2, NULL,
+						   NULL, (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* test if data are higher than max used bits value */
+	data_p[0].exp_flags = 0x4; /* has more than 2 bits (max_used_bits.s_exp_flags) */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].exp_flags = 0x3;
+	data_p[1].fx = 0x200000; /* has more than 21 bits (max_used_bits.fx) */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].fx = 0x1FFFFF;
+	data_p[1].efx = 0x100000; /* has more than 16 bits (max_used_bits.efx) */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	/* error case exp_flag setup */
+	max_used_bits.s_exp_flags = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	/* error case fx setup */
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	/* error case efx setup */
+	max_used_bits.s_fx = 21;
+	max_used_bits.s_efx = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_s_fx_ncob
+ */
+
+void test_compress_s_fx_ncob_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = 3;
+	uint32_t spillover_exp_flags = 6;
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_ncob = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_ncob = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_ncob)] = {0};
+	uint8_t model_data[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_ncob)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx_ncob)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct s_fx_ncob *data_p = (struct s_fx_ncob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 21;
+	max_used_bits.s_ncob = 31;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_NCOB, CMP_MODE_MODEL_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, model_data,
+						   NULL, (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* the compressed_data buffer is to small */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits);
+
+	/* test if data are higher than max used bits value */
+	data_p[2].exp_flags = 0x4; /* has more than 2 bits (max_used_bits.s_exp_flags) */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].exp_flags = 0x3;
+	data_p[1].fx = 0x200000; /* value to high */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].fx = 0x1FFFFF; /* value to high */
+	data_p[0].ncob_y = 0x80000000; /* value to high */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+	data_p[0].ncob_y = 0x7FFFFFFF; /* value to high */
+
+	/* error case exp_flag setup */
+	max_used_bits.s_exp_flags = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	/* error case fx setup */
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	/* error case efx setup */
+	max_used_bits.s_fx = 21;
+	max_used_bits.s_ncob = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_s_fx_efx_ncob_ecob
+ */
+
+void test_compress_s_fx_efx_ncob_ecob_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = 3;
+	uint32_t spillover_exp_flags = 6;
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_ncob = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_ncob = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint32_t cmp_par_efx = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_efx =  cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint32_t cmp_par_ecob = 23;
+	uint32_t spillover_ecob = cmp_icu_max_spill(23);
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_efx_ncob_ecob)] = {0};
+	uint8_t model_data[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_efx_ncob_ecob)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx_efx_ncob_ecob)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct s_fx_efx_ncob_ecob *data_p = (struct s_fx_efx_ncob_ecob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+
+	max_used_bits.s_exp_flags = 2;
+	max_used_bits.s_fx = 21;
+	max_used_bits.s_ncob = 31;
+	max_used_bits.s_efx = 23;
+	max_used_bits.s_ecob = 7;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX_NCOB_ECOB, CMP_MODE_MODEL_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob,
+			       spillover_ncob, cmp_par_efx, spillover_efx,
+			       cmp_par_ecob, spillover_ecob, CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, model_data,
+						   NULL, (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* the compressed_data buffer is to small */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits);
+
+	/* test if data are higher than max used bits value */
+	data_p[2].exp_flags = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].exp_flags = 0x3;
+	data_p[2].fx = 0x200000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].fx = 0x1FFFFF;
+	data_p[1].ncob_x = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].ncob_x = 0x7FFFFFFF;
+	data_p[1].ncob_y = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].ncob_y = 0x7FFFFFFF;
+	data_p[1].efx = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].efx = 0x7FFFFF;
+	data_p[1].ecob_y = 0x80;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+	data_p[1].ecob_y = 0x7F;
+
+	/* error case exp_flag setup */
+	max_used_bits.s_exp_flags = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	/* error case fx setup */
+	max_used_bits.s_exp_flags = 32;
+	max_used_bits.s_fx = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	/* error case efx setup */
+	max_used_bits.s_fx = 32;
+	max_used_bits.s_ncob = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.s_ncob = 32;
+	max_used_bits.s_efx = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.s_efx = 32;
+	max_used_bits.s_ecob = 33;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+	max_used_bits.s_ecob = 32;
+}
+
+
+/**
+ * @test compress_f_fx
+ */
+
+void test_compress_f_fx_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_fx = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_fx = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct f_fx)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+
+	max_used_bits.f_fx = 23;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx, spillover_fx, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* compressed data are to small for the compressed_data buffer */
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits);
+
+	max_used_bits.f_fx= 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_f_fx_efx
+ */
+
+void test_compress_f_fx_efx_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_efx = 1;
+	uint32_t spillover_efx = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+2*sizeof(struct f_fx_efx)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx_efx)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct f_fx_efx *data_p = (struct f_fx_efx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.f_fx = 23;
+	max_used_bits.f_efx = 31;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx, spillover_fx, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, cmp_par_efx, spillover_efx,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 2, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* compressed data are to small for the compressed_data buffer */
+	data_p[0].fx = 42;
+	data_p[0].efx = 42;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits);
+
+	/* efx value is to big for the max used bits values */
+	data_p[0].efx = 0x80000000;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+	data_p[0].efx = 0x7FFFFFFF;
+
+	max_used_bits.f_fx= 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.f_fx= 32;
+	max_used_bits.f_efx= 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_f_fx_ncob
+ */
+
+void test_compress_f_fx_ncob_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_fx = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_ncob = 1;
+	uint32_t spillover_ncob = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+2*sizeof(struct f_fx_ncob)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx_ncob)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct f_fx_ncob *data_p = (struct f_fx_ncob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.f_fx = 31;
+	max_used_bits.f_ncob = 23;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_NCOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 2, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* compressed data are to small for the compressed_data buffer */
+	data_p[0].fx = 42;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits);
+
+	/* value is to big for the max used bits values */
+	data_p[0].ncob_x = 0x800000;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+	data_p[0].ncob_x = 0x7FFFFF;
+	data_p[0].ncob_y = 0x800000;
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+	data_p[0].ncob_y = 0x7FFFFF;
+
+	max_used_bits.f_fx= 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.f_fx= 32;
+	max_used_bits.f_ncob= 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_f_fx_efx_ncob_ecob
+ */
+
+void test_compress_f_fx_efx_ncob_ecob(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_ncob = 2;
+	uint32_t spillover_ncob = 10;
+	uint32_t cmp_par_efx = 3;
+	uint32_t spillover_efx = 44;
+	uint32_t cmp_par_ecob = 5;
+	uint32_t spillover_ecob = 55;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+4*sizeof(struct f_fx_efx_ncob_ecob)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx_efx_ncob_ecob)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct f_fx_efx_ncob_ecob *data_p = (struct f_fx_efx_ncob_ecob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.f_fx = 31;
+	max_used_bits.f_ncob = 3;
+	max_used_bits.f_efx = 16;
+	max_used_bits.f_ecob = 8;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 4, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[3].fx = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[3].fx = 0x80000000-1;
+	data_p[2].ncob_x = 0x8;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].ncob_x = 0x7;
+	data_p[1].ncob_y = 0x8;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].ncob_y = 0x7;
+	data_p[0].efx = 0x10000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].efx = 0x10000-1;
+	data_p[2].ecob_x = 0x100;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].ecob_x = 0x100-1;
+	data_p[3].ecob_y = 0x100;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+	data_p[3].ecob_y = 0x100-1;
+
+	max_used_bits.f_fx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.f_fx = 32;
+	max_used_bits.f_ncob = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.f_ncob = 32;
+	max_used_bits.f_efx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.f_efx = 32;
+	max_used_bits.f_ecob = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_l_fx
+ */
+
+void test_compress_l_fx_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = 3;
+	uint32_t spillover_exp_flags = 10;
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_fx_cob_variance = 30;
+	uint32_t spillover_fx_cob_variance = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct l_fx *data_p = (struct l_fx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.l_exp_flags = 23;
+	max_used_bits.l_fx = 31;
+	max_used_bits.l_efx = 1;
+	max_used_bits.l_fx_variance = 23;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[2].exp_flags = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].exp_flags = 0x800000-1;
+	data_p[2].fx = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].fx = 0x80000000-1;
+	data_p[0].fx_variance = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].fx_variance = 0x800000-1;
+
+	max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_exp_flags = 32;
+	max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_fx = 32;
+	max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_l_fx_efx
+ */
+
+void test_compress_l_fx_efx_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_efx = 3;
+	uint32_t spillover_efx = 44;
+	uint32_t cmp_par_fx_cob_variance = 30;
+	uint32_t spillover_fx_cob_variance = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx_efx)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx_efx)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct l_fx_efx *data_p = (struct l_fx_efx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.l_exp_flags = 23;
+	max_used_bits.l_fx = 31;
+	max_used_bits.l_efx = 1;
+	max_used_bits.l_fx_variance = 23;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_efx, spillover_efx, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[2].exp_flags = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].exp_flags = 0x800000-1;
+	data_p[2].fx = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].fx = 0x80000000-1;
+	data_p[1].efx = 0x2;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].efx = 0x1;
+	data_p[0].fx_variance = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].fx_variance = 0x800000-1;
+
+	max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_exp_flags = 32;
+	max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_fx = 32;
+	max_used_bits.l_efx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_efx = 32;
+	max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_l_fx_ncob
+ */
+
+void test_compress_l_fx_ncob_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_ncob = 2;
+	uint32_t spillover_ncob = 10;
+	uint32_t cmp_par_fx_cob_variance = 30;
+	uint32_t spillover_fx_cob_variance = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx_ncob)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx_ncob)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct l_fx_ncob *data_p = (struct l_fx_ncob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.l_exp_flags = 23;
+	max_used_bits.l_fx = 31;
+	max_used_bits.l_ncob = 2;
+	max_used_bits.l_fx_variance = 23;
+	max_used_bits.l_cob_variance = 11;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_NCOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[2].exp_flags = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].exp_flags = 0x800000-1;
+	data_p[2].fx = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].fx = 0x80000000-1;
+	data_p[2].ncob_x = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].ncob_x = 0x3;
+	data_p[2].ncob_y = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].ncob_y = 0x3;
+	data_p[0].fx_variance = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].fx_variance = 0x800000-1;
+	data_p[2].cob_x_variance = 0x800;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].cob_x_variance = 0x800-1;
+	data_p[2].cob_y_variance = 0x800;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].cob_y_variance = 0x800-1;
+
+	max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_exp_flags = 32;
+	max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_fx = 32;
+	max_used_bits.l_ncob = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_ncob = 32;
+	max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_fx_variance = 32;
+	max_used_bits.l_cob_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_l_fx_efx_ncob_ecob
+ */
+
+void test_compress_l_fx_efx_ncob_ecob_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags);
+	uint32_t cmp_par_fx = 1;
+	uint32_t spillover_fx = 8;
+	uint32_t cmp_par_ncob = 2;
+	uint32_t spillover_ncob = 10;
+	uint32_t cmp_par_efx = 3;
+	uint32_t spillover_efx = 44;
+	uint32_t cmp_par_ecob = 5;
+	uint32_t spillover_ecob = 55;
+	uint32_t cmp_par_fx_cob_variance = 30;
+	uint32_t spillover_fx_cob_variance = 8;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx_efx_ncob_ecob)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx_efx_ncob_ecob)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct l_fx_efx_ncob_ecob *data_p = (struct l_fx_efx_ncob_ecob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.l_exp_flags = 23;
+	max_used_bits.l_fx = 31;
+	max_used_bits.l_ncob = 2;
+	max_used_bits.l_efx = 1;
+	max_used_bits.l_ecob = 3;
+	max_used_bits.l_fx_variance = 23;
+	max_used_bits.l_cob_variance = 11;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags,
+			       cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob,
+			       cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob,
+			       cmp_par_fx_cob_variance, spillover_fx_cob_variance);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[2].exp_flags = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].exp_flags = 0x800000-1;
+	data_p[2].fx = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].fx = 0x80000000-1;
+	data_p[2].ncob_x = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].ncob_x = 0x3;
+	data_p[2].ncob_y = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].ncob_y = 0x3;
+	data_p[1].efx = 0x2;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].efx = 0x1;
+	data_p[1].ecob_x = 0x8;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].ecob_x = 0x7;
+	data_p[1].ecob_y = 0x8;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].ecob_y = 0x7;
+	data_p[0].fx_variance = 0x800000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].fx_variance = 0x800000-1;
+	data_p[2].cob_x_variance = 0x800;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].cob_x_variance = 0x800-1;
+	data_p[2].cob_y_variance = 0x800;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[2].cob_y_variance = 0x800-1;
+
+	max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_exp_flags = 32;
+	max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_fx = 32;
+	max_used_bits.l_ncob = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_ncob = 32;
+	max_used_bits.l_efx = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_efx = 32;
+	max_used_bits.l_ecob = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_ecob = 32;
+	max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.l_fx_variance = 32;
+	max_used_bits.l_cob_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_nc_offset
+ */
+
+void test_compress_nc_offset_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_mean = 1;
+	uint32_t spillover_mean = 2;
+	uint32_t cmp_par_variance = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_variance = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct nc_offset)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct nc_offset)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct nc_offset *data_p = (struct nc_offset *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.nc_offset_mean = 1;
+	max_used_bits.nc_offset_variance = 31;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_OFFSET, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[0].mean = 0x2;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].mean = 0x1;
+	data_p[1].variance = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].variance = 0x80000000-1;
+
+	max_used_bits.nc_offset_mean = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.nc_offset_mean = 32;
+	max_used_bits.nc_offset_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_nc_background
+ */
+
+void test_compress_nc_background_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_mean = 1;
+	uint32_t spillover_mean = 2;
+	uint32_t cmp_par_variance = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_variance = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint32_t cmp_par_pixels_error = 23;
+	uint32_t spillover_pixels_error = 42;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct nc_background)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct nc_background)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct nc_background *data_p = (struct nc_background *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.nc_background_mean = 1;
+	max_used_bits.nc_background_variance = 31;
+	max_used_bits.nc_background_outlier_pixels = 2;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_BACKGROUND, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[0].mean = 0x2;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].mean = 0x1;
+	data_p[1].variance = 0x80000000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].variance = 0x80000000-1;
+	data_p[1].outlier_pixels = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].outlier_pixels = 0x3;
+
+	max_used_bits.nc_background_mean = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.nc_background_mean = 32;
+	max_used_bits.nc_background_variance = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.nc_background_variance = 32;
+	max_used_bits.nc_background_outlier_pixels = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test compress_smearing
+ */
+
+void test_compress_smearing_error_cases(void)
+{
+	int error, cmp_bits, compressed_data_size;
+	struct cmp_cfg cfg = {0};
+	uint32_t cmp_par_mean = 1;
+	uint32_t spillover_mean = 2;
+	uint32_t cmp_par_variance = MAX_ICU_GOLOMB_PAR;
+	uint32_t spillover_variance = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR);
+	uint32_t cmp_par_pixels_error = 23;
+	uint32_t spillover_pixels_error = 42;
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct smearing)] = {0};
+	uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct smearing)] = {0};
+	struct cmp_max_used_bits max_used_bits = {0};
+	struct smearing *data_p = (struct smearing *)&data_to_compress[MULTI_ENTRY_HDR_SIZE];
+
+	max_used_bits.smearing_mean = 1;
+	max_used_bits.smearing_variance_mean = 15;
+	max_used_bits.smearing_outlier_pixels = 2;
+	cmp_set_max_used_bits(&max_used_bits);
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_SMEARING, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean,
+			    cmp_par_variance, spillover_variance,
+			    cmp_par_pixels_error, spillover_pixels_error);
+	TEST_ASSERT_FALSE(error);
+
+	compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL,
+						   (uint32_t *)compressed_data, 1);
+	TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size);
+
+	/* value is to big for the max used bits values */
+	data_p[0].mean = 0x2;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[0].mean = 0x1;
+	data_p[1].variance_mean = 0x8000;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].variance_mean = 0x8000-1;
+	data_p[1].outlier_pixels = 0x4;
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits);
+
+	data_p[1].outlier_pixels = 0x3;
+
+	max_used_bits.smearing_mean = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.smearing_mean = 32;
+	max_used_bits.smearing_variance_mean = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+
+	max_used_bits.smearing_variance_mean = 32;
+	max_used_bits.smearing_outlier_pixels = 33; /* more than 32 bits are not allowed */
+	cmp_set_max_used_bits(&max_used_bits);
+	cmp_bits = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_bits);
+}
+
+
+/**
+ * @test pad_bitstream
+ */
+
+void test_pad_bitstream(void)
+{
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+	int cmp_size_return;
+	uint32_t cmp_data[3];
+	const int MAX_BIT_LEN = 96;
+
+	memset(cmp_data, 0xFF, sizeof(cmp_data));
+	cfg.icu_output_buf = cmp_data;
+	cfg.data_type = DATA_TYPE_IMAGETTE; /* 16 bit samples */
+	cfg.buffer_length = 6; /* 6 * 16 bit samples -> 3 * 32 bit */
+
+	/* test negative cmp_size */
+	cmp_size = -1;
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(-1, cmp_size_return);
+	cmp_size = -3;
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(-3, cmp_size_return);
+
+	/* test RAW_MODE */
+	cfg.cmp_mode = CMP_MODE_RAW;
+	cmp_size = MAX_BIT_LEN;
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(MAX_BIT_LEN, cmp_size_return);
+	TEST_ASSERT_EQUAL_INT(cmp_data[0], 0xFFFFFFFF);
+	TEST_ASSERT_EQUAL_INT(cmp_data[1], 0xFFFFFFFF);
+	TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF);
+
+	/* test Normal operation */
+	cfg.cmp_mode = CMP_MODE_MODEL_MULTI;
+	cmp_size = 0;
+	/* set the first 32 bits zero no change should occur */
+	cmp_size = put_n_bits32(0, 32, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN);
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size, cmp_size_return);
+	TEST_ASSERT_EQUAL_INT(cmp_data[0], 0);
+	TEST_ASSERT_EQUAL_INT(cmp_data[1], 0xFFFFFFFF);
+	TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF);
+
+	/* set the first 33 bits zero; and checks the padding  */
+	cmp_size = put_n_bits32(0, 1, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN);
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size, cmp_size_return);
+	TEST_ASSERT_EQUAL_INT(cmp_data[0], 0);
+	TEST_ASSERT_EQUAL_INT(cmp_data[1], 0);
+	TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF);
+
+	/* set the first 63 bits zero; and checks the padding  */
+	cmp_data[1] = 0xFFFFFFFF;
+	cmp_size = 32;
+	cmp_size = put_n_bits32(0, 31, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN);
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size, cmp_size_return);
+	TEST_ASSERT_EQUAL_INT(cmp_data[0], 0);
+	TEST_ASSERT_EQUAL_INT(cmp_data[1], 0);
+	TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF);
+
+	/* error case the rest of the compressed data are to small dor a 32 bit
+	 * access  */
+	cfg.buffer_length = 5;
+	cmp_size = 64;
+	cmp_size = put_n_bits32(0, 1, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN);
+	cmp_size_return = pad_bitstream(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size_return);
+}
+
+
+/**
+ * @test cmp_data_to_big_endian
+ */
+
+void test_cmp_data_to_big_endian_error_cases(void)
+{
+	struct cmp_cfg cfg = {0};
+	int cmp_size;
+	int cmp_size_return;
+	uint16_t cmp_data[3] = {0x0123, 0x4567, 0x89AB};
+	uint8_t *p;
+
+	cfg.icu_output_buf = (uint32_t *)cmp_data;
+
+	/* this should work */
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_RAW;
+	cmp_size = 48;
+	cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size_return, 48);
+	p = (uint8_t *)cfg.icu_output_buf;
+	TEST_ASSERT_EQUAL(p[0], 0x01);
+	TEST_ASSERT_EQUAL(p[1], 0x23);
+	TEST_ASSERT_EQUAL(p[2], 0x45);
+	TEST_ASSERT_EQUAL(p[3], 0x67);
+	TEST_ASSERT_EQUAL(p[4], 0x89);
+	TEST_ASSERT_EQUAL(p[5], 0xAB);
+
+	/* error cases */
+	cmp_data[0] = 0x0123;
+	cmp_data[1] = 0x4567;
+	cmp_data[2] = 0x89AB;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_RAW;
+	cmp_size = 47; /* wrong size */
+	cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size_return, -1);
+
+	cmp_data[0] = 0x0123;
+	cmp_data[1] = 0x4567;
+	cmp_data[2] = 0x89AB;
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_RAW;
+	cmp_size = 49; /* wrong size */
+	cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size_return, -1);
+
+	cmp_data[0] = 0x0123;
+	cmp_data[1] = 0x4567;
+	cmp_data[2] = 0x89AB;
+	cfg.data_type = DATA_TYPE_UNKNOWN; /* wrong data_type */
+	cfg.cmp_mode = CMP_MODE_RAW;
+	cmp_size = 48;
+	cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size);
+	TEST_ASSERT_EQUAL_INT(cmp_size_return, -1);
+}
+
+
+/**
+ * @test icu_compress_data
+ */
+
+void test_icu_compress_data_error_cases(void)
+{
+	int cmp_size;
+	struct cmp_cfg cfg = {0};
+
+	/* cfg = NULL test */
+	cmp_size = icu_compress_data(NULL);
+	TEST_ASSERT_EQUAL(-1, cmp_size);
+
+	/* samples = 0 test */
+	cfg.samples = 0;
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL(0, cmp_size);
+}
+
diff --git a/test/cmp_icu/test_decmp.c b/test/cmp_icu/test_decmp.c
new file mode 100644
index 0000000000000000000000000000000000000000..6f2fe2df2451f456793b1017b548ce04ed01950c
--- /dev/null
+++ b/test/cmp_icu/test_decmp.c
@@ -0,0 +1,826 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "unity.h"
+
+#include "compiler.h"
+#include "cmp_debug.h"
+#include "cmp_entity.h"
+#include "../../lib/cmp_icu.c" /* .c file included to test static functions */
+#include "../../lib/decmp.c" /* .c file included to test static functions */
+
+
+#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
+#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX)
+
+
+/**
+ * @brief generate a uint32_t random number
+ *
+ * @return a "random" uint32_t value
+ * @see https://stackoverflow.com/a/33021408
+ */
+
+uint32_t rand32(void)
+{
+	int i;
+	uint32_t r = 0;
+
+	for (i = 0; i < 32; i += RAND_MAX_WIDTH) {
+		r <<= RAND_MAX_WIDTH;
+		r ^= (unsigned int) rand();
+	}
+	return r;
+}
+
+
+/**
+ * returns the needed size of the compression entry header plus the max size of the
+ * compressed data if ent ==  NULL if ent is set the size of the compression
+ * entry (entity header + compressed data)
+ */
+size_t icu_compress_data_entity(struct cmp_entity *ent, const struct cmp_cfg *cfg)
+{
+	size_t s;
+	struct cmp_cfg cfg_cpy;
+	int cmp_size_bits;
+
+	if (!cfg)
+		return 0;
+
+	if (cfg->icu_output_buf)
+		debug_print("Warning the set buffer for the compressed data is ignored! The compressed data are write to the compression entry.");
+
+	s = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type);
+	if (!s)
+		return 0;
+	/* we round down to the next 4-byte allied address because we access the
+	 * cmp_buffer in uint32_t words
+	 */
+	if (cfg->cmp_mode != CMP_MODE_RAW)
+		s &= ~0x3U;
+
+	s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, s);
+
+	if (!ent || !s)
+		return s;
+
+	cfg_cpy = *cfg;
+	cfg_cpy.icu_output_buf = cmp_ent_get_data_buf(ent);
+	if (!cfg_cpy.icu_output_buf)
+		return 0;
+	cmp_size_bits = icu_compress_data(&cfg_cpy);
+	if (cmp_size_bits < 0)
+		return 0;
+
+	/* XXX overwrite the size of the compression entity with the size of the actual
+	 * size of the compressed data; not all allocated memory is normally used */
+	s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW,
+			   cmp_bit_to_4byte(cmp_size_bits));
+
+	if (cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits))
+		return 0;
+
+
+	return s;
+}
+
+
+void test_cmp_decmp_n_imagette_raw(void)
+{
+	int cmp_size;
+	size_t s, i;
+	struct cmp_cfg cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 0, CMP_LOSSLESS);
+	uint16_t data[] = {0, 1, 2, 0x42, INT16_MIN, INT16_MAX, UINT16_MAX};
+	uint32_t *compressed_data;
+	uint16_t *decompressed_data;
+	struct cmp_entity *ent;
+
+	s = cmp_cfg_icu_buffers(&cfg, data, ARRAY_SIZE(data), NULL, NULL,
+				NULL, ARRAY_SIZE(data));
+	TEST_ASSERT_TRUE(s);
+	compressed_data = malloc(s);
+	TEST_ASSERT_TRUE(compressed_data);
+	s = cmp_cfg_icu_buffers(&cfg, data, ARRAY_SIZE(data), NULL, NULL,
+				compressed_data, ARRAY_SIZE(data));
+	TEST_ASSERT_TRUE(s);
+
+	cmp_size = icu_compress_data(&cfg);
+	TEST_ASSERT_EQUAL_INT(sizeof(data)*CHAR_BIT, cmp_size);
+
+	s = cmp_ent_build(NULL, 0, 0, 0, 0, 0, &cfg, cmp_bit_to_4byte(cmp_size));
+	TEST_ASSERT_TRUE(s);
+	ent = malloc(s);
+	TEST_ASSERT_TRUE(ent);
+	s = cmp_ent_build(ent, 0, 0, 0, 0, 0, &cfg, cmp_bit_to_4byte(cmp_size));
+	TEST_ASSERT_TRUE(s);
+	memcpy(cmp_ent_get_data_buf(ent), compressed_data, (cmp_size+7)/8);
+
+	s = decompress_cmp_entiy(ent, NULL, NULL, NULL);
+	TEST_ASSERT_EQUAL_INT(sizeof(data), s);
+	decompressed_data = malloc(s);
+	TEST_ASSERT_TRUE(decompressed_data);
+	s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(sizeof(data), s);
+
+	for (i = 0; i < ARRAY_SIZE(data); ++i) {
+		TEST_ASSERT_EQUAL_INT(data[i], decompressed_data[i]);
+
+	}
+
+	free(compressed_data);
+	free(ent);
+	free(decompressed_data);
+}
+
+
+/**
+ * @test count_leading_ones
+ */
+
+void test_count_leading_ones(void)
+{
+	unsigned int n_leading_bit;
+	uint32_t value;
+
+	value = 0;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(0, n_leading_bit);
+
+	value = 0x7FFFFFFF;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(0, n_leading_bit);
+
+	value = 0x80000000;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(1, n_leading_bit);
+
+	value = 0xBFFFFFFF;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(1, n_leading_bit);
+
+	value = 0xFFFF0000;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(16, n_leading_bit);
+
+	value = 0xFFFF7FFF;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(16, n_leading_bit);
+
+	value = 0xFFFFFFFF;
+	n_leading_bit = count_leading_ones(value);
+	TEST_ASSERT_EQUAL_INT(32, n_leading_bit);
+}
+
+
+/**
+ * @test rice_decoder
+ */
+
+void test_rice_decoder(void)
+{
+	int cw_len;
+	uint32_t code_word;
+	unsigned int m = ~0;  /* we don't need this value */
+	unsigned int log2_m;
+	unsigned int decoded_cw;
+
+	/* test log_2 to big */
+	code_word = 0xE0000000;
+	log2_m = 33;
+	cw_len = rice_decoder(code_word, m, log2_m, &decoded_cw);
+	TEST_ASSERT_EQUAL(0, cw_len);
+	log2_m = UINT_MAX;
+	cw_len = rice_decoder(code_word, m, log2_m, &decoded_cw);
+	TEST_ASSERT_EQUAL(0, cw_len);
+}
+
+
+/**
+ * @test re_map_to_pos
+ */
+
+void test_re_map_to_pos(void)
+{
+	int j;
+	uint32_t input, result;
+	unsigned int max_value_bits;
+
+	input = INT32_MIN;
+	result = re_map_to_pos(map_to_pos(input, 32));
+	TEST_ASSERT_EQUAL_INT32(input, result);
+
+	input = INT32_MAX;
+	result = re_map_to_pos(map_to_pos(input, 32));
+	TEST_ASSERT_EQUAL_INT32(input, result);
+
+	input = -1;
+	result = re_map_to_pos(map_to_pos(input, 32));
+	TEST_ASSERT_EQUAL_INT32(input, result);
+
+	input = 0;
+	result = re_map_to_pos(map_to_pos(input, 32));
+	TEST_ASSERT_EQUAL_INT32(input, result);
+
+	input = 1; max_value_bits = 6;
+	result = re_map_to_pos(map_to_pos(input, max_value_bits));
+	TEST_ASSERT_EQUAL_INT32(input, result);
+
+	for (j = -16; j < 15; j++) {
+		uint32_t map_val =  map_to_pos(j, 16) & 0x3F;
+		result = re_map_to_pos(map_val);
+		TEST_ASSERT_EQUAL_INT32(j, result);
+	}
+
+	for (j = INT16_MIN; j < INT16_MAX; j++) {
+		uint32_t map_val =  map_to_pos(j, 16) & 0xFFFF;
+		result = re_map_to_pos(map_val);
+		TEST_ASSERT_EQUAL_INT32(j, result);
+	}
+#if 0
+	for (j = INT32_MIN; j < INT32_MAX; j++) {
+		result = re_map_to_pos(map_to_pos(j, 32));
+		TEST_ASSERT_EQUAL_INT32(j, result);
+	}
+#endif
+}
+
+
+void test_decode_normal(void)
+{
+	uint32_t decoded_value = ~0;
+	int stream_pos, sample;
+	 /* compressed data from 0 to 6; */
+	uint32_t cmp_data[] = {0x5BBDF7E0};
+	struct decoder_setup setup = {0};
+
+	cpu_to_be32s(cmp_data);
+
+	setup.decode_cw_f = rice_decoder;
+	setup.encoder_par1 = 1;
+	setup.encoder_par2 = ilog_2(setup.encoder_par1);
+	setup.bitstream_adr = cmp_data;
+	setup.max_stream_len = 32;
+
+	stream_pos = 0;
+	for (sample = 0; sample < 7; sample++) {
+		stream_pos = decode_normal(&decoded_value, stream_pos, &setup);
+		TEST_ASSERT_EQUAL_HEX(sample, decoded_value);
+	}
+
+	 /* TODO error case: negative stream_pos */
+}
+
+
+void test_decode_zero(void)
+{
+	uint32_t decoded_value = ~0;
+	int stream_pos;
+	uint32_t cmp_data[] = {0x88449FE0};
+	struct decoder_setup setup = {0};
+	struct cmp_cfg cfg = {0};
+
+	cpu_to_be32s(cmp_data);
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_ZERO;
+	cfg.icu_output_buf = cmp_data;
+	cfg.buffer_length = 4;
+
+	int err = configure_decoder_setup(&setup, 1, 8, CMP_LOSSLESS, 16, &cfg);
+	TEST_ASSERT_FALSE(err);
+
+	stream_pos = 0;
+
+	stream_pos = decode_zero(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(0, decoded_value);
+	stream_pos = decode_zero(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(0x4223, decoded_value);
+	stream_pos = decode_zero(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(7, decoded_value);
+	TEST_ASSERT_EQUAL_INT(28, stream_pos);
+
+	 /* TODO error case: negativ stream_pos */
+}
+
+void test_decode_multi(void)
+{
+	uint32_t decoded_value = ~0;
+	int stream_pos;
+	uint32_t cmp_data[] = {0x16B66DF8, 0x84360000};
+	struct decoder_setup setup = {0};
+	struct cmp_cfg cfg = {0};
+
+	cpu_to_be32s(&cmp_data[0]);
+	cpu_to_be32s(&cmp_data[1]);
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_DIFF_MULTI;
+	cfg.icu_output_buf = cmp_data;
+	cfg.buffer_length = 8;
+
+	int err = configure_decoder_setup(&setup, 3, 8, CMP_LOSSLESS, 16, &cfg);
+	TEST_ASSERT_FALSE(err);
+
+	stream_pos = 0;
+
+	stream_pos = decode_multi(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(0, decoded_value);
+	stream_pos = decode_multi(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(1, decoded_value);
+	stream_pos = decode_multi(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(7, decoded_value);
+	stream_pos = decode_multi(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(8, decoded_value);
+	stream_pos = decode_multi(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(9, decoded_value);
+	stream_pos = decode_multi(&decoded_value, stream_pos, &setup);
+	TEST_ASSERT_EQUAL_HEX(0x4223, decoded_value);
+	TEST_ASSERT_EQUAL_INT(47, stream_pos);
+
+}
+
+
+void test_decompress_imagette_model(void)
+{
+	uint16_t data[5]  = {0};
+	uint16_t model[5] = {0, 1, 2, 3, 4};
+	uint16_t up_model[5]  = {0};
+	uint32_t cmp_data[] = {0};
+	struct cmp_cfg cfg = {0};
+	int stream_pos;
+
+	cmp_data[0] = cpu_to_be32(0x49240000);
+
+	cfg.data_type = DATA_TYPE_IMAGETTE;
+	cfg.cmp_mode = CMP_MODE_MODEL_MULTI;
+	cfg.input_buf = data;
+	cfg.model_buf = model;
+	cfg.icu_new_model_buf = up_model;
+	cfg.icu_output_buf = cmp_data;
+	cfg.buffer_length = 4;
+	cfg.samples = 5;
+	cfg.model_value = 16;
+	cfg.golomb_par = 4;
+	cfg.spill = 48;
+
+	stream_pos = decompress_imagette(&cfg);
+	TEST_ASSERT_EQUAL_INT(15, stream_pos);
+	TEST_ASSERT_EQUAL_HEX(1, data[0]);
+	TEST_ASSERT_EQUAL_HEX(2, data[1]);
+	TEST_ASSERT_EQUAL_HEX(3, data[2]);
+	TEST_ASSERT_EQUAL_HEX(4, data[3]);
+	TEST_ASSERT_EQUAL_HEX(5, data[4]);
+
+	TEST_ASSERT_EQUAL_HEX(0, up_model[0]);
+	TEST_ASSERT_EQUAL_HEX(1, up_model[1]);
+	TEST_ASSERT_EQUAL_HEX(2, up_model[2]);
+	TEST_ASSERT_EQUAL_HEX(3, up_model[3]);
+	TEST_ASSERT_EQUAL_HEX(4, up_model[4]);
+}
+
+
+
+#define DATA_SAMPLES 5
+void test_cmp_decmp_s_fx_diff(void)
+{
+	size_t s;
+	int err;
+
+	struct cmp_entity *ent;
+	const uint32_t MAX_VALUE = ~(~0U << MAX_USED_S_FX_BITS);
+	struct s_fx data_entry[DATA_SAMPLES] = {
+		{0,0}, {1,23}, {2,42}, {3,MAX_VALUE}, {3,MAX_VALUE>>1} };
+	uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE + sizeof(data_entry)];
+	struct s_fx *decompressed_data = NULL;
+	/* uint32_t *compressed_data = NULL; */
+	uint32_t compressed_data_len_samples = DATA_SAMPLES;
+	struct cmp_cfg cfg;
+
+	for (s = 0; s < MULTI_ENTRY_HDR_SIZE; s++)
+		data_to_compress[s] = s;
+	memcpy(&data_to_compress[MULTI_ENTRY_HDR_SIZE], data_entry, sizeof(data_entry));
+
+	cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_DIFF_MULTI,
+				 CMP_PAR_UNUSED, CMP_LOSSLESS);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+	s = cmp_cfg_icu_buffers(&cfg, data_to_compress, DATA_SAMPLES, NULL, NULL,
+				NULL, compressed_data_len_samples);
+	TEST_ASSERT_TRUE(s);
+
+	err = cmp_cfg_fx_cob(&cfg, 2, 6, 4, 14, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			     CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED,
+			     CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED);
+	TEST_ASSERT_FALSE(err);
+
+	s = icu_compress_data_entity(NULL, &cfg);
+	TEST_ASSERT_TRUE(s);
+	ent = malloc(s); TEST_ASSERT_TRUE(ent);
+	s = icu_compress_data_entity(ent, &cfg);
+	TEST_ASSERT_TRUE(s);
+
+	/* now decompress the data */
+	s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(cmp_cal_size_of_data(cfg.samples, cfg.data_type), s);
+	decompressed_data = malloc(s); TEST_ASSERT_TRUE(decompressed_data);
+	s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(cmp_cal_size_of_data(cfg.samples, cfg.data_type), s);
+
+	TEST_ASSERT_FALSE(memcmp(data_to_compress, decompressed_data, s));
+	/* for (i = 0; i < samples; ++i) { */
+	/* 	printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round); */
+	/* 	uint32_t mask = ~0U << round; */
+	/* 	if ((data[i]&mask) != (decompressed_data[i]&mask)) */
+	/* 		TEST_ASSERT(0); */
+	/* 	if (model_mode_is_used(cmp_mode)) */
+	/* 		if (up_model[i] != de_up_model[i]) */
+	/* 			TEST_ASSERT(0); */
+	/* } */
+}
+#undef DATA_SAMPLES
+
+
+int my_random(unsigned int min, unsigned int max)
+{
+	TEST_ASSERT(min < max);
+	if (max-min < RAND_MAX)
+		return min + rand() / (RAND_MAX / (max - min + 1ULL) + 1);
+	else
+		return min + rand32() / (UINT32_MAX / (max - min + 1ULL) + 1);
+
+}
+
+/* #include <cmp_io.h> */
+/* void test_imagette_1(void) */
+/* { */
+/* 	size_t i; */
+
+/* 	enum cmp_mode cmp_mode = 1; */
+/* 	uint16_t model_value = 10; */
+/* 	struct cmp_cfg cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, cmp_mode, model_value, CMP_LOSSLESS); */
+/* 	unsigned int samples = 1; */
+/* 	uint16_t data[1] = {0x8000}; */
+/* 	uint16_t model[1] = {0}; */
+/* 	uint16_t up_model[1] = {0}; */
+/* 	uint16_t de_up_model[1] = {0}; */
+/* 	uint32_t compressed_data[1]; */
+
+/* 	size_t s = cmp_cfg_buffers(&cfg, data, samples, model, up_model, */
+/* 			      compressed_data, 2*samples); */
+/* 	TEST_ASSERT(s > 0); */
+
+/* 	uint32_t golomb_par = 9; */
+/* 	uint32_t spill = 44; */
+
+/* 	cfg.spill = spill; */
+/* 	cfg.golomb_par = golomb_par; */
+/* 	/1* print_cfg(&cfg, 0); *1/ */
+/* 	int cmp_size = icu_compress_data(&cfg, NULL); */
+/* 	TEST_ASSERT(cmp_size > 0); */
+
+
+/* 	s = cmp_ent_build(NULL, 0, 0, 0, 0, 0, &cfg, cmp_size); */
+/* 	TEST_ASSERT_TRUE(s); */
+/* 	struct cmp_entity *ent = malloc(s); */
+/* 	TEST_ASSERT_TRUE(ent); */
+/* 	s = cmp_ent_build(ent, 0, 0, 0, 0, 0, &cfg, cmp_size); */
+/* 	TEST_ASSERT_TRUE(s); */
+/* 	memcpy(cmp_ent_get_data_buf(ent), compressed_data, cmp_bit_to_4byte(cmp_size)); */
+
+/* 	s = decompress_cmp_entiy(ent, model, de_up_model, NULL); */
+/* 	TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s); */
+/* 	uint16_t *decompressed_data = malloc(s); */
+/* 	TEST_ASSERT_TRUE(decompressed_data); */
+/* 	s = decompress_cmp_entiy(ent, model, de_up_model, decompressed_data); */
+/* 	TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s); */
+
+/* 	for (i = 0; i < samples; ++i) { */
+/* 		if (data[i] != decompressed_data[i]) */
+/* 			TEST_ASSERT(0); */
+/* 		/1* TEST_ASSERT_EQUAL_HEX16(data[i], decompressed_data[i]); *1/ */
+/* 		/1* TEST_ASSERT_EQUAL_HEX16(up_model[i], de_up_model[i]); *1/ */
+/* 	} */
+
+
+/* 	free(ent); */
+/* 	free(decompressed_data); */
+/* } */
+
+#include <unistd.h>
+#include "cmp_io.h"
+
+void test_imagette_random(void)
+{
+	unsigned int seed = time(NULL) * getpid();
+	size_t i, s, cmp_data_size;
+	int error;
+	struct cmp_cfg cfg;
+	struct cmp_entity *ent;
+
+	enum cmp_mode cmp_mode = my_random(0, 4);
+	enum cmp_data_type data_type = DATA_TYPE_IMAGETTE;
+	uint16_t model_value = my_random(0, MAX_MODEL_VALUE);
+	uint32_t round = my_random(0, 3);
+	uint32_t samples, compressed_data_len_samples;
+	uint16_t *data, *model = NULL, *up_model = NULL, *de_up_model = NULL;
+
+	/* Seeds the pseudo-random number generator used by rand() */
+	srand(seed);
+	printf("seed: %u\n", seed);
+
+	/* create random test _data */
+	samples = my_random(1, 100000);
+	s = cmp_cal_size_of_data(samples, data_type);
+	data = malloc(s); TEST_ASSERT_TRUE(data);
+	for (i = 0; i < samples; ++i) {
+		data[i] = my_random(0, UINT16_MAX);
+	}
+	if (model_mode_is_used(cmp_mode)) {
+		model = malloc(s); TEST_ASSERT_TRUE(model);
+		up_model = malloc(s); TEST_ASSERT_TRUE(up_model);
+		de_up_model = malloc(s); TEST_ASSERT(de_up_model);
+		for (i = 0; i < samples; ++i) {
+			model[i] = my_random(0, UINT16_MAX);
+		}
+	}
+	compressed_data_len_samples = 6*samples;
+
+	/* create a compression configuration */
+	cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, round);
+	TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN);
+
+
+	cmp_data_size = cmp_cfg_icu_buffers(&cfg, data, samples, model, up_model,
+					    NULL, compressed_data_len_samples);
+	TEST_ASSERT_TRUE(cmp_data_size);
+
+	uint32_t golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+	uint32_t max_spill = cmp_ima_max_spill(golomb_par);
+	TEST_ASSERT(max_spill > 1);
+	uint32_t spill = my_random(2, max_spill);
+
+	error = cmp_cfg_icu_imagette(&cfg, golomb_par, spill);
+	TEST_ASSERT_FALSE(error);
+
+	/* print_cfg(&cfg, 0); */
+	s = icu_compress_data_entity(NULL, &cfg);
+	TEST_ASSERT_TRUE(s);
+	ent = malloc(s); TEST_ASSERT_TRUE(ent);
+	s = icu_compress_data_entity(ent, &cfg);
+	TEST_ASSERT_TRUE(s);
+
+	s = decompress_cmp_entiy(ent, model, de_up_model, NULL);
+	TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s);
+	uint16_t *decompressed_data = malloc(s);
+	TEST_ASSERT_TRUE(decompressed_data);
+	s = decompress_cmp_entiy(ent, model, de_up_model, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s);
+
+	for (i = 0; i < samples; ++i) {
+		/* printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round); */
+		uint32_t mask = ~0U << round;
+		if ((data[i]&mask) != (decompressed_data[i]&mask))
+			TEST_ASSERT(0);
+		if (model_mode_is_used(cmp_mode))
+			if (up_model[i] != de_up_model[i])
+				TEST_ASSERT(0);
+	}
+
+	free(data);
+	free(model);
+	free(up_model);
+	free(de_up_model);
+	free(ent);
+	free(decompressed_data);
+}
+
+
+void test_s_fx_diff(void)
+{
+	size_t s, i;
+	uint8_t cmp_entity[88] = {
+		0x80, 0x00, 0x00, 0x09, 0x00, 0x00, 0x58, 0x00, 0x00, 0x20, 0x04, 0xEE, 0x21, 0xBD, 0xB0, 0x1C, 0x04, 0xEE, 0x21, 0xBD, 0xB0, 0x41, 0x00, 0x08, 0x02, 0x08, 0xD0, 0x10, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xAE, 0xDE, 0x00, 0x00, 0x00, 0x73, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00,
+	};
+
+	uint8_t result_data[32] = {0};
+	struct multi_entry_hdr *hdr = (struct multi_entry_hdr *)result_data;
+	struct s_fx *data = (struct s_fx *)hdr->entry;
+	/* put some dummy data in the header*/
+	for (i = 0; i < sizeof(*hdr); ++i)
+		result_data[i] = i;
+	data[0].exp_flags = 0;
+	data[0].fx = 0;
+	data[1].exp_flags = 1;
+	data[1].fx = 0xFFFFFF;
+	data[2].exp_flags = 3;
+	data[2].fx = 0x7FFFFF;
+	data[3].exp_flags = 0;
+	data[3].fx = 0;
+
+	s = decompress_cmp_entiy((void *)cmp_entity, NULL, NULL, NULL);
+	TEST_ASSERT_EQUAL_INT(sizeof(result_data), s);
+	uint8_t *decompressed_data = malloc(s);
+	TEST_ASSERT_TRUE(decompressed_data);
+	s = decompress_cmp_entiy((void *)cmp_entity, NULL, NULL, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(sizeof(result_data), s);
+	for (i = 0; i < s; ++i) {
+		TEST_ASSERT_EQUAL(result_data[i], decompressed_data[i]);
+	}
+}
+
+
+void test_s_fx_model(void)
+{
+	size_t s, i;
+	uint8_t compressed_data_buf[92] = {
+		0x80, 0x00, 0x00, 0x09, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x20, 0x04, 0xF0, 0xC2, 0xD3, 0x47, 0xE4, 0x04, 0xF0, 0xC2, 0xD3, 0x48, 0x16, 0x00, 0x08, 0x03, 0x08, 0xD0, 0x10, 0x01, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x3B, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x5B, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x5D, 0x80, 0x00, 0x00,
+	};
+	struct cmp_entity * cmp_entity = (struct cmp_entity *)compressed_data_buf;
+
+	uint8_t model_buf[32];
+	uint8_t decompressed_data[32];
+	uint8_t up_model_buf[32];
+	uint8_t exp_data_buf[32] = {0}; /* expected uncompressed data */
+	uint8_t exp_up_model_buf[32] = {0};
+
+	struct multi_entry_hdr *model_collection = (struct multi_entry_hdr *)model_buf;
+	struct s_fx *model_data = (struct s_fx *)model_collection->entry;
+
+	memset(model_collection, 0xFF, sizeof(*model_collection));
+	model_data[0].exp_flags = 0;
+	model_data[0].fx = 0;
+	model_data[1].exp_flags = 3;
+	model_data[1].fx = 0x7FFFFF;
+	model_data[2].exp_flags = 0;
+	model_data[2].fx = 0xFFFFFF;
+	model_data[3].exp_flags = 3;
+	model_data[3].fx = 0xFFFFFF;
+
+	struct multi_entry_hdr *exp_data_collection = (struct multi_entry_hdr *)exp_data_buf;
+	struct s_fx *exp_data = (struct s_fx *)exp_data_collection->entry;
+	/* put some dummy data in the header */
+	for (i = 0; i < sizeof(*exp_data_collection); i++)
+		exp_data_buf[i] = i;
+	exp_data[0].exp_flags = 0;
+	exp_data[0].fx = 0;
+	exp_data[1].exp_flags = 1;
+	exp_data[1].fx = 0xFFFFFF;
+	exp_data[2].exp_flags = 3;
+	exp_data[2].fx = 0x7FFFFF;
+	exp_data[3].exp_flags = 0;
+	exp_data[3].fx = 0;
+
+	struct multi_entry_hdr *exp_up_model_collection = (struct multi_entry_hdr *)exp_up_model_buf;
+	struct s_fx *exp_updated_model_data = (struct s_fx *)exp_up_model_collection->entry;
+	/* put some dummy data in the header*/
+	for (i = 0; i < sizeof(*exp_up_model_collection); i++)
+		exp_up_model_buf[i] = i;
+	exp_updated_model_data[0].exp_flags = 0;
+	exp_updated_model_data[0].fx = 0;
+	exp_updated_model_data[1].exp_flags = 2;
+	exp_updated_model_data[1].fx = 0xBFFFFF;
+	exp_updated_model_data[2].exp_flags = 1;
+	exp_updated_model_data[2].fx = 0xBFFFFF;
+	exp_updated_model_data[3].exp_flags = 1;
+	exp_updated_model_data[3].fx = 0x7FFFFF;
+
+	s = decompress_cmp_entiy(cmp_entity, model_buf, up_model_buf, decompressed_data);
+	TEST_ASSERT_EQUAL_INT(sizeof(exp_data_buf), s);
+
+	TEST_ASSERT_FALSE(memcmp(exp_data_buf, decompressed_data, s));
+	TEST_ASSERT_FALSE(memcmp(exp_up_model_buf, up_model_buf, s));
+}
+
+/* TODO: implement this! */
+void generate_random_test_data(void *data, int samples,
+			       enum cmp_data_type data_type)
+{
+	int s = cmp_cal_size_of_data(samples, data_type);
+	memset(data, 0x0, s);
+}
+
+
+void test_random_compression_decompression(void)
+{
+	size_t s;
+	struct cmp_cfg cfg = {0};
+	struct cmp_entity *cmp_ent;
+	void *decompressed_data;
+	void *decompressed_up_model = NULL;
+
+	srand(0); /* TODO:XXX*/
+	puts("--------------------------------------------------------------");
+
+	/* for (cfg.data_type = DATA_TYPE_IMAGETTE; TODO:!! implement this */
+	/*      cfg.data_type < DATA_TYPE_F_CAM_BACKGROUND+1; cfg.data_type++) { */
+	for (cfg.data_type = DATA_TYPE_IMAGETTE;
+	     cfg.data_type < DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE+1; cfg.data_type++) {
+		cfg.samples = my_random(1,0x30000);
+			if (cfg.data_type == DATA_TYPE_OFFSET)
+				puts("FADF");
+
+		cfg.buffer_length = (CMP_ENTITY_MAX_SIZE - NON_IMAGETTE_HEADER_SIZE - MULTI_ENTRY_HDR_SIZE)/size_of_a_sample(cfg.data_type);;
+		s = cmp_cal_size_of_data(cfg.samples, cfg.data_type);
+		printf("%s\n", data_type2string(cfg.data_type));
+		TEST_ASSERT_TRUE(s);
+		cfg.input_buf = calloc(1, s);
+		TEST_ASSERT_NOT_NULL(cfg.input_buf);
+		cfg.model_buf = calloc(1, s);
+		TEST_ASSERT_TRUE(cfg.model_buf);
+		decompressed_data = calloc(1, s);
+		TEST_ASSERT_NOT_NULL(decompressed_data);
+		cfg.icu_new_model_buf = calloc(1, s);
+		TEST_ASSERT_TRUE(cfg.icu_new_model_buf);
+		decompressed_up_model = calloc(1, s);
+		TEST_ASSERT_TRUE(decompressed_up_model);
+		cmp_ent = calloc(1, CMP_ENTITY_MAX_SIZE);
+
+		generate_random_test_data(cfg.input_buf, cfg.samples, cfg.data_type);
+		generate_random_test_data(cfg.model_buf, cfg.samples, cfg.data_type);
+
+		cfg.model_value = my_random(0,16);
+		/* cfg.round = my_random(0,3); /1* XXX *1/ */
+		cfg.round = 0;
+
+		cfg.golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+		cfg.ap1_golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+		cfg.ap2_golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+		cfg.cmp_par_exp_flags = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_fx = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_ncob = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_efx = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_ecob = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_fx_cob_variance = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_mean = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_variance = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+		cfg.cmp_par_pixels_error = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+
+		cfg.spill = my_random(MIN_IMA_SPILL, cmp_ima_max_spill(cfg.golomb_par));
+		cfg.ap1_spill = my_random(MIN_IMA_SPILL, cmp_ima_max_spill(cfg.ap1_golomb_par));
+		cfg.ap2_spill = my_random(MIN_IMA_SPILL, cmp_ima_max_spill(cfg.ap2_golomb_par));
+		if (!rdcu_supported_data_type_is_used(cfg.data_type)) {
+			cfg.spill_exp_flags = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_exp_flags));
+			cfg.spill_fx = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_fx));
+			cfg.spill_ncob = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_ncob));
+			cfg.spill_efx = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_efx));
+			cfg.spill_ecob = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_ecob));
+			cfg.spill_fx_cob_variance = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_fx_cob_variance));
+			cfg.spill_mean = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_mean));
+			cfg.spill_variance = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_variance));
+			cfg.spill_pixels_error = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_pixels_error));
+		}
+
+		for (cfg.cmp_mode = CMP_MODE_RAW; cfg.cmp_mode < CMP_MODE_STUFF; cfg.cmp_mode++) {
+			int cmp_size, decompress_size;
+
+			cmp_size = icu_compress_data_entity(cmp_ent, &cfg);
+			if (cmp_size <= 0) {
+				printf("cmp_size: %i\n", cmp_size);
+				print_cfg(&cfg, 0);
+			}
+			TEST_ASSERT_GREATER_THAN(0, cmp_size);
+
+			/* now decompress the data */
+			decompress_size = decompress_cmp_entiy(cmp_ent, cfg.model_buf,
+							       decompressed_up_model, decompressed_data);
+
+			TEST_ASSERT_EQUAL_INT(s, decompress_size);
+			if (memcmp(cfg.input_buf, decompressed_data, s)) {
+				print_cfg(&cfg, 0);
+				TEST_ASSERT_FALSE(memcmp(cfg.input_buf, decompressed_data, s));
+			}
+			if (model_mode_is_used(cfg.cmp_mode))
+				TEST_ASSERT_FALSE(memcmp(cfg.icu_new_model_buf, decompressed_up_model, s));
+
+			memset(cmp_ent, 0, CMP_ENTITY_MAX_SIZE);
+			memset(decompressed_data, 0, s);
+			memset(decompressed_up_model, 0, s);
+			memset(cfg.icu_new_model_buf, 0, s);
+		}
+
+		free(cfg.model_buf);
+		cfg.model_buf = NULL;
+		free(cfg.input_buf);
+		cfg.input_buf = NULL;
+		free(cfg.icu_new_model_buf);
+		cfg.icu_new_model_buf = NULL;
+		free(cmp_ent);
+		cmp_ent = NULL;
+		free(decompressed_data);
+		decompressed_data = NULL;
+		free(decompressed_up_model);
+		decompressed_up_model = NULL;
+
+	}
+}
+
+void test_decompression_error_cases(void)
+{
+	/* error cases model decompression without a model Buffer */
+	/* error cases wrong cmp parameter; model value; usw */
+}
diff --git a/test/cmp_tool/Makefile b/test/cmp_tool/Makefile
deleted file mode 100644
index 543ea135a4f15e10d25440b3a7e17c9d3e1b41ff..0000000000000000000000000000000000000000
--- a/test/cmp_tool/Makefile
+++ /dev/null
@@ -1,25 +0,0 @@
-CC               = gcc
-SOURCEDIR	 =
-INCLUDES         = -I../../include
-PATH            +=
-CFLAGS          := -O0 -W -Wall -Wextra -std=gnu99 -Werror -pedantic -g3\
-		-fprofile-arcs -ftest-coverage
-CPPFLAGS        := -D__MAIN__ $(INCLUDES) -I$(SOURCEDIR)
-LDFLAGS         := -lcunit
-SOURCES         := $(wildcard *.c) ../../lib/cmp_tool_lib.c ../../lib/cmp_guess.c\
-		../../lib/cmp_support.c ../../lib/cmp_icu.c ../../lib/cmp_data_types.c
-OBJECTS         := $(patsubst %.c, $(BUILDDIR)/%.o, $(subst $(SOURCEDIR)/,, $(SOURCES)))
-TARGET          := test_cmp_tool
-
-
-all: $(SOURCES)
-	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $(TARGET)
-
-coverage: all
-	./$(TARGET)
-	lcov --rc lcov_branch_coverage=1 --capture --directory ./ --output-file coverage.info
-	genhtml --rc lcov_branch_coverage=1 --branch-coverage coverage.info --output-directory out
-	#firefox out/index.html
-
-clean:
-	rm -r $(TARGET) *.gcno *.gcda coverage.info out/ tmp_stderr.log
diff --git a/test/cmp_tool/cmp_tool_integration_test.py b/test/cmp_tool/cmp_tool_integration_test.py
old mode 100644
new mode 100755
index f5a022b3538c3e280383eb2af22368bc3201a701..7d58943afab15702f38a6142e43de20de4118b6c
--- a/test/cmp_tool/cmp_tool_integration_test.py
+++ b/test/cmp_tool/cmp_tool_integration_test.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+import pytest
 import subprocess
 import shlex
 import sys
@@ -12,6 +14,7 @@ PATH_CMP_TOOL = "./cmp_tool"
 EXIT_FAILURE = 1
 EXIT_SUCCESS = 0
 
+DATA_TYPE_IMAGETTE  = 1
 
 GENERIC_HEADER_SIZE = 32
 IMAGETTE_HEADER_SIZE = GENERIC_HEADER_SIZE+4
@@ -213,10 +216,7 @@ CMP_START_STR = \
 """#########################################################
 ### PLATO Compression/Decompression Tool Version %s ###
 #########################################################
-Info: Note that the behaviour of the cmp_tool has changed. From now on, the compressed data will be preceded by a header by default. The old behaviour can be achieved with the --no_header option.
-
 """ % (VERSION)
-print(CMP_START_STR)
 
 CMP_START_STR_CMP = CMP_START_STR + "## Starting the compression ##\n"
 CMP_START_STR_DECMP = CMP_START_STR + "## Starting the decompression ##\n"
@@ -277,8 +277,8 @@ def test_print_diff_cfg():
     args = ['--diff_cfg', '--diff_cfg -a', '--diff_cfg --rdcu_par']
     for i, arg in enumerate(args):
         returncode, stdout, stderr = call_cmp_tool(arg)
-        assert(returncode == EXIT_SUCCESS)
         assert(stderr == "")
+        assert(returncode == EXIT_SUCCESS)
 
         cfg = parse_key_value(stdout)
         assert(cfg['cmp_mode'] == '2')
@@ -368,8 +368,8 @@ def test_compression_diff():
         # generate test configuration
         with open(cfg_file_name, 'w', encoding='utf-8') as f:
             returncode, stdout, stderr = call_cmp_tool("--diff_cfg")
-            assert(returncode == EXIT_SUCCESS)
             assert(stderr == "")
+            assert(returncode == EXIT_SUCCESS)
             f.write(stdout)
 
         add_args = [" --no_header", ""]
@@ -379,8 +379,8 @@ def test_compression_diff():
                 " -c "+cfg_file_name+" -d "+data_file_name + " -o "+output_prefix+add_arg)
 
             # check compression results
-            assert(returncode == EXIT_SUCCESS)
             assert(stderr == "")
+            assert(returncode == EXIT_SUCCESS)
             assert(stdout == CMP_START_STR_CMP +
                    "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
                    "Importing data file %s ... \n" % (data_file_name) +
@@ -410,14 +410,13 @@ def test_compression_diff():
                     assert(info['cmp_size'] == '20')
                     assert(info['cmp_err'] == '0')
                 else:
-                    # import pdb; pdb.set_trace()
                     header = read_in_cmp_header(f.read())
                     assert(header['asw_version_id']['value'] == VERSION)
                     assert(header['cmp_ent_size']['value'] == IMAGETTE_HEADER_SIZE+4)
                     assert(header['original_size']['value'] == 10)
                     # todo
                     assert(header['start_time']['value'] < cuc_timestamp(datetime.utcnow()))
-                    #todo
+                    # todo
                     assert(header['end_timestamp']['value'] < cuc_timestamp(datetime.utcnow()))
                     assert(header['data_type']['value'] == 1)
                     assert(header['cmp_mode_used']['value'] == 2)
@@ -429,7 +428,7 @@ def test_compression_diff():
                     assert(header['golomb_par_used']['value'] == 7)
                     assert(header['compressed_data']['value'] == "44444000")
 
-                # decompression
+            # decompression
             if add_arg == " --no_header":
                 returncode, stdout, stderr = call_cmp_tool(
                     " -i "+output_prefix+".info -d "+output_prefix+".cmp -o "+output_prefix)
@@ -442,8 +441,8 @@ def test_compression_diff():
                    "%s" % ((lambda arg : "Importing decompression information file %s.info ... DONE\n" % (output_prefix)
                             if "--no_header" in arg else "")(add_arg)) +
                    "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix) +
-                   "%s" % ((lambda arg : "Parse the compression entity header ... DONE\n"
-                            if not "--no_header" in arg else "")(add_arg)) +
+                   # "%s" % ((lambda arg : "Parse the compression entity header ... DONE\n"
+                   #          if not "--no_header" in arg else "")(add_arg)) +
                    "Decompress data ... DONE\n" +
                    "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix))
 
@@ -460,7 +459,7 @@ def test_compression_diff():
         del_file(output_prefix+'.dat')
 
 
-def test_model_compression_no_header():
+def test_model_compression():
     # generate test data
     data = '00 01 00 02 00 03 00 04 00 05 \n'
     model = '00 00 00 01 00 02 00 03 00 04 \n'
@@ -482,62 +481,93 @@ def test_model_compression_no_header():
             assert(stderr == "")
             cfg = parse_key_value(stdout)
             cfg['cmp_mode'] = 'MODE_MODEL_MULTI'
+            cfg['model_value'] = '0'
             cfg["samples"] = '5'
             cfg["buffer_length"] = '2'
             for key, value in cfg.items():
                 f.write(key + ' = ' + str(value) + '\n')
 
-        # compression
-        returncode, stdout, stderr = call_cmp_tool(
-            " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix1+" --no_header")
+        add_args = [" --no_header", ""]
+        for add_arg in add_args:
+            print("Remove this", add_arg)
+            # compression
+            returncode, stdout, stderr = call_cmp_tool(
+                " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix1+ add_arg)
 
-        # check compression results
-        assert(returncode == EXIT_SUCCESS)
-        assert(stderr == "")
-        assert(stdout == CMP_START_STR_CMP +
-               "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
-               "Importing data file %s ... DONE\n" % (data_file_name) +
-               "Importing model file %s ... DONE\n" % (model_file_name) +
-               "Compress data ... DONE\n" +
-               "Write compressed data to file %s.cmp ... DONE\n" % (output_prefix1) +
-               "Write decompression information to file %s.info ... DONE\n" % (output_prefix1) +
-               "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix1))
-        # check compressed data
-        with open(output_prefix1+".cmp", encoding='utf-8') as f:
-            assert(f.read() == "49 24 00 00 \n")
-        # check info file
-        with open(output_prefix1+".info", encoding='utf-8') as f:
-            info = parse_key_value(f.read())
-        assert(info['cmp_mode_used'] == '3')
-        assert(info['model_value_used'] == cfg['model_value'])
-        assert(info['round_used'] == cfg['round'])
-        assert(info['spill_used'] == cfg['spill'])
-        assert(info['golomb_par_used'] == cfg['golomb_par'])
-        assert(info['samples_used'] == cfg['samples'])
-        assert(info['cmp_size'] == '15')
-        assert(info['cmp_err'] == '0')
-
-        # decompression
-        returncode, stdout, stderr = call_cmp_tool(
-            " -i "+output_prefix1+".info -d "+output_prefix1+".cmp -m "+model_file_name+" -o "+output_prefix2)
-        assert(returncode == EXIT_SUCCESS)
-        assert(stdout == CMP_START_STR_DECMP +
-               "Importing decompression information file %s.info ... DONE\n" % (output_prefix1) +
-               "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix1) +
-               "Importing model file %s ... DONE\n" % (model_file_name) +
-               "Decompress data ... DONE\n" +
-               "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix2) +
-               "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix2))
-        assert(stderr == "")
-        # check compressed data
+            # check compression results
+            assert(stderr == "")
+            assert(stdout == CMP_START_STR_CMP +
+                   "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
+                   "Importing data file %s ... DONE\n" % (data_file_name) +
+                   "Importing model file %s ... DONE\n" % (model_file_name) +
+                   "Compress data ... DONE\n" +
+                   "Write compressed data to file %s.cmp ... DONE\n" % (output_prefix1) +
+                   "%s" % ((lambda arg : "Write decompression information to file %s.info ... DONE\n" % (output_prefix1)
+                            if arg == " --no_header" else "")(add_arg)) +
+                   "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix1)
+            )
+            assert(returncode == EXIT_SUCCESS)
+
+            if add_arg == " --no_header":
+                # check compressed data
+                with open(output_prefix1+".cmp", encoding='utf-8') as f:
+                    assert(f.read() == "49 24 00 00 \n")
+                # check info file
+                with open(output_prefix1+".info", encoding='utf-8') as f:
+                    info = parse_key_value(f.read())
+                assert(info['cmp_mode_used'] == '3')
+                assert(info['model_value_used'] == cfg['model_value'])
+                assert(info['round_used'] == cfg['round'])
+                assert(info['spill_used'] == cfg['spill'])
+                assert(info['golomb_par_used'] == cfg['golomb_par'])
+                assert(info['samples_used'] == cfg['samples'])
+                assert(info['cmp_size'] == '15')
+                assert(info['cmp_err'] == '0')
+            else:
+                with open(output_prefix1+".cmp", encoding='utf-8') as f:
+                    header = read_in_cmp_header(f.read())
+                assert(header['asw_version_id']['value'] == VERSION)
+                assert(header['cmp_ent_size']['value'] == IMAGETTE_HEADER_SIZE+4)
+                assert(header['original_size']['value'] == 10)
+                # todo
+                assert(header['start_time']['value'] < cuc_timestamp(datetime.utcnow()))
+                #todo
+                assert(header['end_timestamp']['value'] < cuc_timestamp(datetime.utcnow()))
+                assert(header['data_type']['value'] == DATA_TYPE_IMAGETTE)
+                assert(header['cmp_mode_used']['value'] == 3)
+                assert(header['model_value_used']['value'] == int(cfg['model_value']))
+                assert(header['model_id']['value'] == 53264)
+                assert(header['model_counter']['value'] == 1)
+                assert(header['lossy_cmp_par_used']['value'] == int(cfg['round']))
+                assert(header['spill_used']['value'] == int(cfg['spill']))
+                assert(header['golomb_par_used']['value'] == int(cfg['golomb_par']))
+                assert(header['compressed_data']['value'] == "49240000")
 
-        with open(output_prefix2+".dat", encoding='utf-8') as f:
-            assert(f.read() == data)
+            # decompression
+            if add_arg == " --no_header":
+                returncode, stdout, stderr = call_cmp_tool(
+                    " -i "+output_prefix1+".info -d "+output_prefix1+".cmp -m "+model_file_name+" -o "+output_prefix2)
+            else:
+                returncode, stdout, stderr = call_cmp_tool("-d "+output_prefix1+".cmp -m "+model_file_name+" -o "+output_prefix2)
+            assert(stderr == "")
+            assert(stdout == CMP_START_STR_DECMP +
+                   "%s" % ((lambda arg : "Importing decompression information file %s.info ... DONE\n" % (output_prefix1)
+                            if "--no_header" in arg else "")(add_arg)) +
+                   "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix1) +
+                   "Importing model file %s ... DONE\n" % (model_file_name) +
+                   "Decompress data ... DONE\n" +
+                   "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix2) +
+                   "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix2))
+            assert(returncode == EXIT_SUCCESS)
+            # check compressed data
+
+            with open(output_prefix2+".dat", encoding='utf-8') as f:
+                assert(f.read() == data)
 
-        with open(output_prefix1+"_upmodel.dat", encoding='utf-8') as f1:
-            with open(output_prefix2+"_upmodel.dat", encoding='utf-8') as f2:
-                assert(f1.read() == f2.read() ==
-                       '00 00 00 01 00 02 00 03 00 04 \n')
+            with open(output_prefix1+"_upmodel.dat", encoding='utf-8') as f1:
+                with open(output_prefix2+"_upmodel.dat", encoding='utf-8') as f2:
+                    assert(f1.read() == f2.read() == data) # upmodel == data -> model_value = 0
+                           # '00 00 00 01 00 02 00 03 00 04 \n')
     # clean up
     finally:
         del_file(data_file_name)
@@ -583,7 +613,7 @@ def test_raw_mode_compression():
             with open(output_prefix+".cmp", encoding='utf-8') as f:
                 if "--no_header" in arg:
                     # check compressed data file
-                    assert(f.read() == data[:-1]+"00 00 \n")
+                    assert(f.read() == data)#[:-1]+"00 00 \n")
                     # check info file
                     with open(output_prefix+".info", encoding='utf-8') as f:
                         info = parse_key_value(f.read())
@@ -628,8 +658,6 @@ def test_raw_mode_compression():
                    "%s" % ((lambda arg : "Importing decompression information file %s.info ... DONE\n" % (output_prefix)
                             if "--no_header" in arg else "")(arg)) +
                    "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix) +
-                   "%s" % ((lambda arg : "Parse the compression entity header ... DONE\n"
-                            if not "--no_header" in arg else "")(arg)) +
                    "Decompress data ... DONE\n" +
                    "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix))
             assert(returncode == EXIT_SUCCESS)
@@ -803,9 +831,7 @@ def test_small_buf_err():
         assert(stdout == CMP_START_STR_CMP +
                "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
                "Importing data file %s ... DONE\n" % (data_file_name) +
-               "Compress data ... \n"
-               "Compression error 0x01\n"
-               "... FAILED\n")
+               "Compress data ... FAILED\n")
         # assert(stderr == "cmp_tool: the buffer for the compressed data is too small. Try a larger buffer_length parameter.\n")
         assert(stderr == "Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n")
         assert(returncode == EXIT_FAILURE)
@@ -980,11 +1006,9 @@ def test_sample_used_is_to_big():
             else:
                 assert(stdout == CMP_START_STR_DECMP +
                        "Importing compressed data file %s ... DONE\n" % (cmp_file_name) +
-                       "Parse the compression entity header ... DONE\n" +
                        "Decompress data ... FAILED\n")
 
-            assert(stderr == "Error: Buffer overflow detected.\n" +
-                   "Error: Compressed values could not be decoded.\n")
+            assert(stderr == "Error: Buffer overflow detected.\n")
 
             assert(returncode == EXIT_FAILURE)
     finally:
@@ -1010,6 +1034,7 @@ def test_header_wrong_formatted():
     finally:
         del_file(cmp_file_name)
 
+
 def test_header_read_in():
     cmp_file_name = 'test_header_read_in.cmp'
 
@@ -1082,7 +1107,7 @@ def test_header_read_in():
         assert(returncode == EXIT_FAILURE)
         assert(stdout == CMP_START_STR_DECMP +
                "Importing compressed data file %s ... DONE\n" % (cmp_file_name) +
-               "Parse the compression entity header ... FAILED\n" )
+               "Decompress data ... FAILED\n" )
         assert(stderr == "Error: Compression mode not supported.\n")
 
     finally:
@@ -1107,25 +1132,27 @@ def test_model_fiel_erros():
             f.write(cfg)
 
         # no -m option in model mode
-        returncode, stdout, stderr = call_cmp_tool(
-            " -c "+cfg_file_name+" -d "+data_file_name + " -o "+output_prefix+" --no_header")
-        assert(returncode == EXIT_FAILURE)
-        assert(stdout == CMP_START_STR_CMP +
-               "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
-               "Importing data file %s ... DONE\n" % (data_file_name) +
-               "Importing model file  ... FAILED\n" )
-        assert(stderr == "cmp_tool: No model file (-m option) specified.\n")
+        add_args = [" --no_header", ""]
+        for add_arg in add_args:
+            returncode, stdout, stderr = call_cmp_tool(
+                " -c "+cfg_file_name+" -d "+data_file_name + " -o "+output_prefix+add_arg)
+            assert(returncode == EXIT_FAILURE)
+            assert(stdout == CMP_START_STR_CMP +
+                   "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
+                   "Importing data file %s ... DONE\n" % (data_file_name) +
+                   "Importing model file  ... FAILED\n" )
+            assert(stderr == "cmp_tool: No model file (-m option) specified.\n")
 
-        # model file to small
-        with open(model_file_name, 'w', encoding='utf-8') as f:
-            f.write(model)
-        returncode, stdout, stderr = call_cmp_tool(
-            " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix)
-        assert(returncode == EXIT_FAILURE)
-        assert(stdout == CMP_START_STR_CMP +
-               "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
-               "Importing data file %s ... DONE\n" % (data_file_name) +
-               "Importing model file %s ... FAILED\n" % (model_file_name) )
+            # model file to small
+            with open(model_file_name, 'w', encoding='utf-8') as f:
+                f.write(model)
+            returncode, stdout, stderr = call_cmp_tool(
+                " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix)
+            assert(returncode == EXIT_FAILURE)
+            assert(stdout == CMP_START_STR_CMP +
+                   "Importing configuration file %s ... DONE\n" % (cfg_file_name) +
+                   "Importing data file %s ... DONE\n" % (data_file_name) +
+                   "Importing model file %s ... FAILED\n" % (model_file_name) )
         assert(stderr == "cmp_tool: %s: Error: The files do not contain enough data as requested.\n" % (model_file_name))
 
         # updated model can not write
@@ -1137,6 +1164,11 @@ def test_model_fiel_erros():
                          "longlonglonglonglonglonglonglonglonglonglonglonglong"
                          "longlonglonglonglonglonglonglonglonglonglonglonglong"
                          "longlonglonglonglonglonglonglonglonglong")
+        if sys.platform == 'win32' or sys.platform == 'cygwin':
+          output_prefix = ("longlonglonglonglonglonglonglonglonglonglonglonglong"
+                           "longlonglonglonglonglonglonglonglonglonglonglonglong"
+                           "longlonglonglonglonglonglonglonglonglonglonglonglong"
+                           "longlonglonglonglonglonglonglonglonglonglong")
         returncode, stdout, stderr = call_cmp_tool(
             " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix)
         assert(returncode == EXIT_FAILURE)
@@ -1148,8 +1180,10 @@ def test_model_fiel_erros():
                "Compress data ... DONE\n" +
                "Write compressed data to file %s.cmp ... DONE\n" %(output_prefix) +
                "Write updated model to file %s_upmodel.dat ... FAILED\n" %(output_prefix))
-        assert(stderr == "cmp_tool: %s_upmodel.dat: File name too long\n" % (output_prefix))
-        #
+        if sys.platform == 'win32' or sys.platform == 'cygwin':
+          assert(stderr == "cmp_tool: %s_upmodel.dat: No such file or directory\n" % (output_prefix))
+        else:
+          assert(stderr == "cmp_tool: %s_upmodel.dat: File name too long\n" % (output_prefix))
 
     finally:
         del_file(data_file_name)
diff --git a/test/cmp_tool/meson.build b/test/cmp_tool/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..065cc4557853043de6dbd6a861fd620f603da24a
--- /dev/null
+++ b/test/cmp_tool/meson.build
@@ -0,0 +1,12 @@
+int_test_file = files('cmp_tool_integration_test.py')
+
+pytest = find_program('pytest', required : false)
+if pytest.found()
+  test('cmp_tool Interface Test',
+    pytest,
+    args : ['--color=yes', '-vvv', int_test_file],
+    depends : cmp_tool_exe,
+    workdir : meson.project_build_root())
+else
+  message('Pytest framework not found! Skipping integration tests. Run pip install pytest.')
+endif
diff --git a/test/meson.build b/test/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..36fee6ce08454a4e3db2b9cf0092bbdb9274a460
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,41 @@
+# add checkpatch syntax-check target
+checkpatch = find_program('checkpatch.pl', 'checkpatch', required : false)
+if checkpatch.found()
+  checkpatch_args = [
+    '--no-tree', '-f',
+    '--show-types',
+    '--color=always',
+    '--ignore', 'SPDX_LICENSE_TAG,PREFER_DEFINED_ATTRIBUTE_MACRO,EMBEDDED_FILENAME,BLOCK_COMMENT_STYLE,EMBEDDED_FUNCTION_NAME',
+  ]
+  run_target('syntax-check',
+  command : [checkpatch, checkpatch_args, main, cmplib_sources])
+endif
+
+# add cppcheck inspector target
+cppcheck = find_program('cppcheck', required : false)
+if cppcheck.found()
+  cppcheck_args = [
+    main, cmplib_sources,
+    '--clang',
+    '--cppcheck-build-dir='+meson.current_build_dir(),
+    '-I', 'include',
+    '--std=c89',
+    # '--addon=misra.py',
+    '--bug-hunting',
+    '--enable=all',
+    '--inconclusive'
+  ]
+  run_target('inspector',
+    command : [cppcheck, cppcheck_args]
+  )
+endif
+
+subdir('tools')
+
+subdir('cmp_tool')
+
+unity_dep = dependency('unity', fallback : ['unity', 'unity_dep'])
+
+subdir('cmp_icu')
+subdir('cmp_data_types')
+subdir('cmp_entity')
diff --git a/test/tools/generate_test_runner.rb b/test/tools/generate_test_runner.rb
new file mode 100755
index 0000000000000000000000000000000000000000..1c0ec3450435f7c8cf95219afd6f9226b7389a0f
--- /dev/null
+++ b/test/tools/generate_test_runner.rb
@@ -0,0 +1,512 @@
+#!/usr/bin/env ruby
+# ==========================================
+#   Unity Project - A Test Framework for C
+#   Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
+#   [Released under MIT License. Please refer to license.txt for details]
+# ==========================================
+
+class UnityTestRunnerGenerator
+  def initialize(options = nil)
+    @options = UnityTestRunnerGenerator.default_options
+    case options
+    when NilClass
+      @options
+    when String
+      @options.merge!(UnityTestRunnerGenerator.grab_config(options))
+    when Hash
+      # Check if some of these have been specified
+      @options[:has_setup] = !options[:setup_name].nil?
+      @options[:has_teardown] = !options[:teardown_name].nil?
+      @options[:has_suite_setup] = !options[:suite_setup].nil?
+      @options[:has_suite_teardown] = !options[:suite_teardown].nil?
+      @options.merge!(options)
+    else
+      raise 'If you specify arguments, it should be a filename or a hash of options'
+    end
+    require_relative 'type_sanitizer'
+  end
+
+  def self.default_options
+    {
+      includes: [],
+      defines: [],
+      plugins: [],
+      framework: :unity,
+      test_prefix: 'test|spec|should',
+      mock_prefix: 'Mock',
+      mock_suffix: '',
+      setup_name: 'setUp',
+      teardown_name: 'tearDown',
+      test_reset_name: 'resetTest',
+      test_verify_name: 'verifyTest',
+      main_name: 'main', # set to :auto to automatically generate each time
+      main_export_decl: '',
+      cmdline_args: false,
+      omit_begin_end: false,
+      use_param_tests: false,
+      include_extensions: '(?:hpp|hh|H|h)',
+      source_extensions: '(?:cpp|cc|ino|C|c)'
+    }
+  end
+
+  def self.grab_config(config_file)
+    options = default_options
+    unless config_file.nil? || config_file.empty?
+      require 'yaml'
+      yaml_guts = YAML.load_file(config_file)
+      options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
+      raise "No :unity or :cmock section found in #{config_file}" unless options
+    end
+    options
+  end
+
+  def run(input_file, output_file, options = nil)
+    @options.merge!(options) unless options.nil?
+
+    # pull required data from source file
+    source = File.read(input_file)
+    source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil)
+    tests = find_tests(source)
+    headers = find_includes(source)
+    testfile_includes = (headers[:local] + headers[:system])
+    used_mocks = find_mocks(testfile_includes)
+    testfile_includes = (testfile_includes - used_mocks)
+    testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ }
+    find_setup_and_teardown(source)
+
+    # build runner file
+    generate(input_file, output_file, tests, used_mocks, testfile_includes)
+
+    # determine which files were used to return them
+    all_files_used = [input_file, output_file]
+    all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty?
+    all_files_used += @options[:includes] unless @options[:includes].empty?
+    all_files_used += headers[:linkonly] unless headers[:linkonly].empty?
+    all_files_used.uniq
+  end
+
+  def generate(input_file, output_file, tests, used_mocks, testfile_includes)
+    File.open(output_file, 'w') do |output|
+      create_header(output, used_mocks, testfile_includes)
+      create_externs(output, tests, used_mocks)
+      create_mock_management(output, used_mocks)
+      create_setup(output)
+      create_teardown(output)
+      create_suite_setup(output)
+      create_suite_teardown(output)
+      create_reset(output)
+      create_run_test(output) unless tests.empty?
+      create_args_wrappers(output, tests)
+      create_main(output, input_file, tests, used_mocks)
+    end
+
+    return unless @options[:header_file] && !@options[:header_file].empty?
+
+    File.open(@options[:header_file], 'w') do |output|
+      create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks)
+    end
+  end
+
+  def find_tests(source)
+    tests_and_line_numbers = []
+
+    # contains characters which will be substituted from within strings, doing
+    # this prevents these characters from interfering with scrubbers
+    # @ is not a valid C character, so there should be no clashes with files genuinely containing these markers
+    substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' }
+    substring_re = Regexp.union(substring_subs.keys)
+    substring_unsubs = substring_subs.invert                   # the inverse map will be used to fix the strings afterwords
+    substring_unsubs['@quote@'] = '\\"'
+    substring_unsubs['@apos@'] = '\\\''
+    substring_unre = Regexp.union(substring_unsubs.keys)
+    source_scrubbed = source.clone
+    source_scrubbed = source_scrubbed.gsub(/\\"/, '@quote@')   # hide escaped quotes to allow capture of the full string/char
+    source_scrubbed = source_scrubbed.gsub(/\\'/, '@apos@')    # hide escaped apostrophes to allow capture of the full string/char
+    source_scrubbed = source_scrubbed.gsub(/("[^"\n]*")|('[^'\n]*')/) { |s| s.gsub(substring_re, substring_subs) } # temporarily hide problematic characters within strings
+    source_scrubbed = source_scrubbed.gsub(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '')  # remove line comments that comment out the start of blocks
+    source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '')                     # remove block comments
+    source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '')                          # remove line comments (all that remain)
+    lines = source_scrubbed.split(/(^\s*\#.*$) | (;|\{|\}) /x)                     # Treat preprocessor directives as a logical line. Match ;, {, and } as end of lines
+                           .map { |line| line.gsub(substring_unre, substring_unsubs) } # unhide the problematic characters previously removed
+
+    lines.each_with_index do |line, _index|
+      # find tests
+      next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m
+
+      arguments = Regexp.last_match(1)
+      name = Regexp.last_match(2)
+      call = Regexp.last_match(3)
+      params = Regexp.last_match(4)
+      args = nil
+
+      if @options[:use_param_tests] && !arguments.empty?
+        args = []
+        arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] }
+
+        arguments.scan(/\s*TEST_RANGE\s*\((.*)\)\s*$/).flatten.each do |range_str|
+          args += range_str.scan(/\[(-?\d+.?\d*), *(-?\d+.?\d*), *(-?\d+.?\d*)\]/).map do |arg_values_str|
+            arg_values_str.map do |arg_value_str|
+              arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i
+            end
+          end.map do |arg_values|
+            (arg_values[0]..arg_values[1]).step(arg_values[2]).to_a
+          end.reduce do |result, arg_range_expanded|
+            result.product(arg_range_expanded)
+          end.map do |arg_combinations|
+            arg_combinations.flatten.join(', ')
+          end
+        end
+      end
+
+      tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 }
+    end
+
+    tests_and_line_numbers.uniq! { |v| v[:test] }
+
+    # determine line numbers and create tests to run
+    source_lines = source.split("\n")
+    source_index = 0
+    tests_and_line_numbers.size.times do |i|
+      source_lines[source_index..-1].each_with_index do |line, index|
+        next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/
+
+        source_index += index
+        tests_and_line_numbers[i][:line_number] = source_index + 1
+        break
+      end
+    end
+
+    tests_and_line_numbers
+  end
+
+  def find_includes(source)
+    # remove comments (block and line, in three steps to ensure correct precedence)
+    source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '')  # remove line comments that comment out the start of blocks
+    source.gsub!(/\/\*.*?\*\//m, '')                     # remove block comments
+    source.gsub!(/\/\/.*$/, '')                          # remove line comments (all that remain)
+
+    # parse out includes
+    includes = {
+      local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten,
+      system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" },
+      linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten
+    }
+    includes
+  end
+
+  def find_mocks(includes)
+    mock_headers = []
+    includes.each do |include_path|
+      include_file = File.basename(include_path)
+      mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}\.h$/i
+    end
+    mock_headers
+  end
+
+  def find_setup_and_teardown(source)
+    @options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/
+    @options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/
+    @options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/)
+    @options[:has_suite_teardown] ||= (source =~ /int\s+suiteTearDown\s*\(int\s+([a-zA-Z0-9_])+\s*\)/)
+  end
+
+  def create_header(output, mocks, testfile_includes = [])
+    output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
+    output.puts("\n/*=======Automagically Detected Files To Include=====*/")
+    output.puts("#include \"#{@options[:framework]}.h\"")
+    output.puts('#include "cmock.h"') unless mocks.empty?
+    if @options[:defines] && !@options[:defines].empty?
+      @options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") }
+    end
+    if @options[:header_file] && !@options[:header_file].empty?
+      output.puts("#include \"#{File.basename(@options[:header_file])}\"")
+    else
+      @options[:includes].flatten.uniq.compact.each do |inc|
+        output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
+      end
+      testfile_includes.each do |inc|
+        output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
+      end
+    end
+    mocks.each do |mock|
+      output.puts("#include \"#{mock}\"")
+    end
+    output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception)
+
+    return unless @options[:enforce_strict_ordering]
+
+    output.puts('')
+    output.puts('int GlobalExpectCount;')
+    output.puts('int GlobalVerifyOrder;')
+    output.puts('char* GlobalOrderError;')
+  end
+
+  def create_externs(output, tests, _mocks)
+    output.puts("\n/*=======External Functions This Runner Calls=====*/")
+    output.puts("extern void #{@options[:setup_name]}(void);")
+    output.puts("extern void #{@options[:teardown_name]}(void);")
+    output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc]
+    tests.each do |test|
+      output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});")
+    end
+    output.puts("#ifdef __cplusplus\n}\n#endif") if @options[:externc]
+    output.puts('')
+  end
+
+  def create_mock_management(output, mock_headers)
+    output.puts("\n/*=======Mock Management=====*/")
+    output.puts('static void CMock_Init(void)')
+    output.puts('{')
+
+    if @options[:enforce_strict_ordering]
+      output.puts('  GlobalExpectCount = 0;')
+      output.puts('  GlobalVerifyOrder = 0;')
+      output.puts('  GlobalOrderError = NULL;')
+    end
+
+    mocks = mock_headers.map { |mock| File.basename(mock, '.*') }
+    mocks.each do |mock|
+      mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
+      output.puts("  #{mock_clean}_Init();")
+    end
+    output.puts("}\n")
+
+    output.puts('static void CMock_Verify(void)')
+    output.puts('{')
+    mocks.each do |mock|
+      mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
+      output.puts("  #{mock_clean}_Verify();")
+    end
+    output.puts("}\n")
+
+    output.puts('static void CMock_Destroy(void)')
+    output.puts('{')
+    mocks.each do |mock|
+      mock_clean = TypeSanitizer.sanitize_c_identifier(mock)
+      output.puts("  #{mock_clean}_Destroy();")
+    end
+    output.puts("}\n")
+  end
+
+  def create_setup(output)
+    return if @options[:has_setup]
+
+    output.puts("\n/*=======Setup (stub)=====*/")
+    output.puts("void #{@options[:setup_name]}(void) {}")
+  end
+
+  def create_teardown(output)
+    return if @options[:has_teardown]
+
+    output.puts("\n/*=======Teardown (stub)=====*/")
+    output.puts("void #{@options[:teardown_name]}(void) {}")
+  end
+
+  def create_suite_setup(output)
+    return if @options[:suite_setup].nil?
+
+    output.puts("\n/*=======Suite Setup=====*/")
+    output.puts('void suiteSetUp(void)')
+    output.puts('{')
+    output.puts(@options[:suite_setup])
+    output.puts('}')
+  end
+
+  def create_suite_teardown(output)
+    return if @options[:suite_teardown].nil?
+
+    output.puts("\n/*=======Suite Teardown=====*/")
+    output.puts('int suiteTearDown(int num_failures)')
+    output.puts('{')
+    output.puts(@options[:suite_teardown])
+    output.puts('}')
+  end
+
+  def create_reset(output)
+    output.puts("\n/*=======Test Reset Options=====*/")
+    output.puts("void #{@options[:test_reset_name]}(void);")
+    output.puts("void #{@options[:test_reset_name]}(void)")
+    output.puts('{')
+    output.puts("  #{@options[:teardown_name]}();")
+    output.puts('  CMock_Verify();')
+    output.puts('  CMock_Destroy();')
+    output.puts('  CMock_Init();')
+    output.puts("  #{@options[:setup_name]}();")
+    output.puts('}')
+    output.puts("void #{@options[:test_verify_name]}(void);")
+    output.puts("void #{@options[:test_verify_name]}(void)")
+    output.puts('{')
+    output.puts('  CMock_Verify();')
+    output.puts('}')
+  end
+
+  def create_run_test(output)
+    require 'erb'
+    template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')), nil, '<>')
+    output.puts("\n" + template.result(binding))
+  end
+
+  def create_args_wrappers(output, tests)
+    return unless @options[:use_param_tests]
+
+    output.puts("\n/*=======Parameterized Test Wrappers=====*/")
+    tests.each do |test|
+      next if test[:args].nil? || test[:args].empty?
+
+      test[:args].each.with_index(1) do |args, idx|
+        output.puts("static void runner_args#{idx}_#{test[:test]}(void)")
+        output.puts('{')
+        output.puts("    #{test[:test]}(#{args});")
+        output.puts("}\n")
+      end
+    end
+  end
+
+  def create_main(output, filename, tests, used_mocks)
+    output.puts("\n/*=======MAIN=====*/")
+    main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s
+    if @options[:cmdline_args]
+      if main_name != 'main'
+        output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);")
+      end
+      output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)")
+      output.puts('{')
+      output.puts('  int parse_status = UnityParseOptions(argc, argv);')
+      output.puts('  if (parse_status != 0)')
+      output.puts('  {')
+      output.puts('    if (parse_status < 0)')
+      output.puts('    {')
+      output.puts("      UnityPrint(\"#{filename.gsub('.c', '')}.\");")
+      output.puts('      UNITY_PRINT_EOL();')
+      tests.each do |test|
+        if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty?
+          output.puts("      UnityPrint(\"  #{test[:test]}\");")
+          output.puts('      UNITY_PRINT_EOL();')
+        else
+          test[:args].each do |args|
+            output.puts("      UnityPrint(\"  #{test[:test]}(#{args})\");")
+            output.puts('      UNITY_PRINT_EOL();')
+          end
+        end
+      end
+      output.puts('      return 0;')
+      output.puts('    }')
+      output.puts('    return parse_status;')
+      output.puts('  }')
+    else
+      main_return = @options[:omit_begin_end] ? 'void' : 'int'
+      if main_name != 'main'
+        output.puts("#{@options[:main_export_decl]} #{main_return} #{main_name}(void);")
+      end
+      output.puts("#{main_return} #{main_name}(void)")
+      output.puts('{')
+    end
+    output.puts('  suiteSetUp();') if @options[:has_suite_setup]
+    if @options[:omit_begin_end]
+      output.puts("  UnitySetTestFile(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
+    else
+      output.puts("  UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");")
+    end
+    tests.each do |test|
+      if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty?
+        output.puts("  run_test(#{test[:test]}, \"#{test[:test]}\", #{test[:line_number]});")
+      else
+        test[:args].each.with_index(1) do |args, idx|
+          wrapper = "runner_args#{idx}_#{test[:test]}"
+          testname = "#{test[:test]}(#{args})".dump
+          output.puts("  run_test(#{wrapper}, #{testname}, #{test[:line_number]});")
+        end
+      end
+    end
+    output.puts
+    output.puts('  CMock_Guts_MemFreeFinal();') unless used_mocks.empty?
+    if @options[:has_suite_teardown]
+      if @options[:omit_begin_end]
+        output.puts('  (void) suite_teardown(0);')
+      else
+        output.puts('  return suiteTearDown(UnityEnd());')
+      end
+    else
+      output.puts('  return UnityEnd();') unless @options[:omit_begin_end]
+    end
+    output.puts('}')
+  end
+
+  def create_h_file(output, filename, tests, testfile_includes, used_mocks)
+    filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase
+    output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */')
+    output.puts("#ifndef _#{filename}")
+    output.puts("#define _#{filename}\n\n")
+    output.puts("#include \"#{@options[:framework]}.h\"")
+    output.puts('#include "cmock.h"') unless used_mocks.empty?
+    @options[:includes].flatten.uniq.compact.each do |inc|
+      output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
+    end
+    testfile_includes.each do |inc|
+      output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}")
+    end
+    output.puts "\n"
+    tests.each do |test|
+      if test[:params].nil? || test[:params].empty?
+        output.puts("void #{test[:test]}(void);")
+      else
+        output.puts("void #{test[:test]}(#{test[:params]});")
+      end
+    end
+    output.puts("#endif\n\n")
+  end
+end
+
+if $0 == __FILE__
+  options = { includes: [] }
+
+  # parse out all the options first (these will all be removed as we go)
+  ARGV.reject! do |arg|
+    case arg
+    when '-cexception'
+      options[:plugins] = [:cexception]
+      true
+    when /\.*\.ya?ml$/
+      options = UnityTestRunnerGenerator.grab_config(arg)
+      true
+    when /--(\w+)=\"?(.*)\"?/
+      options[Regexp.last_match(1).to_sym] = Regexp.last_match(2)
+      true
+    when /\.*\.(?:hpp|hh|H|h)$/
+      options[:includes] << arg
+      true
+    else false
+    end
+  end
+
+  # make sure there is at least one parameter left (the input file)
+  unless ARGV[0]
+    puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)",
+          "\n  input_test_file         - this is the C file you want to create a runner for",
+          '  output                  - this is the name of the runner file to generate',
+          '                            defaults to (input_test_file)_Runner',
+          '  files:',
+          '    *.yml / *.yaml        - loads configuration from here in :unity or :cmock',
+          '    *.h                   - header files are added as #includes in runner',
+          '  options:',
+          '    -cexception           - include cexception support',
+          '    -externc              - add extern "C" for cpp support',
+          '    --setup_name=""       - redefine setUp func name to something else',
+          '    --teardown_name=""    - redefine tearDown func name to something else',
+          '    --main_name=""        - redefine main func name to something else',
+          '    --test_prefix=""      - redefine test prefix from default test|spec|should',
+          '    --test_reset_name=""  - redefine resetTest func name to something else',
+          '    --test_verify_name="" - redefine verifyTest func name to something else',
+          '    --suite_setup=""      - code to execute for setup of entire suite',
+          '    --suite_teardown=""   - code to execute for teardown of entire suite',
+          '    --use_param_tests=1   - enable parameterized tests (disabled by default)',
+          '    --omit_begin_end=1    - omit calls to UnityBegin and UnityEnd (disabled by default)',
+          '    --header_file=""      - path/name of test header file to generate too'].join("\n")
+    exit 1
+  end
+
+  # create the default test runner name if not specified
+  ARGV[1] = ARGV[0].gsub('.c', '_Runner.c') unless ARGV[1]
+
+  UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1])
+end
diff --git a/test/tools/meson.build b/test/tools/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..7e9b12294e366202a2a9f41d06af8173b156b206
--- /dev/null
+++ b/test/tools/meson.build
@@ -0,0 +1,6 @@
+generate_test_runner = find_program('generate_test_runner.rb')
+test_runner_generator = generator(
+  generate_test_runner,
+  output: ['@BASENAME@_Runner.c'],
+  arguments: ['@INPUT@', '@OUTPUT@']
+)
diff --git a/test/tools/run_test.erb b/test/tools/run_test.erb
new file mode 100644
index 0000000000000000000000000000000000000000..f91b566915b10cff86d3d4da119ffe1c5863a6f4
--- /dev/null
+++ b/test/tools/run_test.erb
@@ -0,0 +1,37 @@
+/*=======Test Runner Used To Run Each Test=====*/
+static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num)
+{
+    Unity.CurrentTestName = name;
+    Unity.CurrentTestLineNumber = line_num;
+#ifdef UNITY_USE_COMMAND_LINE_ARGS
+    if (!UnityTestMatches())
+        return;
+#endif
+    Unity.NumberOfTests++;
+    UNITY_CLR_DETAILS();
+    UNITY_EXEC_TIME_START();
+    CMock_Init();
+    if (TEST_PROTECT())
+    {
+<% if @options[:plugins].include?(:cexception) %>
+        CEXCEPTION_T e;
+        Try {
+            <%= @options[:setup_name] %>();
+            func();
+        } Catch(e) {
+            TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!");
+        }
+<% else %>
+        <%= @options[:setup_name] %>();
+        func();
+<% end %>
+    }
+    if (TEST_PROTECT())
+    {
+        <%= @options[:teardown_name] %>();
+        CMock_Verify();
+    }
+    CMock_Destroy();
+    UNITY_EXEC_TIME_STOP();
+    UnityConcludeTest();
+}
diff --git a/test/tools/type_sanitizer.rb b/test/tools/type_sanitizer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..dafb8826e71ceb74afa2c4a1563ce66e659b230a
--- /dev/null
+++ b/test/tools/type_sanitizer.rb
@@ -0,0 +1,6 @@
+module TypeSanitizer
+  def self.sanitize_c_identifier(unsanitized)
+    # convert filename to valid C identifier by replacing invalid chars with '_'
+    unsanitized.gsub(/[-\/\\\.\,\s]/, '_')
+  end
+end