From 87a92212cb3d42eb36f70f9edefa7f2e51eb1d4d Mon Sep 17 00:00:00 2001
From: Dominik Loidolt <dominik.loidolt@univie.ac.at>
Date: Fri, 23 Apr 2021 17:20:54 +0200
Subject: [PATCH] discard old file format. Now the only input format is like:
 12 AB 23 CD .. .. change to new compression and decompression library

---
 .gitignore                  |   51 +
 CHANGELOG.md                |   49 +
 Makefile                    |   36 +
 cmp_tool.c                  |  436 ++++++
 include/byteorder.h         |  273 ++++
 include/cmp_data_types.h    |  190 +++
 include/cmp_debug.h         |   34 +
 include/cmp_icu.h           |   28 +
 include/cmp_rdcu.h          |   43 +
 include/cmp_rdcu_extended.h |   30 +
 include/cmp_support.h       |  184 +++
 include/decmp.h             |   31 +
 include/rdcu_cmd.h          |  162 +++
 include/rdcu_ctrl.h         |  284 ++++
 include/rdcu_pkt_to_file.h  |   39 +
 include/rdcu_rmap.h         |   65 +
 include/rmap.h              |  217 +++
 include/tool_lib.h          |   46 +
 lib/cmp_data_types.c        |  647 +++++++++
 lib/cmp_icu.c               | 1781 +++++++++++++++++++++++++
 lib/cmp_rdcu.c              |  876 ++++++++++++
 lib/cmp_support.c           |  595 +++++++++
 lib/decmp.c                 | 1534 +++++++++++++++++++++
 lib/rdcu_cmd.c              |  886 +++++++++++++
 lib/rdcu_ctrl.c             | 2491 +++++++++++++++++++++++++++++++++++
 lib/rdcu_pkt_to_file.c      |  472 +++++++
 lib/rdcu_rmap.c             |  822 ++++++++++++
 lib/rmap.c                  |  778 +++++++++++
 lib/tool_lib.c              | 1206 +++++++++++++++++
 test_data/test_data1.dat    |    4 +
 test_data/test_data2.dat    |    4 +
 31 files changed, 14294 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 CHANGELOG.md
 create mode 100644 Makefile
 create mode 100755 cmp_tool.c
 create mode 100644 include/byteorder.h
 create mode 100644 include/cmp_data_types.h
 create mode 100644 include/cmp_debug.h
 create mode 100644 include/cmp_icu.h
 create mode 100644 include/cmp_rdcu.h
 create mode 100644 include/cmp_rdcu_extended.h
 create mode 100644 include/cmp_support.h
 create mode 100644 include/decmp.h
 create mode 100644 include/rdcu_cmd.h
 create mode 100644 include/rdcu_ctrl.h
 create mode 100644 include/rdcu_pkt_to_file.h
 create mode 100644 include/rdcu_rmap.h
 create mode 100644 include/rmap.h
 create mode 100644 include/tool_lib.h
 create mode 100644 lib/cmp_data_types.c
 create mode 100644 lib/cmp_icu.c
 create mode 100644 lib/cmp_rdcu.c
 create mode 100644 lib/cmp_support.c
 create mode 100644 lib/decmp.c
 create mode 100644 lib/rdcu_cmd.c
 create mode 100644 lib/rdcu_ctrl.c
 create mode 100644 lib/rdcu_pkt_to_file.c
 create mode 100644 lib/rdcu_rmap.c
 create mode 100644 lib/rmap.c
 create mode 100644 lib/tool_lib.c
 create mode 100644 test_data/test_data1.dat
 create mode 100644 test_data/test_data2.dat

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3158f7e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,51 @@
+### C ###
+# Executables
+cmp_tool
+
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# C/C++/ObjC language server
+.ccls-cache
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..fdbf871
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,49 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+## [Unreleased]
+## [0.05] - 23-04-2021
+### Removed
+- discard old file format. Now the only input format is like: 12 AB 23 CD .. ..
+### Changed
+- change to new compression and decompression library
+## [0.05 Beta 2] - 04-12-2020
+### Fixed
+- packet file number now 4 digits long
+- now the mtu size in .rdcu_pkt_mode_cfg file for the data packets
+## [0.05 Beta] - 17-11-2020
+### Fixed
+- fixes small errors when reading the data
+### Added
+- add frame script to mange multiple compression in a raw
+- add last_info option to generate RMAP packets to read the last compression results in parallel
+## [0.04] - 12-08-2020
+### Fixed
+- fixes an error when reading compressed data for decompression when compiled for a 32-bit system where a long integer has 4 bytes
+- fixes a bug that generates wrong packets for reading data from the RDCU with the --rdcu_pkt option
+## [0.03] - 07-07-2020
+### Added
+- README: add a note for the --rdcu_pkt option
+### Fixed
+- if the --rdcu_pkt option is set the program did not create the TC_FILES directory for the tc files
+- if the --rdcu_pkt option is set the program did not build the data and model packets correctly.
+- if the --rdcu_pkt option is set the program now also sets the RDCU Interrupt Enable bit.
+- fix typo in Help and README
+## [0.02] - 02-06-2020
+### Added
+- add --rdcu_pkt option to generate the packets to set a RDCU compression
+- add --model_cfg, --diff_cfg option to print default model/1d-diff configuration
+- add --rdcu_par option to add the RDCU parameters to compression configuration and decompression information
+- check the cfg file and the info file for plausibility
+### Changed
+- change .info file format
+### Fixed
+- include fixes of rmap lib
+### Removed
+- removes comma symbol as indicator for a comment
+
+## [0.01] - 06-05-2020
+### Added
+- initialte realse
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d617c78
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+CC               = gcc
+SOURCEDIR	       = lib
+INCLUDEDIR       = include
+BUILDDIR         = ./
+CFLAGS          := -Wall -Wextra -std=gnu99 -pedantic -Wshadow
+RELCFLAGS       := -O2 # Release flags
+DBCFLAGS        := -O0 -g3 #debug 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)/tool_lib.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)
diff --git a/cmp_tool.c b/cmp_tool.c
new file mode 100755
index 0000000..90ce973
--- /dev/null
+++ b/cmp_tool.c
@@ -0,0 +1,436 @@
+/**
+ * @file   cmp_tool.c
+ * @author Johannes Seelig (johannes.seelig@univie.ac.at)
+ * @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 command line tool for PLATO ICU/RDCU compression/decompression
+ * @see README.md
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ */
+
+#include <limits.h>
+#include <getopt.h>
+
+#include "include/tool_lib.h"
+#include "include/cmp_icu.h"
+#include "include/cmp_rdcu.h"
+#include "include/decmp.h"
+
+#define VERSION "0.05"
+
+/*
+ * For long options that have no equivalent short option, use a
+ * non-character as a pseudo short option, starting with CHAR_MAX + 1.
+ */
+enum {
+	RDCU_PKT_OPTION = CHAR_MAX + 1,
+	DIFF_CFG_OPTION,
+	RDCU_PAR_OPTION,
+	LAST_INFO,
+};
+
+static struct option const long_options[] = {
+	{"rdcu_par", no_argument, NULL, 'a'},
+	{"model_cfg", no_argument, NULL, 'n'},
+	{"help", no_argument, NULL, 'h'},
+	{"verbose", no_argument, NULL, 'v'},
+	{"version", no_argument, NULL, 'V'},
+	{"rdcu_pkt", no_argument, NULL, RDCU_PKT_OPTION},
+	{"diff_cfg", no_argument, NULL, DIFF_CFG_OPTION},
+	{"last_info", required_argument, NULL, LAST_INFO}
+};
+
+
+/**
+ * @brief This is the main function of the compression / decompression tool
+ *
+ * @param argc argument count
+ * @param argv argument vector
+ * @see README.md
+ *
+ * @returns EXIT_SUCCESS on success, EXIT_FAILURE on error
+ */
+
+int main(int argc, char **argv)
+{
+	int32_t opt;
+
+	const char *cfg_file_name = NULL;
+	const char *info_file_name = NULL;
+	const char *data_file_name = NULL;
+	const char *model_file_name = NULL;
+	const char *last_info_file_name = NULL;
+	const char *output_prefix = DEFAULT_OUTPUT_PREFIX;
+
+	int print_model_cfg = 0;
+	int print_diff_cfg = 0;
+	int print_rdcu_cfg = 1;
+	int cmp_operation = 0;
+	int verbose_en = 0;
+	int rdcu_pkt_mode = 0;
+
+	struct cmp_cfg cfg = {0}; /* compressor configuration struct */
+	struct cmp_info info = {0}; /* decompression information struct */
+	struct cmp_info last_info = {0}; /* last decompression information struct */
+	int error;
+
+	uint32_t *decomp_input_buf = NULL;
+	uint16_t *input_model_buf = NULL;
+
+	/* show help if no arguments are provided */
+	if (argc < 2) {
+		Print_Help(*argv);
+		exit(EXIT_FAILURE);
+	}
+
+	while ((opt = getopt_long (argc, argv, "ac:d:hi:m:no:vV", long_options,
+				   NULL)) != -1) {
+		switch (opt) {
+		case 'a': /* --rdcu_par */
+			print_rdcu_cfg = 1;
+			break;
+		case 'c':
+			cmp_operation = 1;
+			cfg_file_name = optarg;
+			break;
+		case 'd':
+			data_file_name = optarg;
+			break;
+		case 'h': /* --help */
+			Print_Help(*argv);
+			exit(EXIT_SUCCESS);
+			break;
+		case 'i':
+			info_file_name = optarg;
+			break;
+		case 'm': /* read model */
+			model_file_name = optarg;
+			break;
+		case 'n': /* --model_cfg */
+			print_model_cfg = 1;
+			break;
+		case 'o':
+			output_prefix = optarg;
+			break;
+		case 'v': /* --verbose */
+			verbose_en = 1;
+			break;
+		case 'V': /* --version */
+			printf("%s %s\n", PROGRAM_NAME, VERSION);
+			exit(EXIT_SUCCESS);
+			break;
+		case DIFF_CFG_OPTION:
+			print_diff_cfg = 1;
+			break;
+		case RDCU_PKT_OPTION:
+			rdcu_pkt_mode = 1;
+			break;
+		case LAST_INFO:
+			rdcu_pkt_mode = 1;
+			last_info_file_name = optarg;
+			break;
+		default:
+			Print_Help(*argv);
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (print_model_cfg == 1) {
+		print_cfg(&DEFAULT_CFG_MODEL, print_rdcu_cfg);
+		exit(EXIT_SUCCESS);
+	}
+
+	if (print_diff_cfg == 1) {
+		print_cfg(&DEFAULT_CFG_DIFF, print_rdcu_cfg);
+		exit(EXIT_SUCCESS);
+	}
+
+	printf("#########################################################\n");
+	printf("### PLATO Compression/Decompression Tool Version %s ###\n",
+	       VERSION);
+	printf("#########################################################\n\n");
+
+	if (!cfg_file_name && !info_file_name) {
+		fprintf(stderr, "%s: No configuration file (-c option) or decompression information file (-i option) specified.\n",
+			PROGRAM_NAME);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!data_file_name) {
+		fprintf(stderr, "%s: No data file (-d option) specified.\n",
+			PROGRAM_NAME);
+			exit(EXIT_FAILURE);
+	}
+
+	/* read input data and .cfg or .info */
+	if (cmp_operation) { /* compression mode */
+		printf("### Compression ###\n");
+		printf("Importing configuration file %s ... ", cfg_file_name);
+
+		error = read_cmp_cfg(cfg_file_name, &cfg, verbose_en);
+		if (error) {
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+
+		printf("Importing data file %s ... ", data_file_name);
+
+		cfg.input_buf = read_file16(data_file_name, cfg.samples,
+					   verbose_en);
+		if (!cfg.input_buf) {
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+	} else { /* decompression mode*/
+		uint32_t cmp_size_byte;
+
+		printf("### Decompression ###\n\n");
+		printf("Importing decompression information file ... ");
+
+		error  = read_cmp_info(info_file_name, &info, verbose_en);
+		if (error) {
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+
+		printf("Importing compressed data file %s ... ", data_file_name);
+
+		cmp_size_byte = (info.cmp_size + 31) / 8;
+
+		decomp_input_buf = read_file32(data_file_name, cmp_size_byte/4,
+					      verbose_en);
+		if (!decomp_input_buf) {
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+	}
+
+	/* read in model for compressed and decompression */
+	if ((cmp_operation && model_mode_is_used(cfg.cmp_mode)) ||
+	    (!cmp_operation && model_mode_is_used(info.cmp_mode_used))) {
+		uint32_t model_length;
+
+		if (cmp_operation)
+			model_length = cfg.samples;
+		else
+			model_length = info.samples_used;
+
+		if (!model_file_name) {
+			fprintf(stderr, "%s: No model file (-m "
+				"option) specified.\n", PROGRAM_NAME);
+			exit(EXIT_FAILURE);
+		}
+
+		printf("Importing model file %s ... ", model_file_name);
+
+
+		input_model_buf = read_file16(model_file_name, model_length,
+					     verbose_en);
+		if (!input_model_buf) {
+			printf("FAILED\n");
+			free(cfg.input_buf);
+			free(decomp_input_buf);
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+		if (cmp_operation)
+			cfg.model_buf = input_model_buf;
+	}
+
+	if (cmp_operation) { /* perform a compression */
+		uint32_t cmp_size_byte;
+
+		if (rdcu_pkt_mode) {
+			printf("Generate compression setup packets ... \n");
+			error = init_rmap_pkt_to_file();
+			if (error) {
+				printf("... FAILED\n");
+				fprintf(stderr, "%s: Read RMAP packet config file .rdcu_pkt_mode_cfg failed.\n",
+					PROGRAM_NAME);
+				free(cfg.input_buf);
+				free(input_model_buf);
+				exit(EXIT_FAILURE);
+			}
+
+			if (last_info_file_name) {
+				error  = read_cmp_info(last_info_file_name,
+						       &last_info, verbose_en);
+				if (error) {
+					printf("... FAILED\n");
+					fprintf(stderr, "%s: %s: Importing last decompression information file failed.\n",
+						PROGRAM_NAME, last_info_file_name);
+					exit(EXIT_FAILURE);
+				}
+
+				error = gen_rdcu_parallel_pkts(&cfg, &last_info);
+				if (error) {
+					printf("... FAILED\n");
+					free(cfg.input_buf);
+					free(input_model_buf);
+					exit(EXIT_FAILURE);
+				}
+			}
+
+			error = gen_write_rdcu_pkts(&cfg);
+
+			if (error) {
+				printf("... FAILED\n");
+				free(cfg.input_buf);
+				free(input_model_buf);
+				exit(EXIT_FAILURE);
+			} else
+				printf("... DONE\n");
+		}
+
+		cfg.icu_output_buf = (uint32_t *)malloc(cfg.buffer_length *
+							SAM2BYT);
+		if (cfg.icu_output_buf == NULL) {
+			printf("%s: Error allocating Memory for Output Buffer."
+			       "\n", PROGRAM_NAME);
+			free(cfg.input_buf);
+			free(input_model_buf);
+			abort();
+		}
+
+		printf("Compress data ... ");
+
+		error = icu_compress_data(&cfg, &info);
+		free(cfg.input_buf);
+		if (error || info.cmp_err != 0) {
+			printf("FAILED\n");
+			printf("Compression error %#X\n", info.cmp_err);
+			free(input_model_buf);
+			free(cfg.icu_output_buf);
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+		if (rdcu_pkt_mode) {
+			printf("Generate the read results packets ... ");
+			error = gen_read_rdcu_pkts(&info);
+			if (error) {
+				printf("FAILED\n");
+				free(input_model_buf);
+				free(cfg.icu_output_buf);
+				exit(EXIT_FAILURE);
+			} else
+				printf("DONE\n");
+		}
+		printf("Write compressed data to file %s.cmp ... ",
+		       output_prefix);
+
+		/* length of cmp_size in bytes words (round up to 4 bytes) */
+		cmp_size_byte = (info.cmp_size + 31)/32 * 4;
+
+		error = write_cmp_data_file(cfg.icu_output_buf, cmp_size_byte,
+					output_prefix, ".cmp", verbose_en);
+		free(cfg.icu_output_buf);
+		if (error) {
+			printf("FAILED\n");
+			free(input_model_buf);
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+		if (model_mode_is_used(cfg.cmp_mode)) {
+			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);
+			free(input_model_buf);
+			if (error) {
+				printf("FAILED\n");
+				exit(EXIT_FAILURE);
+			} else
+				printf("DONE\n");
+		}
+
+		printf("Write decompression information to file %s.info ... ",
+		       output_prefix);
+
+		error = write_info(&info, output_prefix, print_rdcu_cfg);
+		if (error) {
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+		if (verbose_en) {
+			printf("\n");
+			print_cmp_info(&info);
+			printf("\n");
+		}
+	} else { /* perform a decompression */
+		uint16_t *decomp_output;
+
+		decomp_output = (uint16_t *)malloc(info.samples_used * SAM2BYT);
+		if (decomp_output == NULL) {
+			printf("Error allocating Memory for decmpr Model Buffer\n");
+			free(decomp_input_buf);
+			free(input_model_buf);
+			abort();
+		}
+
+		printf("Decompress data ... ");
+
+		error = decompress_data(decomp_input_buf, input_model_buf,
+					&info, decomp_output);
+		free(decomp_input_buf);
+		if (error != 0) {
+			free(decomp_output);
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			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);
+		free(decomp_output);
+		if (error) {
+			printf("FAILED\n");
+			exit(EXIT_FAILURE);
+		} else
+			printf("DONE\n");
+
+		if (model_mode_is_used(info.cmp_mode_used)) {
+			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);
+			free(input_model_buf);
+			if (error) {
+				printf("FAILED\n");
+				exit(EXIT_FAILURE);
+			} else
+				printf("DONE\n");
+		}
+	}
+
+	exit(EXIT_SUCCESS);
+}
diff --git a/include/byteorder.h b/include/byteorder.h
new file mode 100644
index 0000000..b039705
--- /dev/null
+++ b/include/byteorder.h
@@ -0,0 +1,273 @@
+/**
+ * @file   byteorder.h
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2015
+ *
+ * @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.
+ *
+ * This is a set of macros for consistent endianess conversion. They work
+ * for both little and big endian cpus.
+ *
+ * conversion of XX-bit integers (16- or 32-) between native CPU format
+ * and little/big endian format:
+ *	cpu_to_[bl]eXX(uintXX_t x)
+ *	[bl]eXX_to_cpu(uintXX_t x)
+ *
+ * the same, but change in situ:
+ *	cpu_to_[bl]eXXs(uintXX_t x)
+ *	[bl]eXX_to_cpus(uintXX_t x)
+ *
+ *
+ * This is based on the byte order macros from the linux kernel, see:
+ * include/linux/byteorder/generic.h
+ * include/uapi/linux/swab.h
+ * include/uapi/linux/byteorder/big_endian.h
+ * include/uapi/linux/byteorder/little_endian.h
+ * by @author Linus Torvalds et al.
+ *
+ */
+#ifndef BYTEORDER_H
+#define BYTEORDER_H
+
+#include <stdint.h>
+
+
+
+#ifdef __BIG_ENDIAN
+#undef __BIG_ENDIAN
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#undef __LITTLE_ENDIAN
+#endif
+
+#if (__sparc__)
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+#endif
+
+#if (__i386__ || __x86_64__)
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+#endif
+
+
+#define ___constant_swab16(x) ((uint16_t)(			\
+	(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) |		\
+	(((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
+
+#define ___constant_swab32(x) ((uint32_t)(			\
+	(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) |	\
+	(((uint32_t)(x) & (uint32_t)0x0000ff00UL) <<  8) |	\
+	(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >>  8) |	\
+	(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
+
+
+#ifdef USE_BUILTIN_BSWAP
+#if GCC_VERSION >= 40400
+#define __HAVE_BUILTIN_BSWAP32__
+#endif
+#if GCC_VERSION >= 40800
+#define __HAVE_BUILTIN_BSWAP16__
+#endif
+#endif /* USE_BUILTIN_BSWAP */
+
+
+static inline __attribute__((const)) uint16_t __fswab16(uint16_t val)
+{
+#ifdef __HAVE_BUILTIN_BSWAP16__
+	return __builtin_bswap16(val);
+#else
+	return ___constant_swab16(val);
+#endif
+}
+
+
+static inline __attribute__((const)) uint32_t __fswab32(uint32_t val)
+{
+#ifdef __HAVE_BUILTIN_BSWAP32__
+	return __builtin_bswap32(val);
+#else
+	return ___constant_swab32(val);
+#endif
+}
+
+
+/**
+ * @brief return a byteswapped 16-bit value
+ * @param x value to byteswap
+ */
+
+#define __swab16(x)				\
+	(__builtin_constant_p((uint16_t)(x)) ?	\
+	___constant_swab16(x) :			\
+	__fswab16(x))
+
+
+/**
+ * @brief return a byteswapped 32-bit value
+ * @param x a value to byteswap
+ */
+
+#define __swab32(x)				\
+	(__builtin_constant_p((uint32_t)(x)) ?	\
+	___constant_swab32(x) :			\
+	__fswab32(x))
+
+
+/**
+ * @brief return a byteswapped 16-bit value from a pointer
+ * @param p a pointer to a naturally-aligned 16-bit value
+ */
+static inline uint16_t __swab16p(const uint16_t *p)
+{
+	return __swab16(*p);
+}
+
+
+/**
+ * @brief return a byteswapped 32-bit value from a pointer
+ * @param p a pointer to a naturally-aligned 32-bit value
+ */
+static inline uint32_t __swab32p(const uint32_t *p)
+{
+	return __swab32(*p);
+}
+
+
+/**
+ * @brief byteswap a 16-bit value in-place
+ * @param p a pointer to a naturally-aligned 16-bit value
+ */
+
+static inline void __swab16s(uint16_t *p)
+{
+	*p = __swab16p(p);
+}
+
+
+/**
+ * @brief byteswap a 32-bit value in-place
+ * @param p a pointer to a naturally-aligned 32-bit value
+ */
+
+static inline void __swab32s(uint32_t *p)
+{
+	*p = __swab32p(p);
+}
+
+
+
+#ifdef __BIG_ENDIAN
+
+#define __cpu_to_le16(x)   ((uint16_t)__swab16((x)))
+#define __cpu_to_le32(x)   ((uint32_t)__swab32((x)))
+
+#define __cpu_to_le16s(x)  __swab16s((x))
+#define __cpu_to_le32s(x)  __swab32s((x))
+
+#define __cpu_to_be16(x)   ((uint16_t)(x))
+#define __cpu_to_be32(x)   ((uint32_t)(x))
+
+#define __cpu_to_be16s(x)  { (void)(x); }
+#define __cpu_to_be32s(x)  { (void)(x); }
+
+
+
+#define __le16_to_cpu(x)   __swab16((uint16_t)(x))
+#define __le32_to_cpu(x)   __swab32((uint32_t)(x))
+
+#define __le16_to_cpus(x)  __swab16s((x))
+#define __le32_to_cpus(x)  __swab32s((x))
+
+#define __be16_to_cpu(x)   ((uint16_t)(x))
+#define __be32_to_cpu(x)   ((uint32_t)(x))
+
+#define __be16_to_cpus(x)  { (void)(x); }
+#define __be32_to_cpus(x)  { (void)(x); }
+
+#endif /* __BIG_ENDIAN */
+
+
+#ifdef __LITTLE_ENDIAN
+
+#define __cpu_to_le16(x)   ((uint16_t)(x))
+#define __cpu_to_le32(x)   ((uint32_t)(x))
+
+#define __cpu_to_le16s(x)  { (void)(x); }
+#define __cpu_to_le32s(x)  { (void)(x); }
+
+#define __cpu_to_be16(x)   ((uint16_t)__swab16((x)))
+#define __cpu_to_be32(x)   ((uint32_t)__swab32((x)))
+
+#define __cpu_to_be16s(x)  __swab16s((x))
+#define __cpu_to_be32s(x)  __swab32s((x))
+
+
+
+#define __le16_to_cpu(x)  ((uint16_t)(x))
+#define __le32_to_cpu(x)  ((uint32_t)(x))
+
+#define __le32_to_cpus(x) { (void)(x); }
+#define __le16_to_cpus(x) { (void)(x); }
+
+#define __be16_to_cpu(x)  __swab16((uint16_t)(uint16_t)(x))
+#define __be32_to_cpu(x)  __swab32((uint32_t)(uint32_t)(x))
+
+#define __be16_to_cpus(x) __swab16s((x))
+#define __be32_to_cpus(x) __swab32s((x))
+
+#endif /* __LITTLE_ENDIAN */
+
+
+
+/** these are the conversion macros */
+
+/** convert cpu order to little endian */
+#define cpu_to_le16  __cpu_to_le16
+#define cpu_to_le32  __cpu_to_le32
+
+/** in-place convert cpu order to little endian */
+#define cpu_to_le16s __cpu_to_le16s
+#define cpu_to_le32s __cpu_to_le32s
+
+/** convert cpu order to big endian */
+#define cpu_to_be16  __cpu_to_be16
+#define cpu_to_be32  __cpu_to_be32
+
+/** in-place convert cpu order to big endian */
+#define cpu_to_be16s __cpu_to_be16s
+#define cpu_to_be32s __cpu_to_be32s
+
+
+/* same, but in reverse */
+
+/** convert little endian to cpu order*/
+#define le16_to_cpu  __le16_to_cpu
+#define le32_to_cpu  __le32_to_cpu
+
+/** in-place convert little endian to cpu order*/
+#define le16_to_cpus __le16_to_cpus
+#define le32_to_cpus __le32_to_cpus
+
+/** convert big endian to cpu order*/
+#define be16_to_cpu  __be16_to_cpu
+#define be32_to_cpu  __be32_to_cpu
+
+/** in-place convert big endian to cpu order*/
+#define be16_to_cpus __be16_to_cpus
+#define be32_to_cpus __be32_to_cpus
+
+
+
+#endif /* BYTEORDER_H */
diff --git a/include/cmp_data_types.h b/include/cmp_data_types.h
new file mode 100644
index 0000000..345c0ae
--- /dev/null
+++ b/include/cmp_data_types.h
@@ -0,0 +1,190 @@
+/**
+ * @file   cmp_data_types.h
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2020
+ * @brief definition of the different data types
+ *
+ * @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.
+ *
+ *
+ * Three data rates:
+ * 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
+ * The prefixes F, S and L stand for Fast, Short and Long cadence
+ */
+
+#ifndef CMP_DATA_TYPE_H
+#define CMP_DATA_TYPE_H
+
+#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;
+};
+
+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));
+
+#endif /* CMP_DATA_TYPE_H */
diff --git a/include/cmp_debug.h b/include/cmp_debug.h
new file mode 100644
index 0000000..ba345d2
--- /dev/null
+++ b/include/cmp_debug.h
@@ -0,0 +1,34 @@
+/**
+ * @file   cmp_debug.h
+ * @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 compression/decompression debugging defines
+ */
+
+#ifndef CMP_DEBUG_H
+#define CMP_DEBUG_H
+
+#include <stdio.h>
+
+#if defined(DEBUG) || DDEBUGLEVEL > 0
+	__extension__
+	#define debug_print(...) \
+		do { fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+	#define debug_print(...) \
+		do {} while (0)
+#endif
+
+
+#endif /* CMP_DEBUG_H */
diff --git a/include/cmp_icu.h b/include/cmp_icu.h
new file mode 100644
index 0000000..a2acd62
--- /dev/null
+++ b/include/cmp_icu.h
@@ -0,0 +1,28 @@
+/**
+ * @file   cmp_icu.h
+ * @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 compression library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ */
+
+#ifndef _CMP_ICU_H_
+#define _CMP_ICU_H_
+
+#include "../include/cmp_support.h"
+
+int icu_compress_data(struct cmp_cfg *cfg, struct cmp_info *info);
+
+#endif /* _CMP_ICU_H_ */
diff --git a/include/cmp_rdcu.h b/include/cmp_rdcu.h
new file mode 100644
index 0000000..ee5cffb
--- /dev/null
+++ b/include/cmp_rdcu.h
@@ -0,0 +1,43 @@
+/**
+ * @file   cmp_rdcu.h
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2019
+ *
+ * @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 hardware compressor control library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ */
+
+
+#ifndef _CMP_RDCU_H_
+#define _CMP_RDCU_H_
+
+#include <stdint.h>
+#include "../include/cmp_support.h"
+
+
+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_model(const struct cmp_info *info, void *model_buf);
+
+int rdcu_interrupt_compression(void);
+
+void rdcu_enable_interrput_signal(void);
+void rdcu_disable_interrput_signal(void);
+
+#endif /* _CMP_RDCU_H_ */
diff --git a/include/cmp_rdcu_extended.h b/include/cmp_rdcu_extended.h
new file mode 100644
index 0000000..a4f33e0
--- /dev/null
+++ b/include/cmp_rdcu_extended.h
@@ -0,0 +1,30 @@
+/**
+ * @file   cmp_rdcu_extended.h
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2021
+ *
+ * @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.
+ */
+
+
+#ifndef _CMP_RDCU_EXTENDED_H_
+#define _CMP_RDCU_EXTENDED_H_
+
+#include "../include/cmp_rdcu.h"
+
+int rdcu_start_compression(void);
+
+int rdcu_set_compression_register(const struct cmp_cfg *cfg);
+
+int rdcu_compress_data_parallel(const struct cmp_cfg *cfg,
+				const struct cmp_info *last_info);
+
+#endif /* _CMP_RDCU_EXTENDED_H_ */
diff --git a/include/cmp_support.h b/include/cmp_support.h
new file mode 100644
index 0000000..62dd1e6
--- /dev/null
+++ b/include/cmp_support.h
@@ -0,0 +1,184 @@
+/**
+ * @file   cmp_support.h
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2018
+ *
+ * @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 compression/decompression helper functions
+ */
+
+#ifndef CMP_SUPPORT_H
+#define CMP_SUPPORT_H
+
+#include <stdint.h>
+#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
+
+#define MAX_MODEL_VALUE                                                        \
+	16UL /* 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 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 SAM2BYT                                                                \
+	2 /* sample to byte conversion factor; one samples has 16 bits (2 bytes) */
+
+/**
+ * @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
+				     * 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 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 */
+	void *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)*/
+};
+
+
+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.
+ */
+
+struct cmp_status {
+	uint8_t cmp_ready; /* Data Compressor Ready; 0: Compressor is busy 1: Compressor is ready */
+	uint8_t cmp_active; /* Data Compressor Active; 0: Compressor is on hold; 1: Compressor is active */
+	uint8_t data_valid; /* Compressor Data Valid; 0: Data is invalid; 1: Data is valid */
+	uint8_t cmp_interrupted; /* Data Compressor Interrupted; HW only; 0: No compressor interruption; 1: Compressor was interrupted */
+	uint8_t rdcu_interrupt_en; /* RDCU Interrupt Enable; HW only; 0: Interrupt is disabled; 1: Interrupt is enabled */
+};
+
+
+/**
+ * @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
+ */
+
+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 */
+	uint32_t cmp_size;            /* Compressed data size; measured in bits */
+	uint32_t ap1_cmp_size;        /* Adaptive compressed data size 1; measured in bits */
+	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 */
+	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
+				       * [bit 2] model_value_err; The model_value parameter is not set correctly
+				       * [bit 3] cmp_par_err; The spill, golomb_par combination is not set correctly
+				       * [bit 4] ap1_cmp_par_err; The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression)
+				       * [bit 5] ap2_cmp_par_err; The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression)
+				       * [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) */
+};
+
+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 zero_escape_mech_is_used(unsigned int cmp_mode);
+int multi_escape_mech_is_used(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 cal_up_model(unsigned int data, unsigned int model, unsigned int
+			  model_value);
+
+uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode);
+
+size_t size_of_a_sample(unsigned int cmp_mode);
+unsigned int size_of_bitstream(unsigned int cmp_size);
+unsigned int size_of_model(unsigned int samples, unsigned int cmp_mode);
+
+void print_cmp_cfg(const struct cmp_cfg *cfg);
+void print_cmp_info(const struct cmp_info *info);
+
+#endif /* CMP_SUPPORT_H */
diff --git a/include/decmp.h b/include/decmp.h
new file mode 100644
index 0000000..139273f
--- /dev/null
+++ b/include/decmp.h
@@ -0,0 +1,31 @@
+/**
+ * @file   decmp.h
+ * @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
+ */
+
+#ifndef DECMP_H_
+#define DECMP_H_
+
+#include "../include/cmp_support.h"
+
+void *malloc_decompressed_data(const struct cmp_info *info);
+
+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);
+
+#endif /* DECMP_H_ */
diff --git a/include/rdcu_cmd.h b/include/rdcu_cmd.h
new file mode 100644
index 0000000..0e4b8f4
--- /dev/null
+++ b/include/rdcu_cmd.h
@@ -0,0 +1,162 @@
+/**
+ * @file   rdcu_cmd.h
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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.
+ *
+ * @see FPGA Requirement Specification PLATO-IWF-PL-RS-005 Issue 0.6
+ */
+#ifndef _RDCU_CMD_H_
+#define _RDCU_CMD_H_
+
+#include <stdint.h>
+
+/* readable RDCU register addresses (RDCU-FRS-FN-0284) */
+#define FPGA_VERSION			0x10000000UL
+#define RDCU_STATUS			0x10000004UL
+#define LVDS_CORE_STATUS		0x10000008UL
+#define SPW_LINK_STATUS			0x1000000CUL
+#define SPW_ERR_CNTRS			0x10000010UL
+#define RMAP_LAST_ERR			0x10000014UL
+#define RMAP_NO_REPLY_ERR_CNTRS		0x10000018UL
+#define RMAP_PCKT_ERR_CNTRS		0x1000001CUL
+#define ADC_VALUES_1			0x10000020UL
+#define ADC_VALUES_2			0x10000024UL
+#define ADC_VALUES_3			0x10000028UL
+#define ADC_VALUES_4			0x1000002CUL
+#define ADC_STATUS			0x10000030UL
+/* spare: 0x10000034UL */
+#define COMPR_STATUS			0x10000038UL
+/* spare: 0x1000003CUL */
+
+/* writeable RDCU register addresses (RDCU-FRS-FN-0284) */
+#define RDCU_RESET			0x10000040UL
+#define SPW_LINK_CTRL			0x10000044UL
+#define LVDS_CTRL			0x10000048UL
+#define CORE_CTRL			0x1000004CUL
+#define ADC_CTRL			0x10000050UL
+/* spare: 0x10000054UL */
+#define COMPR_CTRL			0x10000058UL
+/* spare: 0x1000005CUL */
+
+
+
+/* writeable Data Compressor register addresses (RDCU-FRS-FN-0288) */
+#define COMPR_PARAM_1			0x11000000UL
+#define COMPR_PARAM_2			0x11000004UL
+#define ADAPTIVE_PARAM_1		0x11000008UL
+#define ADAPTIVE_PARAM_2		0x1100000CUL
+#define DATA_START_ADDR			0x11000010UL
+#define MODEL_START_ADDR		0x11000014UL
+#define NUM_SAMPLES			0x11000018UL
+#define UPDATED_MODEL_START_ADDR	0x1100001CUL
+#define COMPR_DATA_BUF_START_ADDR	0x11000020UL
+#define COMPR_DATA_BUF_LEN		0x11000024UL
+/* spare: 0x11000028UL */
+/* spare: 0x1100002CUL */
+
+/* readable Data Compressor register addresses (RDCU-FRS-FN-0288) */
+#define USED_COMPR_PARAM_1		0x11000030UL
+#define USED_COMPR_PARAM_2		0x11000034UL
+#define COMPR_DATA_START_ADDR		0x11000038UL
+#define COMPR_DATA_SIZE			0x1100003CUL
+#define COMPR_DATA_ADAPTIVE_1_SIZE	0x11000040UL
+#define COMPR_DATA_ADAPTIVE_2_SIZE	0x11000044UL
+#define COMPR_ERROR			0x11000048UL
+#define USED_UPDATED_MODEL_START_ADDR	0x1100004CUL
+#define USED_NUMBER_OF_SAMPLES		0x11000050UL
+/* spare: 0x11000054UL */
+/* spare: 0x11000058UL */
+/* spare: 0x1100005CUL */
+
+
+/* writeable SRAM EDAC register addresses (RDCU-FRS-FN-0292) */
+#define SRAM_EDAC_CTRL			0x01000000UL
+/* spare: 0x01000004UL */
+
+/* readable SRAM EDAC register addresses (RDCU-FRS-FN-0292) */
+#define SRAM_EDAC_STATUS		0x01000008UL
+/* spare: 0x0100000CUL */
+
+/* SRAM address range (RDCU-FRS-FN-0280) */
+#define RDCU_SRAM_START			0x00000000UL
+#define RDCU_SRAM_END			0x007FFFFFUL
+#define RDCU_SRAM_SIZE			(RDCU_SRAM_END - RDCU_SRAM_START + 1UL)
+
+
+
+
+int rdcu_read_cmd_register(uint16_t trans_id, uint8_t *cmd, uint32_t addr);
+int rdcu_write_cmd_register(uint16_t trans_id, uint8_t *cmd, uint32_t addr);
+
+int rdcu_write_cmd_data(uint16_t trans_id, uint8_t *cmd,
+			uint32_t addr, uint32_t size);
+int rdcu_read_cmd_data(uint16_t trans_id, uint8_t *cmd,
+		       uint32_t addr, uint32_t size);
+
+
+/* RDCU read accessors */
+int rdcu_read_cmd_fpga_version(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_rdcu_status(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_lvds_core_status(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_spw_link_status(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_spw_err_cntrs(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_rmap_last_err(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_rmap_no_reply_err_cntrs(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_rmap_pckt_err_cntrs(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_adc_values_1(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_adc_values_2(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_adc_values_3(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_adc_values_4(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_adc_status(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_compr_status(uint16_t trans_id, uint8_t *cmd);
+
+/* RDCU read accessors */
+int rdcu_write_cmd_rdcu_reset(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_spw_link_ctrl(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_lvds_ctrl(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_core_ctrl(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_adc_ctrl(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_compr_ctrl(uint16_t trans_id, uint8_t *cmd);
+
+/* Data Compressor write accessors */
+int rdcu_write_cmd_compressor_param1(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_compressor_param2(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_adaptive_param1(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_adaptive_param2(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_data_start_addr(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_model_start_addr(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_num_samples(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_new_model_start_addr(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_compr_data_buf_start_addr(uint16_t trans_id, uint8_t *cmd);
+int rdcu_write_cmd_compr_data_buf_len(uint16_t trans_id, uint8_t *cmd);
+
+/* Data Compressor read accessors */
+int rdcu_read_cmd_used_param1(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_used_param2(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_compr_data_start_addr(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_compr_data_size(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_compr_data_adaptive_1_size(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_compr_data_adaptive_2_size(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_compr_error(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_new_model_addr_used(uint16_t trans_id, uint8_t *cmd);
+int rdcu_read_cmd_samples_used(uint16_t trans_id, uint8_t *cmd);
+
+
+/* SRAM EDAC read accessors */
+int rdcu_read_cmd_sram_edac_status(uint16_t trans_id, uint8_t *cmd);
+
+/* SRAM EDAC write accessors */
+int rdcu_write_cmd_sram_edac_ctrl(uint16_t trans_id, uint8_t *cmd);
+
+
+#endif /* _RDCU_CMD_H_ */
diff --git a/include/rdcu_ctrl.h b/include/rdcu_ctrl.h
new file mode 100644
index 0000000..ec5b9a2
--- /dev/null
+++ b/include/rdcu_ctrl.h
@@ -0,0 +1,284 @@
+/**
+ * @file   rdcu_ctrl.h
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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.
+ *
+ * @see FPGA Requirement Specification PLATO-IWF-PL-RS-005 Issue 0.6
+ */
+#ifndef _RDCU_CTRL_H_
+#define _RDCU_CTRL_H_
+
+#include <stdint.h>
+
+
+struct rdcu_mirror {
+	/* RDCU registers */
+	uint32_t fpga_version;			/* RDCU-FRS-FN-0522 */
+	uint32_t rdcu_status;			/* RDCU-FRS-FN-0532 */
+	uint32_t lvds_core_status;		/* RDCU-FRS-FN-0542 */
+	uint32_t spw_link_status;		/* RDCU-FRS-FN-0552 */
+	uint32_t spw_err_cntrs;			/* RDCU-FRS-FN-0562 */
+	uint32_t rmap_last_err;			/* RDCU-FRS-FN-0572 */
+	uint32_t rmap_no_reply_err_cntrs;	/* RDCU-FRS-FN-0582 */
+	uint32_t rmap_pckt_err_cntrs;		/* RDCU-FRS-FN-0592 */
+	uint32_t adc_values_1;			/* RDCU-FRS-FN-0602 */
+	uint32_t adc_values_2;
+	uint32_t adc_values_3;
+	uint32_t adc_values_4;
+	uint32_t adc_status;			/* RDCU-FRS-FN-0610 */
+	uint32_t compr_status;			/* RDCU-FRS-FN-0632 */
+	uint32_t rdcu_reset;			/* RDCU-FRS-FN-0662 */
+	uint32_t spw_link_ctrl;			/* RDCU-FRS-FN-0672 */
+	uint32_t lvds_ctrl;			/* RDCU-FRS-FN-0682 */
+	uint32_t core_ctrl;			/* RDCU-FRS-FN-0692 */
+	uint32_t adc_ctrl;			/* RDCU-FRS-FN-0712 */
+	uint32_t compr_ctrl;			/* RDCU-FRS-FN-0732 */
+
+	/* Data Compressor registers */
+	uint32_t compressor_param1;		/* RDCU-FRS-FN-0772 */
+	uint32_t compressor_param2;		/* RDCU-FRS-FN-0782 */
+	uint32_t adaptive_param1;		/* RDCU-FRS-FN-0792 */
+	uint32_t adaptive_param2;		/* RDCU-FRS-FN-0802 */
+	uint32_t data_start_addr;		/* RDCU-FRS-FN-0812 */
+	uint32_t model_start_addr;		/* RDCU-FRS-FN-0822 */
+	uint32_t num_samples;			/* RDCU-FRS-FN-0832 */
+	uint32_t new_model_start_addr;		/* RDCU-FRS-FN-0842 */
+	uint32_t compr_data_buf_start_addr;	/* RDCU-FRS-FN-0852 */
+	uint32_t compr_data_buf_len;		/* RDCU-FRS-FN-0862 */
+
+	uint32_t used_param1;			/* RDCU-FRS-FN-0892 */
+	uint32_t used_param2;			/* RDCU-FRS-FN-0902 */
+	uint32_t compr_data_start_addr;		/* RDCU-FRS-FN-0912 */
+	uint32_t compr_data_size;		/* RDCU-FRS-FN-0922 */
+	uint32_t compr_data_adaptive_1_size;	/* RDCU-FRS-FN-0932 */
+	uint32_t compr_data_adaptive_2_size;	/* RDCU-FRS-FN-0942 */
+	uint32_t compr_error;			/* RDCU-FRS-FN-0952 */
+	uint32_t new_model_addr_used;		/* RDCU-FRS-FN-0962 */
+	uint32_t samples_used;			/* RDCU-FRS-FN-0970 */
+
+
+	/* SRAM EDAC registers */
+	uint32_t sram_edac_ctrl;		/* RDCU-FRS-FN-1012 */
+	uint32_t sram_edac_status;		/* RDCU-FRS-FN-1032 */
+
+	uint8_t *sram;				/* RDCU-FRS-FN-0280 */
+};
+
+
+/* RDCU registers */
+int rdcu_sync_fpga_version(void);
+int rdcu_sync_rdcu_status(void);
+int rdcu_sync_lvds_core_status(void);
+int rdcu_sync_spw_link_status(void);
+int rdcu_sync_spw_err_cntrs(void);
+int rdcu_sync_rmap_last_err(void);
+int rdcu_sync_rmap_no_reply_err_cntrs(void);
+int rdcu_sync_rmap_pckt_err_cntrs(void);
+int rdcu_sync_adc_values(int id);
+int rdcu_sync_adc_status(void);
+int rdcu_sync_compr_status(void);
+int rdcu_sync_rdcu_reset(void);
+int rdcu_sync_spw_link_ctrl(void);
+int rdcu_sync_lvds_ctrl(void);
+int rdcu_sync_core_ctrl(void);
+int rdcu_sync_adc_ctrl(void);
+int rdcu_sync_compr_ctrl(void);
+
+
+/* Data Compressor registers */
+int rdcu_sync_compressor_param1(void);
+int rdcu_sync_compressor_param2(void);
+int rdcu_sync_adaptive_param1(void);
+int rdcu_sync_adaptive_param2(void);
+int rdcu_sync_data_start_addr(void);
+int rdcu_sync_model_start_addr(void);
+int rdcu_sync_num_samples(void);
+int rdcu_sync_new_model_start_addr(void);
+int rdcu_sync_compr_data_buf_start_addr(void);
+int rdcu_sync_compr_data_buf_len(void);
+
+int rdcu_sync_used_param1(void);
+int rdcu_sync_used_param2(void);
+int rdcu_sync_compr_data_start_addr(void);
+int rdcu_sync_compr_data_size(void);
+int rdcu_sync_compr_data_adaptive_1_size(void);
+int rdcu_sync_compr_data_adaptive_2_size(void);
+int rdcu_sync_compr_error(void);
+int rdcu_sync_new_model_addr_used(void);
+int rdcu_sync_samples_used(void);
+
+/* SRAM EDAC registers */
+int rdcu_sync_sram_edac_ctrl(void);
+int rdcu_sync_sram_edac_status(void);
+
+/* SRAM */
+int rdcu_sync_mirror_to_sram(uint32_t addr, uint32_t size, uint32_t mtu);
+int rdcu_sync_sram_to_mirror(uint32_t addr, uint32_t size, uint32_t mtu);
+int rdcu_sync_sram_mirror_parallel(uint32_t rx_addr, uint32_t rx_size,
+				   uint32_t tx_addr, uint32_t tx_size,
+				   uint32_t mtu);
+
+/* RDCU registers */
+uint16_t rdcu_get_fpga_version(void);
+
+uint32_t rdcu_get_rdcu_status_board_serial_number(void);
+uint32_t rdcu_get_rdcu_status_fpga_core_power_good(void);
+uint32_t rdcu_get_rdcu_status_io_power_good(void);
+uint32_t rdcu_get_rdcu_status_reset_by_register(void);
+uint32_t rdcu_get_rdcu_status_power_on_reset(void);
+
+uint8_t rdcu_get_rmap_target_logical_address(void);
+uint8_t rdcu_get_rmap_target_cmd_key(void);
+uint32_t rdcu_get_lvds_link_enabled(uint32_t link);
+
+uint16_t rdcu_get_spw_empty_pckt_cnt(void);
+uint8_t  rdcu_get_spw_run_clk_div(void);
+uint8_t  rdcu_get_spw_lnk_run_state(void);
+
+uint8_t rdcu_get_spw_lnk_credit_errs(void);
+uint8_t rdcu_get_spw_lnk_escape_errs(void);
+uint8_t rdcu_get_spw_lnk_parity_errs(void);
+uint8_t rdcu_get_spw_lnk_disconnect_errs(void);
+
+uint8_t rdcu_get_rmap_last_error_user_code(void);
+uint8_t rdcu_get_rmap_last_error_standard_code(void);
+
+uint8_t rdcu_get_rmap_incomplete_hdrs(void);
+uint8_t rdcu_get_rmap_recv_reply_pckts(void);
+uint8_t rdcu_get_recv_non_rmap_pckts(void);
+
+uint8_t rdcu_get_rmap_pckt_errs(void);
+uint8_t rdcu_get_rmap_oper_errs(void);
+uint8_t rdcu_get_rmap_cmd_auth_errs(void);
+uint8_t rdcu_get_rmap_hdr_errs(void);
+
+uint16_t rdcu_get_adc_value(int id);
+
+uint32_t rdcu_get_valid_adc_values(void);
+uint32_t rdcu_get_adc_logic_reset(void);
+uint32_t rdcu_get_adc_logic_enabled(void);
+
+
+uint32_t rdcu_get_rdcu_interrupt_enabled(void);
+uint32_t rdcu_get_compr_status_valid(void);
+uint32_t rdcu_get_data_compr_ready(void);
+uint32_t rdcu_get_data_compr_interrupted(void);
+uint32_t rdcu_get_data_compr_active(void);
+
+
+void rdcu_set_rdcu_board_reset_keyword(uint8_t key);
+void rdcu_set_rdcu_bus_reset(void);
+void rdcu_clear_rdcu_bus_reset(void);
+void rdcu_set_rdcu_rmap_error_cntr_reset(void);
+void rdcu_clear_rdcu_rmap_error_cntr_reset(void);
+void rdcu_set_rdcu_spw_error_cntr_reset(void);
+void rdcu_clear_rdcu_spw_error_cntr_reset(void);
+void rdcu_set_rdcu_board_reset(void);
+void rdcu_clear_rdcu_board_reset(void);
+
+int rdcu_set_spw_link_run_clkdiv(uint8_t div);
+
+int rdcu_set_lvds_link_enabled(uint32_t link);
+int rdcu_set_lvds_link_disabled(uint32_t link);
+
+
+void rdcu_set_rmap_target_logical_address(uint8_t addr);
+void rdcu_set_rmap_target_cmd_key(uint8_t key);
+
+void rdcu_set_adc_logic_reset(void);
+void rdcu_clear_adc_logic_reset(void);
+void rdcu_set_adc_logic_enabled(void);
+void rdcu_set_adc_logic_disabled(void);
+
+void rdcu_set_rdcu_interrupt(void);
+void rdcu_clear_rdcu_interrupt(void);
+void rdcu_set_data_compr_interrupt(void);
+void rdcu_clear_data_compr_interrupt(void);
+void rdcu_set_data_compr_start(void);
+void rdcu_clear_data_compr_start(void);
+
+
+
+/* Data Compressor registers */
+int rdcu_set_noise_bits_rounded(uint32_t rpar);
+int rdcu_set_weighting_param(uint32_t mval);
+int rdcu_set_compression_mode(uint32_t cmode);
+
+int rdcu_set_spillover_threshold(uint32_t spill);
+int rdcu_set_golomb_param(uint32_t gpar);
+
+int rdcu_set_adaptive_1_spillover_threshold(uint32_t spill);
+int rdcu_set_adaptive_1_golomb_param(uint32_t gpar);
+
+int rdcu_set_adaptive_2_spillover_threshold(uint32_t spill);
+int rdcu_set_adaptive_2_golomb_param(uint32_t gpar);
+
+int rdcu_set_data_start_addr(uint32_t addr);
+
+int rdcu_set_model_start_addr(uint32_t addr);
+
+int rdcu_set_num_samples(uint32_t samples);
+
+int rdcu_set_new_model_start_addr(uint32_t addr);
+
+int rdcu_set_compr_data_buf_start_addr(uint32_t addr);
+
+int rdcu_set_compr_data_buf_len(uint32_t samples);
+
+
+uint32_t rdcu_get_compression_mode(void);
+uint32_t rdcu_get_noise_bits_rounded(void);
+uint32_t rdcu_get_weighting_param(void);
+
+uint32_t rdcu_get_spillover_threshold(void);
+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_adaptive_1_size(void);
+
+uint32_t rdcu_get_compr_data_adaptive_2_size(void);
+
+uint16_t rdcu_get_compr_error(void);
+
+uint32_t rdcu_get_new_model_addr_used(void);
+
+uint32_t rdcu_get_samples_used(void);
+
+/* SRAM EDAC registers */
+int rdcu_edac_set_sub_chip_die_addr(uint32_t ca);
+void rdcu_edac_set_ctrl_reg_read_op(void);
+void rdcu_edac_set_ctrl_reg_write_op(void);
+void rdcu_edac_set_bypass(void);
+void rdcu_edac_clear_bypass(void);
+void rdcu_edac_set_scrub_info(uint8_t nfo);
+
+
+uint32_t rdcu_edac_get_sub_chip_die_addr(void);
+uint32_t rdcu_edac_get_bypass_status(void);
+uint8_t rdcu_edac_get_scrub_info(void);
+
+/* SRAM */
+int rdcu_read_sram(void *buf, uint32_t addr, uint32_t size);
+int rdcu_write_sram(void *buf, uint32_t addr, uint32_t size);
+int rdcu_write_sram_8(uint8_t *buf, uint32_t addr, uint32_t size);
+int rdcu_write_sram_16(uint16_t *buf, uint32_t addr, uint32_t size);
+int rdcu_write_sram_32(uint32_t *buf, uint32_t addr, uint32_t size);
+
+
+int rdcu_ctrl_init(void);
+
+
+#endif /* _RDCU_CTRL_H_ */
diff --git a/include/rdcu_pkt_to_file.h b/include/rdcu_pkt_to_file.h
new file mode 100644
index 0000000..87c3d4b
--- /dev/null
+++ b/include/rdcu_pkt_to_file.h
@@ -0,0 +1,39 @@
+/**
+ * @file   rdcu_pkt_to_file.h
+ * @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.
+ *
+ */
+
+#ifndef _RDCU_PKT_TO_FILE_H_
+#define _RDCU_PKT_TO_FILE_H_
+
+#include "cmp_support.h"
+
+/* directory where the tc files are stored, when --rdcu_pkt option is set */
+#define TC_DIR "TC_FILES"
+
+#define RDCU_DEST_KEY	0x0
+
+#define MAX_TC_FOLDER_DIR_LEN 256
+
+int init_rmap_pkt_to_file(void);
+
+void set_tc_folder_dir(const char *dir_name);
+
+int gen_write_rdcu_pkts(const struct cmp_cfg *cfg);
+int gen_read_rdcu_pkts(const struct cmp_info *info);
+int gen_rdcu_parallel_pkts(const struct cmp_cfg *cfg,
+			   const struct cmp_info *last_info);
+
+#endif /* _RDCU_PKT_TO_FILE_H_ */
diff --git a/include/rdcu_rmap.h b/include/rdcu_rmap.h
new file mode 100644
index 0000000..b6ce568
--- /dev/null
+++ b/include/rdcu_rmap.h
@@ -0,0 +1,65 @@
+/**
+ * @file   rdcu_rmap.h
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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.
+ *
+ */
+
+#ifndef _RDCU_RMAP_H_
+#define _RDCU_RMAP_H_
+
+#include <stdint.h>
+
+
+
+int rdcu_submit_tx(const uint8_t *cmd,  int cmd_size,
+		   const uint8_t *data, int data_size);
+
+
+int rdcu_gen_cmd(uint16_t trans_id, uint8_t *cmd,
+		 uint8_t rmap_cmd_type,
+		 uint32_t addr, uint32_t size);
+
+int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd),
+	      void *addr, int data_len);
+
+int rdcu_sync_data(int (*fn)(uint16_t trans_id, uint8_t *cmd,
+			     uint32_t addr, uint32_t data_len),
+		   uint32_t addr, void *data, uint32_t data_len, int read);
+
+int rdcu_package(uint8_t *blob,
+		 const uint8_t *cmd, uint32_t cmd_size,
+		 const uint8_t non_crc_bytes,
+		 const uint8_t *data, uint32_t data_size);
+
+void rdcu_set_destination_logical_address(uint8_t addr);
+
+int rdcu_set_destination_path(uint8_t *path, uint8_t len);
+int rdcu_set_return_path(uint8_t *path, uint8_t len);
+void rdcu_set_source_logical_address(uint8_t addr);
+void rdcu_set_destination_key(uint8_t key);
+size_t rdcu_get_data_mtu(void);
+
+int rdcu_rmap_sync_status(void);
+
+void rdcu_rmap_reset_log(void);
+
+int rdcu_rmap_init(size_t mtu,
+		   int32_t (*tx)(const void *hdr,  uint32_t hdr_size,
+				 const uint8_t non_crc_bytes,
+				 const void *data, uint32_t data_size),
+		   uint32_t (*rx)(uint8_t *pkt));
+
+
+
+#endif /* _RDCU_RMAP_H_ */
diff --git a/include/rmap.h b/include/rmap.h
new file mode 100644
index 0000000..5156679
--- /dev/null
+++ b/include/rmap.h
@@ -0,0 +1,217 @@
+/**
+ * @file   rmap.h
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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 rmap command/reply helper functions
+ */
+
+#ifndef RMAP_H
+#define RMAP_H
+
+#include <stdint.h>
+
+/**
+ * valid RMAP command codes, see Table 5-1 of ECSS‐E‐ST‐50‐52C
+ *
+ * all valid commands are made up of the four bits below
+ */
+
+
+#define RMAP_CMD_BIT_WRITE			0x8
+#define RMAP_CMD_BIT_VERIFY			0x4
+#define RMAP_CMD_BIT_REPLY			0x2
+#define RMAP_CMD_BIT_INC			0x1
+
+#define RMAP_READ_ADDR_SINGLE			0x2
+#define RMAP_READ_ADDR_INC			0x3
+#define RMAP_READ_MODIFY_WRITE_ADDR_INC		0x7
+#define RMAP_WRITE_ADDR_SINGLE			0x8
+#define RMAP_WRITE_ADDR_INC			0x9
+#define RMAP_WRITE_ADDR_SINGLE_REPLY		0xa
+#define RMAP_WRITE_ADDR_INC_REPLY		0xb
+#define RMAP_WRITE_ADDR_SINGLE_VERIFY		0xc
+#define RMAP_WRITE_ADDR_INC_VERIFY		0xd
+#define RMAP_WRITE_ADDR_SINGLE_VERIFY_REPLY	0xe
+#define RMAP_WRITE_ADDR_INC_VERIFY_REPLY	0xf
+
+/**
+ * RMAP error and status codes, see Table 5-4 of ECSS‐E‐ST‐50‐52C
+ */
+
+#define RMAP_STATUS_SUCCESS			0x0
+#define RMAP_STATUS_GENERAL_ERROR		0x1
+#define RMAP_STATUS_UNUSED_TYPE_OR_CODE		0x2
+#define RMAP_STATUS_INVALID_KEY			0x3
+#define RMAP_STATUS_INVALID_DATA_CRC		0x4
+#define RMAP_STATUS_EARLY_EOP			0x5
+#define RMAP_STATUS_TOO_MUCH_DATA		0x6
+#define RMAP_STATUS_EEP				0x7
+#define RMAP_STATUS_RESERVED			0x8
+#define RMAP_STATUS_VERIFY_BUFFER_OVERRRUN	0x9
+#define RMAP_STATUS_CMD_NOT_IMPL_OR_AUTH	0xa
+#define RMAP_STATUS_RMW_DATA_LEN_ERROR		0xb
+#define RMAP_STATUS_INVALID_TARGET_LOGICAL_ADDR	0xc
+
+
+/**
+ * RMAP minimum header sizes, see ECSS‐E‐ST‐50‐52C
+ */
+
+#define RMAP_HDR_MIN_SIZE_WRITE_CMD		15
+#define RMAP_HDR_MIN_SIZE_WRITE_REP		 7
+
+#define RMAP_HDR_MIN_SIZE_READ_CMD		RMAP_HDR_MIN_SIZE_WRITE_CMD
+#define RMAP_HDR_MIN_SIZE_READ_REP		11
+
+#define RMAP_HDR_MIN_SIZE_RMW_CMD		RMAP_HDR_MIN_SIZE_READ_CMD
+#define RMAP_HDR_MIN_SIZE_RMW_REP		RMAP_HDR_MIN_SIZE_READ_REP
+
+
+
+/* RMAP header bytes in relative offsets following last entry in target path */
+#define RMAP_DEST_ADDRESS	0x00
+#define RMAP_PROTOCOL_ID	0x01
+#define RMAP_INSTRUCTION	0x02
+#define RMAP_CMD_DESTKEY	0x03
+#define RMAP_REPLY_STATUS	RMAP_CMD_DESTKEY
+#define RMAP_REPLY_ADDR_START	0x04	/* optional */
+
+/* RMAP header bytes in relative offsets, add (reply address length * 4) */
+#define RMAP_SRC_ADDR		0x04
+#define RMAP_TRANS_ID_BYTE0	0x05
+#define RMAP_TRANS_ID_BYTE1	0x06
+
+/* depending on the command, this is 0 or may contain an address extension */
+#define RMAP_RESERVED		0x07
+#define RMAP_EXTENDED		RMAP_RESERVED
+
+/* optional RMAP header bytes in relative offsets */
+#define RMAP_ADDR_BYTE0		0x08
+#define RMAP_ADDR_BYTE1		0x09
+#define RMAP_ADDR_BYTE2		0x0a
+#define RMAP_ADDR_BYTE3		0x0b
+
+/* RMAP header bytes in relative offsets (add extra 4 if address present)  */
+#define RMAP_DATALEN_BYTE0	0x08
+#define RMAP_DATALEN_BYTE1	0x09
+#define RMAP_DATALEN_BYTE2	0x0a
+#define RMAP_HEADER_CRC		0x0b
+#define RMAP_DATA_START		0x0c
+
+/**
+ * While the size of a SpW packet is in principl not limited, the size of the
+ * header cannot be more than 255 bytes given the 8-bit width of the transfer
+ * descriptor's HEADERLEN field in the GRSPW2 core, so we'll use that as our
+ * limit.
+ *
+ * The reply address path can be at most 12 bytes, as the reply address length
+ * field in the RMAP instruction field is only 2 bits wide and counts the
+ * number of 32 bit words needed to hold the return path.
+ *
+ * The maximum data length is 2^24-1 bits
+ *
+ * All other fields in the header (not counting the header CRC) amount to
+ * 27 bytes.
+ *
+ * @see GR712RC-UM v2.7 p112 and ECSS‐E‐ST‐50‐52C e.g. 5.3.1.1
+ */
+
+#define RMAP_MAX_PATH_LEN		 15
+#define RMAP_MAX_REPLY_ADDR_LEN		  3
+#define RMAP_MAX_REPLY_PATH_LEN		 12
+#define RMAP_MAX_DATA_LEN	   0xFFFFFFUL
+
+
+
+__extension__
+struct rmap_instruction {
+#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+	uint8_t	reserved:1;
+	uint8_t	cmd_resp:1;
+	uint8_t cmd:4;
+	uint8_t	reply_addr_len:2;
+#elif (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+	uint8_t	reply_addr_len:2;
+	uint8_t cmd:4;
+	uint8_t	cmd_resp:1;
+	uint8_t	reserved:1;
+#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
+
+
+/**
+ * This structure holds the relevant contents of an RMAP packet.
+ *
+ * @note this is NOT an actual RMAP packet!
+ */
+
+__extension__
+struct rmap_pkt {
+	uint8_t		*path;		/* path to SpW target */
+	uint8_t		path_len;	/* entries in the path */
+	uint8_t		dst;		/* target logical address */
+	uint8_t		proto_id;	/* protoco id (0x1 = RMAP */
+	union {
+		struct rmap_instruction ri;
+		uint8_t	instruction;
+	};
+	union {
+		uint8_t	key;		/* command authorisation key */
+		uint8_t	status;		/* reply error/status codes */
+	};
+	uint8_t		src;		/* initiator logical address */
+	uint8_t		*rpath;		/* reply path */
+	uint8_t		rpath_len;	/* entries in the reply path */
+	uint16_t	tr_id;		/* transaction identifier */
+	uint32_t	addr;		/* (first) data address */
+	uint8_t		*data;
+	uint32_t	data_len;	/* lenght of data in bytes */
+	uint8_t		hdr_crc;
+	uint8_t		data_crc;
+};
+
+
+
+uint8_t rmap_crc8(const uint8_t *buf, const size_t len);
+
+struct rmap_pkt *rmap_create_packet(void);
+struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len);
+int rmap_build_hdr(struct rmap_pkt *pkt, uint8_t *hdr);
+int rmap_set_data_len(struct rmap_pkt *pkt, uint32_t len);
+void rmap_set_data_addr(struct rmap_pkt *pkt, uint32_t addr);
+int rmap_set_cmd(struct rmap_pkt *pkt, uint8_t cmd);
+
+
+void rmap_set_dst(struct rmap_pkt *pkt, uint8_t addr);
+void rmap_set_src(struct rmap_pkt *pkt, uint8_t addr);
+void rmap_set_key(struct rmap_pkt *pkt, uint8_t key);
+void rmap_set_tr_id(struct rmap_pkt *pkt, uint16_t id);
+
+int rmap_set_reply_path(struct rmap_pkt *pkt, const uint8_t *rpath, uint8_t len);
+int rmap_set_dest_path(struct rmap_pkt *pkt, const uint8_t *path, uint8_t len);
+
+
+void rmap_erase_packet(struct rmap_pkt *pkt);
+
+
+void rmap_parse_pkt(uint8_t *pkt);
+
+
+#endif /* RMAP_H */
diff --git a/include/tool_lib.h b/include/tool_lib.h
new file mode 100644
index 0000000..3592078
--- /dev/null
+++ b/include/tool_lib.h
@@ -0,0 +1,46 @@
+/**
+ * @file   tool_lib.h
+ * @author Johannes Seelig (johannes.seelig@univie.ac.at)
+ * @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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cmp_support.h"
+#include "rdcu_pkt_to_file.h"
+
+#define PROGRAM_NAME "cmp_tool"
+#define MAX_CONFIG_LINE 256
+
+#define DEFAULT_OUTPUT_PREFIX "OUTPUT"
+
+void Print_Help(const char *argv);
+
+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);
+
+uint16_t * read_file16(const char *file_name, uint32_t samples, int verbose_en);
+uint32_t * read_file32(const char *file_name, uint32_t buf_len, int verbose_en);
+
+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);
+
+void print_cfg(const struct cmp_cfg *cfg, int rdcu_cfg);
+
+int write_info(const struct cmp_info *info, const char *output_prefix,
+	       int machine_cfg);
diff --git a/lib/cmp_data_types.c b/lib/cmp_data_types.c
new file mode 100644
index 0000000..e6bbe92
--- /dev/null
+++ b/lib/cmp_data_types.c
@@ -0,0 +1,647 @@
+/**
+ * @file    cmp_data_types.c
+ * @author  Dominik Loidolt (dominik.loidolt@univie.ac.at)
+ * @date    2020
+ * @brief   collection of functions to handle the different compression data types
+ *
+ * @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.
+ *
+ */
+
+
+#include <stddef.h>
+#include <stdio.h>
+
+#include "../include/cmp_data_types.h"
+#include "../include/cmp_support.h"
+#include "../include/cmp_debug.h"
+
+
+/**
+ * @brief rounding down the least significant digits of a uint16_t data buffer
+ *
+ * @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
+ */
+
+int lossy_rounding_16(uint16_t *data_buf, unsigned int samples, unsigned int
+		      round)
+{
+	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] = round_fwd(data_buf[i], round);  /* this is the lossy step */
+
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int de_lossy_rounding_16(uint16_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)
+		return 0;
+
+	for (i = 0; i < samples_used; i++) {
+		/* check if data are not to big for a overflow */
+		uint16_t mask = (uint16_t)(~0 << (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);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief rounding down the least significant digits of a uint32_t data buffer
+ *
+ * @note this step involves data loss (if round > 0)
+ * @note change the data buffer in-place
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int lossy_rounding_32(uint32_t *data_buf, unsigned int samples, unsigned int
+		      round)
+{
+	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] = round_fwd(data_buf[i], round);  /* this is the lossy step */
+
+	return 0;
+}
+
+
+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)
+		return 0;
+
+	for (i = 0; i < samples_used; i++) {
+		/* check if data are not to big for a overflow */
+		uint32_t mask = (uint32_t)(~0 << (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;
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples, unsigned
+			int round)
+{
+	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);
+
+	return 0;
+}
+
+
+int de_lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples_used,
+			   unsigned int round_used)
+{
+	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("Errolr: de_lossy_rounding_S_FX failed\n");
+			return -1;
+		}
+
+		data_buf[i].FX = round_inv(data_buf[i].FX, round_used);
+	}
+	return 0;
+}
+
+
+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 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);
+
+	return result;
+}
+
+
+struct S_FX_EFX sub_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b)
+{
+	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;
+
+	return result;
+}
+
+
+struct S_FX_EFX add_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b)
+{
+	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;
+
+	return result;
+}
+
+
+/**
+ * @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_buf	a 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)
+{
+	size_t i;
+
+	if (!samples)
+		return 0;
+
+	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);
+	}
+	return 0;
+}
+
+
+int de_lossy_rounding_S_FX_EFX(struct S_FX_EFX *data_buf, unsigned int
+			       samples_used, unsigned int round_used)
+{
+	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 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);
+	}
+	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)
+{
+	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;
+}
+
+
+struct S_FX_NCOB sub_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b)
+{
+	struct S_FX_NCOB result;
+
+	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;
+}
+
+
+struct S_FX_NCOB add_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b)
+{
+	struct S_FX_NCOB result;
+
+	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;
+}
+
+
+/**
+ * @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)
+{
+	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);
+	}
+	return 0;
+}
+
+
+int de_lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int
+				samples_used, unsigned int round_used)
+{
+	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);
+	}
+	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)
+{
+	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);
+
+	return result;
+}
+
+
+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 result;
+
+	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;
+}
+
+
+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)
+{
+	struct S_FX_EFX_NCOB_ECOB result;
+
+	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;
+}
+
+
+/**
+ * @brief rounding down the least significant digits of a S_FX_EFX_NCOB_ECOB 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_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
+ */
+
+int lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf,
+				      unsigned int samples, unsigned int round)
+{
+	size_t i;
+
+	if (!samples)
+		return 0;
+
+	if (!data_buf)
+		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)
+		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;
+}
diff --git a/lib/cmp_icu.c b/lib/cmp_icu.c
new file mode 100644
index 0000000..1a8d157
--- /dev/null
+++ b/lib/cmp_icu.c
@@ -0,0 +1,1781 @@
+/**
+ * @file   icu_cmp.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 compression library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ */
+
+
+#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"
+
+
+
+/**
+ * @brief check if the compressor configuration is valid for a SW compression,
+ *	see the user manual for more information (PLATO-UVIE-PL-UM-0001).
+ *
+ * @param cfg	configuration contains all parameters required for compression
+ * @param info	compressor information contains information of an executed
+ *		compression (can be NULL)
+ *
+ * @returns 0 when configuration is valid, invalid configuration otherwise
+ */
+
+int icu_cmp_cfg_valid(const struct cmp_cfg *cfg, struct cmp_info *info)
+{
+	int cfg_invalid = 0;
+
+	if (!cfg) {
+		debug_print("Error: compression configuration structure is NULL.\n");
+		return -1;
+	}
+
+	if (!info)
+		debug_print("Warning: compressor information structure is NULL.\n");
+
+	if (info)
+		info->cmp_err = 0;  /* reset errors */
+
+	if (cfg->input_buf == NULL) {
+		debug_print("Error: The input_buf buffer for the data to be compressed is NULL.\n");
+		cfg_invalid++;
+	}
+
+	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++;
+	}
+
+	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 (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 (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++;
+		}
+
+		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 (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++;
+		}
+	}
+
+	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 (!(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;
+
+	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++;
+		}
+	}
+
+	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++;
+	}
+
+	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 (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++;
+	}
+
+#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++;
+	}
+
+	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
+
+	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++;
+	}
+
+	return -(cfg_invalid);
+}
+
+
+/**
+ * @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
+ */
+
+
+static int set_info(struct cmp_cfg *cfg, struct cmp_info *info)
+{
+	if (!cfg)
+		return -1;
+
+	if (cfg->cmp_mode > UINT8_MAX)
+		return -1;
+
+	if (cfg->round > UINT8_MAX)
+		return -1;
+
+	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->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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int diff_16(uint16_t *data_buf, unsigned int samples, unsigned int round)
+{
+	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];
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ */
+
+static int diff_32(uint32_t *data_buf, unsigned int samples, unsigned int round)
+{
+	size_t i;
+
+	if (!data_buf)
+		return -1;
+
+	lossy_rounding_32(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];
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @param data_buf	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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int diff_S_FX(struct S_FX *data, unsigned int samples, unsigned int
+		     round)
+{
+	size_t i;
+	int err;
+
+	if (!data)
+		return -1;
+
+	err = lossy_rounding_S_FX(data, samples, round);
+	if (err)
+		return err;
+
+	for (i = samples - 1; i > 0; i--) {
+		/* possible underflow is intended */
+		data[i] = sub_S_FX(data[i], data[i-1]);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX 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 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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int diff_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples, unsigned
+			 int round)
+{
+	size_t i;
+	int err;
+
+	if (!data)
+		return -1;
+
+	err = lossy_rounding_S_FX_EFX(data, samples, round);
+	if (err)
+		return err;
+
+	for (i = samples - 1; i > 0; i--) {
+		/* possible underflow is intended */
+		data[i] = sub_S_FX_EFX(data[i], data[i-1]);
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @param data_buf	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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int diff_S_FX_NCOB(struct S_FX_NCOB *data, unsigned int samples, unsigned
+			  int round)
+{
+	size_t i;
+	int err;
+
+	if (!data)
+		return -1;
+
+	err = lossy_rounding_S_FX_NCOB(data, samples, round);
+	if (err)
+		return err;
+
+	for (i = samples - 1; i > 0; i--) {
+		/* possible underflow is intended */
+		data[i] = sub_S_FX_NCOB(data[i], data[i-1]);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX_NCOB_ECOB 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 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 0 on success, error otherwise
+ */
+
+static int diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data, unsigned int
+				   samples, unsigned int round)
+{
+	size_t i;
+	int err;
+
+	if (!data)
+		return -1;
+
+	err = lossy_rounding_S_FX_EFX_NCOB_ECOB(data, samples, round);
+	if (err)
+		return err;
+
+	for (i = samples - 1; i > 0; i--) {
+		/* possible underflow is intended */
+		data[i] = sub_S_FX_EFX_NCOB_ECOB(data[i], data[i-1]);
+	}
+
+	return 0;
+}
+
+
+/**
+ * @brief model pre-processing and rounding of a uint16_t data buffer
+ *
+ * @note overwrite the data_buf in-place with the result
+ * @note update the model_buf in-place if up_model_buf = NULL
+ *
+ * @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 0 on success, error otherwise
+ */
+
+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)
+{
+	size_t i;
+
+	if (!data_buf)
+		return -1;
+
+	if (!model_buf)
+		return -1;
+
+	if (model_value > MAX_MODEL_VALUE)
+		return -1;
+
+	if (!up_model_buf)
+		up_model_buf = model_buf;
+
+	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;
+}
+
+
+/**
+ * @brief model pre-processing and round_input of a uint32_t data buffer
+ *
+ * @note overwrite the data_buf in-place with the result
+ * @note update the model_buf in-place if up_model_buf = NULL
+ *
+ * @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 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)
+{
+	size_t i;
+
+	if (!data_buf)
+		return -1;
+
+	if (!model_buf)
+		return -1;
+
+	if (model_value > MAX_MODEL_VALUE)
+		return -1;
+
+	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);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief model pre-processing and round_input of a S_FX data buffer
+ *
+ * @note overwrite the data_buf in-place with the result
+ * @note update the model_buf in-place if up_model_buf = NULL
+ *
+ * @param data_buf	pointer to the S_FX data buffer to process
+ * @param model_buf	pointer to the model buffer of the data 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 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)
+{
+	size_t i;
+
+	if (!samples)
+		return 0;
+
+	if (!model_buf)
+		return -1;
+
+	if (model_value > MAX_MODEL_VALUE)
+		return -1;
+
+	if (!up_model_buf)  /* overwrite the model buffer if no up_model_buf is set */
+		up_model_buf = model_buf;
+
+
+	for (i = 0; i < samples; i++) {
+		struct S_FX round_data = data_buf[i];
+		struct S_FX round_model = model_buf[i];
+		int err;
+
+		err = lossy_rounding_S_FX(&round_data, 1, round);
+		if (err)
+			return err;
+
+		err = lossy_rounding_S_FX(&round_model, 1, round);
+		if (err)
+			return err;
+
+		/* possible underflow is intended */
+		data_buf[i] = sub_S_FX(round_data, round_model);
+
+		/* 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);
+	}
+
+	return 0;
+}
+
+
+/**
+ * @brief data pre-processing to decorrelate the data
+ *
+ * @param cfg	configuration contains all parameters required for compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int pre_process(struct cmp_cfg *cfg)
+{
+	if (!cfg)
+		return -1;
+
+	if (cfg->samples == 0)
+		return 0;
+
+	if (!cfg->input_buf)
+		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;
+}
+
+
+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);
+}
+
+
+static uint16_t map_to_pos_alg_16(int16_t value_to_map)
+{
+	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);
+}
+
+
+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);
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int map_to_pos_16(uint16_t *data_buf, uint32_t samples, int zero_mode_used)
+{
+	size_t i;
+
+	if (!data_buf)
+		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;
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int map_to_pos_32(uint32_t *data_buf, uint32_t samples, int
+			 zero_mode_used)
+{
+	size_t i;
+
+	if (!data_buf)
+		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;
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples, int
+			   zero_mode_used)
+{
+	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);
+
+		if (zero_mode_used) {
+			/* data_buf[i].EXPOSURE_FLAGS += 1; */
+			data_buf[i].FX += 1;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples, int
+			       zero_mode_used)
+{
+	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].EFX = map_to_pos_alg_32(data_buf[i].EFX);
+
+		if (zero_mode_used) {
+			/* data_buf[i].EXPOSURE_FLAGS += 1; */
+			data_buf[i].FX += 1;
+			data_buf[i].EFX += 1;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t samples,
+				int zero_mode_used)
+{
+	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);
+
+		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;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * @brief map the signed output of the pre-processing stage to a unsigned value
+ *	range for a S_FX_EFX_NCOB_ECOB buffer
+ *
+ * @note overwrite the data_buf in-place with the result
+ *
+ * @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
+ */
+
+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)
+{
+	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;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * @brief map the signed output of the pre-processing stage to a unsigned value
+ *	range
+ *
+ * @note change the data_buf in-place
+ *
+ * @param data_buf	pointer to the data to process
+ * @param buf_len	length of the data to process
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int map_to_pos(struct cmp_cfg *cfg)
+{
+	int zero_mode_used;
+
+	if (!cfg)
+		return -1;
+
+	if (cfg->samples == 0)
+		return 0;
+
+	if (!cfg->input_buf)
+		return -1;
+
+	zero_mode_used = zero_escape_mech_is_used(cfg->cmp_mode);
+
+	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;
+
+	}
+
+	return -1;
+}
+
+
+/**
+ * @brief forms the codeword accurate to the Rice code and returns its length
+ *
+ * @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
+ *
+ * @returns length of the encoded code word in bits
+ */
+
+static unsigned int Rice_encoder(unsigned int value, unsigned int m,
+				 unsigned int log2_m, unsigned int *cw)
+{
+	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 */
+
+	g = value >> log2_m; /* quotient, number of leading bits */
+	q = (1U << g) - 1;    /* prepare the quotient code without ending zero */
+
+	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 */
+
+	return rl + g;	      /* calculate the length of the code word */
+}
+
+
+/**
+ * @brief forms the codeword accurate to the Golomb code and returns its length
+ *
+ * @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
+ *
+ * @returns length of the encoded code word in bits
+ */
+
+static unsigned int Golomb_encoder(unsigned int value, unsigned int m,
+				   unsigned int log2_m, unsigned int *cw)
+{
+	unsigned int len0, b, g, q, lg;
+	unsigned int len;
+	unsigned int cutoff;
+
+	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;
+
+	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 */
+	}
+	return len;
+}
+
+
+typedef unsigned int (*encoder_ptr)(unsigned int, unsigned int, unsigned int,
+				    unsigned int*);
+
+static encoder_ptr select_encoder(unsigned int golomb_par)
+{
+	if (!golomb_par)
+		return NULL;
+
+	if (is_a_pow_of_2(golomb_par))
+		return &Rice_encoder;
+	else
+		return &Golomb_encoder;
+}
+
+
+/**
+ * @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  number of bits written, 0 if the number was too big, -1 if the
+ *	     destAddr buffer is to small to store the bitstream
+ * @note     works in SRAM2
+ */
+
+static unsigned int put_n_bits32(unsigned int value, unsigned int bitOffset,
+				 unsigned int nBits, unsigned int *destAddr,
+				 unsigned int dest_len)
+{
+	unsigned int *localAddr;
+	unsigned int bitsLeft, shiftRight, shiftLeft, localEndPos;
+	unsigned int mask;
+
+	/* check if destination buffer is large enough */
+	/* TODO: adapt that to the other science products */
+	if ((bitOffset + nBits) > (((dest_len+1)/2)*2 * 16)) {
+		debug_print("Error: The icu_output_buf buffer is not small to hold the compressed data.\n");
+		return -2U;
+	}
+
+	/* leave in case of erroneous input */
+	if (nBits == 0)
+		return 0;
+	if (nBits > 32)
+		return 0;
+
+	/* separate the bitOffset into word offset (set localAddr pointer) and local bit offset (bitsLeft) */
+	localAddr = destAddr + (bitOffset >> 5);
+	bitsLeft = bitOffset & 0x1f;
+
+	/* (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;
+
+	/* to see if we need to split the value over two words we need the right end position */
+	localEndPos = bitsLeft + nBits;
+
+	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;
+
+		/* generate the mask, the bits for the values will be true */
+		/* mask = (0xffffffff >> shiftRight) << shiftLeft; */ /* see (M) above! */
+		mask <<= shiftLeft;
+
+		/* clear the destination with inverse mask */
+		*(localAddr) &= ~mask;
+
+		/* 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;
+
+		/* clear the destination with inverse mask */
+		*(localAddr) &= ~mask;
+
+		/* assign the value part 1 */
+		*(localAddr) |= (value >> n2);
+
+		/* 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));
+	}
+	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)
+		return -1;
+
+	if (!cfg->icu_output_buf)
+		return -1;
+
+	if (!cfg->input_buf)
+		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))
+		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;
+
+	err = encode_raw(cfg, enc);
+	if (err)
+		return err;
+
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+	{
+		size_t i;
+		uint16_t *p = cfg->icu_output_buf;
+
+		for (i = 0; i < cfg->samples; i++)
+			cpu_to_be16s(&p[i]);
+
+	}
+#endif /* __BYTE_ORDER__ */
+	return 0;
+}
+
+
+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 = cfg->icu_output_buf;
+			output_buf[i].FX = cpu_to_be32(output_buf[i].FX);
+		}
+	}
+#endif
+	return 0;
+}
+
+
+static int encode_normal(uint32_t value_to_encode, struct cmp_cfg *cfg,
+			 struct encoder_struct *enc)
+{
+	unsigned int code_word;
+	unsigned int cw_len;
+	int err;
+
+	if (!enc->encoder)
+		return -1;
+
+	cw_len = enc->encoder(value_to_encode, cfg->golomb_par,
+			      enc->log2_golomb_par, &code_word);
+
+	err = put_n_bits32(code_word, enc->cmp_size, cw_len,
+			   cfg->icu_output_buf, cfg->buffer_length);
+	if (err <= 0)
+		return err;
+
+	enc->cmp_size += cw_len;
+
+	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 (max_bits > 32)
+		return -1;
+
+	/* use zero as escape symbol */
+	encode_normal(0, cfg, enc);
+
+	/* 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;
+	}
+
+	enc->cmp_size += max_bits;
+
+	return 0;
+}
+
+
+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;
+}
+
+
+static int encode_outlier_multi(uint32_t value_to_encode, struct cmp_cfg *cfg,
+				struct encoder_struct *enc)
+{
+	uint32_t unencoded_data;
+	unsigned int unencoded_data_len;
+	uint32_t escape_sym;
+	int escape_sym_offset;
+	int err;
+
+	/*
+	 * 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 */
+	encode_normal(escape_sym, cfg, enc);
+
+	/* 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;
+}
+
+
+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);
+}
+
+
+static int encode_16(uint16_t *data_to_encode, struct cmp_cfg *cfg,
+		     struct encoder_struct *enc)
+{
+	size_t i;
+
+	if (!cfg)
+		return -1;
+
+	if (!cfg->samples)
+		return 0;
+
+	if (!data_to_encode)
+		return -1;
+
+	if (!enc)
+		return -1;
+
+
+	for (i = 0; i < cfg->samples; i++) {
+		int err = encode_value(data_to_encode[i], 16, cfg, enc);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+
+static int encode_32(struct cmp_cfg *cfg, struct encoder_struct *enc)
+{
+	uint32_t *data_to_encode = cfg->input_buf;
+	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;
+}
+
+
+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;
+
+	cfg_exp_flag.golomb_par = GOLOMB_PAR_EXPOSURE_FLAGS;
+	enc_exp_flag.log2_golomb_par = ilog_2(GOLOMB_PAR_EXPOSURE_FLAGS);
+
+	for (i = 0; i < cfg->samples; i++) {
+		int err;
+
+		/* 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;
+
+		enc->log2_golomb_par = ilog_2(cfg->golomb_par);
+		err = encode_value(data_to_encode[i].FX, 32, cfg, enc);
+		if (err)
+			return err;
+
+		enc_exp_flag.cmp_size = enc->cmp_size;
+	}
+
+	return 0;
+}
+
+
+static int encode_S_FX_EFX(struct cmp_cfg *cfg, struct encoder_struct *enc)
+{
+	struct S_FX_EFX *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 = encode_value(data_to_encode[i].FX, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].EFX, 32, cfg, enc);
+		if (err)
+			return err;
+	}
+	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 = encode_value(data_to_encode[i].FX, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].NCOB_X, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].NCOB_Y, 32, cfg, enc);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+
+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;
+
+		err = encode_value(data_to_encode[i].FX, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].NCOB_X, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].NCOB_Y, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].EFX, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].ECOB_X, 32, cfg, enc);
+		if (err)
+			return err;
+
+		err = encode_value(data_to_encode[i].ECOB_Y, 32, cfg, enc);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+/* pad the bitstream with zeros */
+int pad_bitstream(struct cmp_cfg *cfg, uint32_t cmp_size, struct cmp_info *info)
+{
+	int n_bits = 0;
+
+	if (!cfg)
+		return -1;
+
+	/* is padding needed */
+	if (!raw_mode_is_used(cfg->cmp_mode) && 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) {
+				/* the icu_output_buf is to small to store the whole bitstream */
+				if (info) {
+					info->cmp_err |= 1UL << SMALL_BUFFER_ERR_BIT; /* set small buffer error */
+					info->cmp_size = 0;
+				}
+				return -2;
+			}
+		}
+	}
+	return n_bits;
+}
+
+
+static int encode_data(struct cmp_cfg *cfg, struct cmp_info *info)
+{
+	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;
+
+	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((uint16_t *)cfg->input_buf, 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;
+	}
+
+	if (err == -2) {
+		/* the icu_output_buf is to small to store the whole bitstream */
+		info->cmp_err |= 1UL << SMALL_BUFFER_ERR_BIT; /* set small buffer error */
+		return err;
+	}
+	if (info)
+		info->cmp_size = enc.cmp_size;
+
+	n_bits = pad_bitstream(cfg, enc.cmp_size, info);
+	if (n_bits < 0)
+		return n_bits;
+
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+		{
+			size_t i;
+			uint32_t *p = (uint32_t *)cfg->icu_output_buf;
+			for (i = 0; i < (enc.cmp_size + n_bits)/32; i++)
+				cpu_to_be32s(&p[i]);
+		}
+#endif /*__BYTE_ORDER__ */
+
+	return 0;
+}
+
+
+/**
+ * @brief	compress data on the ICU
+ *
+ * @param cfg	compressor configuration contains all parameters required for
+ *		compression
+ * @param info	compressor information contains information of the executed
+ *		compression
+ *
+ * @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
+ */
+
+int icu_compress_data(struct cmp_cfg *cfg, struct cmp_info *info)
+{
+	int err;
+
+	err = set_info(cfg, info);
+	if (err)
+		return err;
+
+	err = icu_cmp_cfg_valid(cfg, info);
+	if (err)
+		return err;
+
+	err = pre_process(cfg);
+	if (err)
+		return err;
+
+	err = map_to_pos(cfg);
+	if (err)
+		return err;
+
+	err = encode_data(cfg, info);
+	if (err)
+		return err;
+
+	return 0;
+}
diff --git a/lib/cmp_rdcu.c b/lib/cmp_rdcu.c
new file mode 100644
index 0000000..caf9c6e
--- /dev/null
+++ b/lib/cmp_rdcu.c
@@ -0,0 +1,876 @@
+/**
+ * @file   cmp_rdcu.c
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2019
+ *
+ * @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 hardware compressor control library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include "../include/rdcu_cmd.h"
+#include "../include/cmp_support.h"
+#include "../include/rdcu_ctrl.h"
+#include "../include/rdcu_rmap.h"
+
+
+#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 */
+/* RDCU interrupt signal status */
+static int interrupt_signal_enabled = RDCU_INTR_SIG_DEFAULT;
+
+
+/**
+ * @brief save repeating 3 lines of code...
+ *
+ * @note This function depends on the SpW implantation and must be adjusted to it.
+ *
+ * @note prints abort message if pending status is non-zero after 10 retries
+ */
+
+static void sync(void)
+{
+#if 0
+	not needed for packed generation
+
+	int cnt = 0;
+	printf("syncing...");
+	while (rdcu_rmap_sync_status()) {
+		printf("pending: %d\n", rdcu_rmap_sync_status());
+
+		if (cnt++ > 10) {
+			printf("aborting; de");
+			break;
+		}
+
+	}
+	printf("synced\n");
+#endif
+}
+
+
+/**
+ * @brief check if a buffer is in inside the RDCU SRAM
+ *
+ * @param addr	start address of the buffer
+ * @param size	length of the buffer in bytes
+ *
+ * @returns 1 if buffer in inside the RDCU SRAM, 0 when the buffer is outside
+ */
+
+static int in_sram_range(uint32_t addr, uint32_t size)
+{
+	if (addr > RDCU_SRAM_END)
+		return 0;
+
+	if (size > RDCU_SRAM_SIZE)
+		return 0;
+
+	if (addr + size > RDCU_SRAM_END)
+		return 0;
+
+	return 1;
+}
+
+
+/**
+ * @brief check if two buffers are overlapping
+ * @note implement according to https://stackoverflow.com/a/325964
+ *
+ * @param start_a	start address of the 1st buffer
+ * @param end_a		end address of the 1st buffer
+ * @param start_b	start address of the 2nd buffer
+ * @param end_b		end address of the 2nd buffer
+ *
+ * @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)
+{
+	if (start_a < end_b && end_a > start_b)
+		return 1;
+	else
+		return 0;
+}
+
+
+/**
+ * @brief check if the compressor configuration is valid for a RDCU compression,
+ * see the user manual for more information (PLATO-UVIE-PL-UM-0001).
+ *
+ * @param cfg	configuration contains all parameters required for compression
+ *
+ * @returns  >= 0 on success, error otherwise
+ */
+
+int rdcu_cmp_cfg_valid(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->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");
+			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");
+		cfg_invalid++;
+	}
+
+	if (cfg->rdcu_buffer_adr & 0x3) {
+		printf("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");
+		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");
+		cfg_invalid++;
+	}
+
+	if (buffers_overlap(cfg->rdcu_data_adr,
+			    cfg->rdcu_data_adr + cfg->samples * 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_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.");
+			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");
+			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");
+			cfg_invalid++;
+		}
+
+		if (buffers_overlap(
+			    cfg->rdcu_model_adr,
+			    cfg->rdcu_model_adr + cfg->samples * 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_invalid++;
+		}
+
+		if (buffers_overlap(
+			cfg->rdcu_model_adr,
+			cfg->rdcu_model_adr + cfg->samples * 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_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");
+				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_invalid++;
+			}
+
+			if (buffers_overlap(
+				cfg->rdcu_new_model_adr,
+				cfg->rdcu_new_model_adr + cfg->samples * 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_invalid++;
+			}
+
+			if (buffers_overlap(
+				cfg->rdcu_new_model_adr,
+				cfg->rdcu_new_model_adr + cfg->samples * 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_invalid++;
+			}
+			if (buffers_overlap(
+				cfg->rdcu_new_model_adr,
+				cfg->rdcu_new_model_adr + cfg->samples * 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_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_output_buf) {
+		printf("Warning: ICU compressed data buffer is set. This "
+		       "buffer is not used for an RDCU compression.\n");
+		cfg_warning++;
+	}
+
+#ifdef SKIP_CMP_PAR_CHECK
+	return 0;
+#endif
+	if (cfg_invalid)
+		return -cfg_invalid;
+	else
+		return cfg_warning;
+}
+
+
+/**
+ * @brief set up RDCU compression register
+ *
+ * @param cfg  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)
+		return -1;
+
+	/* first, set compression parameters in local mirror registers */
+	if (rdcu_set_compression_mode(cfg->cmp_mode))
+		return -1;
+	if (rdcu_set_golomb_param(cfg->golomb_par))
+		return -1;
+	if (rdcu_set_spillover_threshold(cfg->spill))
+		return -1;
+	if (rdcu_set_weighting_param(cfg->model_value))
+		return -1;
+	if (rdcu_set_noise_bits_rounded(cfg->round))
+		return -1;
+
+	if (rdcu_set_adaptive_1_golomb_param(cfg->ap1_golomb_par))
+		return -1;
+	if (rdcu_set_adaptive_1_spillover_threshold(cfg->ap1_spill))
+		return -1;
+
+	if (rdcu_set_adaptive_2_golomb_param(cfg->ap2_golomb_par))
+		return -1;
+	if (rdcu_set_adaptive_2_spillover_threshold(cfg->ap2_spill))
+		return -1;
+
+	if (rdcu_set_data_start_addr(cfg->rdcu_data_adr))
+		return -1;
+	if (rdcu_set_model_start_addr(cfg->rdcu_model_adr))
+		return -1;
+	if (rdcu_set_num_samples(cfg->samples))
+		return -1;
+	if (rdcu_set_new_model_start_addr(cfg->rdcu_new_model_adr))
+		return -1;
+
+	if (rdcu_set_compr_data_buf_start_addr(cfg->rdcu_buffer_adr))
+		return -1;
+	if (rdcu_set_compr_data_buf_len(cfg->buffer_length))
+		return -1;
+
+	/* now sync the configuration registers to the RDCU... */
+	if (rdcu_sync_compressor_param1())
+		return -1;
+	if (rdcu_sync_compressor_param2())
+		return -1;
+	if (rdcu_sync_adaptive_param1())
+		return -1;
+	if (rdcu_sync_adaptive_param2())
+		return -1;
+	if (rdcu_sync_data_start_addr())
+		return -1;
+	if (rdcu_sync_model_start_addr())
+		return -1;
+	if (rdcu_sync_num_samples())
+		return -1;
+	if (rdcu_sync_new_model_start_addr())
+		return -1;
+	if (rdcu_sync_compr_data_buf_start_addr())
+		return -1;
+	if (rdcu_sync_compr_data_buf_len())
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * @brief start the RDCU data compressor
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int rdcu_start_compression(void)
+{
+	if (interrupt_signal_enabled) {
+		/* enable the interrupt signal to the ICU */
+		rdcu_set_rdcu_interrupt();
+	} else {
+		/* disable the interrupt signal to the ICU */
+		rdcu_clear_rdcu_interrupt();
+	}
+
+	/* start the compression */
+	rdcu_set_data_compr_start();
+	if (rdcu_sync_compr_ctrl())
+		return -1;
+	sync();
+
+	/* clear local bit immediately, this is a write-only register.
+	 * we would not want to restart compression by accidentally calling
+	 * rdcu_sync_compr_ctrl() again
+	 */
+	rdcu_clear_data_compr_start();
+
+	return 0;
+}
+
+
+/**
+ * @brief compressing data with the help of the RDCU hardware compressor
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int rdcu_compress_data(const struct cmp_cfg *cfg)
+{
+	if (!cfg)
+		return -1;
+
+	if (rdcu_set_compression_register(cfg))
+		return -1;
+
+	if (cfg->input_buf != NULL) {
+		/* round up needed size must be a multiple of 4 bytes */
+		uint32_t size = (cfg->samples * 2 + 3) & ~3U;
+		/* now set the data in the local mirror... */
+		if (rdcu_write_sram_16(cfg->input_buf, cfg->rdcu_data_adr,
+				       cfg->samples * 2) < 0)
+			return -1;
+		if (rdcu_sync_mirror_to_sram(cfg->rdcu_data_adr, size,
+					     rdcu_get_data_mtu()))
+			return -1;
+	}
+	/*...and the model when needed */
+	if (cfg->model_buf != NULL) {
+		/* set model only when model mode is used */
+		if (model_mode_is_used(cfg->cmp_mode)) {
+			/* round up needed size must be a multiple of 4 bytes */
+			uint32_t size = (cfg->samples * 2 + 3) & ~3U;
+			/* set the model in the local mirror... */
+			if (rdcu_write_sram_16(cfg->model_buf,
+					       cfg->rdcu_model_adr,
+					       cfg->samples * 2) < 0)
+				return -1;
+			if (rdcu_sync_mirror_to_sram(cfg->rdcu_model_adr, size,
+						     rdcu_get_data_mtu()))
+				return -1;
+		}
+	}
+
+	/* ...and wait for completion */
+	sync();
+
+	/* start the compression */
+	if (rdcu_start_compression())
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * @brief read out the status register of the RDCU compressor
+ *
+ * @param status  compressor status contains the stats of the HW compressor
+ *
+ * @note access to the status registers is also possible during compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int rdcu_read_cmp_status(struct cmp_status *status)
+{
+
+	if (rdcu_sync_compr_status())
+		return -1;
+	sync();
+
+	if (status) {
+		status->data_valid = (uint8_t)rdcu_get_compr_status_valid();
+		status->cmp_ready = (uint8_t)rdcu_get_data_compr_ready();
+		status->cmp_interrupted = (uint8_t)rdcu_get_data_compr_interrupted();
+		status->cmp_active = (uint8_t)rdcu_get_data_compr_active();
+		status->rdcu_interrupt_en = (uint8_t)rdcu_get_rdcu_interrupt_enabled();
+	}
+	return 0;
+}
+
+
+/**
+ * @brief read out the metadata of a RDCU compression
+ *
+ * @param info  compression information contains the metadata of a compression
+ *
+ * @note the compression information registers cannot be accessed during a
+ *	 compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int rdcu_read_cmp_info(struct cmp_info *info)
+{
+	/* read out the compressor information register*/
+	if (rdcu_sync_used_param1())
+		return -1;
+	if (rdcu_sync_used_param2())
+		return -1;
+	if (rdcu_sync_compr_data_start_addr())
+		return -1;
+	if (rdcu_sync_compr_data_size())
+		return -1;
+	if (rdcu_sync_compr_data_adaptive_1_size())
+		return -1;
+	if (rdcu_sync_compr_data_adaptive_2_size())
+		return -1;
+	if (rdcu_sync_compr_error())
+		return -1;
+	if (rdcu_sync_new_model_addr_used())
+		return -1;
+	if (rdcu_sync_samples_used())
+		return -1;
+
+	sync();
+
+	if (info) {
+		/* put the data in the cmp_info structure */
+		info->cmp_mode_used = rdcu_get_compression_mode();
+		info->golomb_par_used = rdcu_get_golomb_param();
+		info->spill_used = rdcu_get_spillover_threshold();
+		info->model_value_used = rdcu_get_weighting_param();
+		info->round_used = rdcu_get_noise_bits_rounded();
+		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_err = rdcu_get_compr_error();
+	}
+	return 0;
+}
+
+
+/**
+ * @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)
+ *
+ * @returns the number of bytes read, < 0 on error
+ */
+
+int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf)
+{
+	uint32_t s;
+
+	if (info == NULL)
+		return -1;
+
+	/* calculate the need bytes for the bitstream */
+	s = size_of_bitstream(info->cmp_size);
+
+	if (output_buf == NULL)
+		return (int)s;
+
+	if (rdcu_sync_sram_to_mirror(info->rdcu_cmp_adr_used, s,
+				     rdcu_get_data_mtu()))
+		return -1;
+
+	/* wait for it */
+	sync();
+
+	return rdcu_read_sram(output_buf, info->rdcu_cmp_adr_used, s);
+}
+
+
+/**
+ * @brief read the model from the RDCU SRAM
+ *
+ * @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)
+ *
+ * @returns the number of bytes read, < 0 on error
+ */
+
+int rdcu_read_model(const struct cmp_info *info, void *model_buf)
+{
+	uint32_t s;
+
+	if (info == NULL)
+		return -1;
+
+	/* calculate the need bytes for the model */
+	s = size_of_model(info->samples_used, info->cmp_mode_used);
+
+	if (model_buf == NULL)
+		return (int)s;
+
+	if (rdcu_sync_sram_to_mirror(info->rdcu_new_model_adr_used, (s+3) & ~3U,
+				     rdcu_get_data_mtu()))
+		return -1;
+
+	/* wait for it */
+	sync();
+
+	return rdcu_read_sram(model_buf, info->rdcu_new_model_adr_used, s);
+}
+
+
+/**
+ * @brief interrupt a data compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int rdcu_interrupt_compression(void)
+{
+	/* interrupt a compression */
+	rdcu_set_data_compr_interrupt();
+	if (rdcu_sync_compr_ctrl())
+		return -1;
+	sync();
+
+	/* clear local bit immediately, this is a write-only register.
+	 * we would not want to restart compression by accidentially calling
+	 * rdcu_sync_compr_ctrl() again
+	 */
+	rdcu_clear_data_compr_interrupt();
+
+	return 0;
+}
+
+
+/**
+ * @brief enable the RDCU to signal a finished compression with an interrupt signal
+ */
+
+void rdcu_enable_interrput_signal(void)
+{
+	interrupt_signal_enabled = RDCU_INTR_SIG_ENA;
+}
+
+
+/**
+ * @brief deactivated the RDCU interrupt signal
+ */
+
+void rdcu_disable_interrput_signal(void)
+{
+	interrupt_signal_enabled = RDCU_INTR_SIG_DIS;
+}
+
+
+/**
+ * @brief compressing data with the help of the RDCU hardware compressor; read
+ *	data from the last compression before starting compression
+ *
+ * @param cfg	     configuration contains all parameters required for compression
+ * @param last_info  compression information of last compression run
+ *
+ * @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 overlapping of the different rdcu buffers is not checked
+ * @note the validity of the cfg structure is checked before the compression is
+ *	 started
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int rdcu_compress_data_parallel(const struct cmp_cfg *cfg,
+				const struct cmp_info *last_info)
+{
+	uint32_t samples_4byte;
+
+	if (!cfg)
+		return -1;
+
+	if (!last_info)
+		return rdcu_compress_data(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;
+
+	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)
+			return -1;
+
+		/* calculate the need bytes for the bitstream */
+		cmp_size_4byte = ((last_info->cmp_size >> 3) + 3) & ~0x3U;
+
+		/* parallel read compressed data and write input data from sram
+		 * to mirror*/
+		if (rdcu_sync_sram_mirror_parallel(last_info->rdcu_cmp_adr_used,
+				cmp_size_4byte, cfg->rdcu_data_adr, samples_4byte,
+				rdcu_get_data_mtu()))
+			return -1;
+		/* wait for it */
+		sync();
+		if (cfg->icu_output_buf) {
+			if (rdcu_read_sram(cfg->icu_output_buf,
+					   last_info->rdcu_cmp_adr_used,
+					   cmp_size_4byte))
+				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");
+	}
+
+	/* read model and write model in parallel */
+	if (cfg->model_buf && model_mode_is_used(cfg->cmp_mode) && model_mode_is_used(last_info->cmp_mode_used)) {
+		uint32_t new_model_size_4byte;
+
+		/* set the model in the local mirror... */
+		if (rdcu_write_sram_16(cfg->model_buf, cfg->rdcu_model_adr,
+				       cfg->samples * SAM2BYT) < 0)
+			return -1;
+
+		new_model_size_4byte = last_info->samples_used * SAM2BYT ;
+		if (rdcu_sync_sram_mirror_parallel(last_info->rdcu_new_model_adr_used,
+						   (new_model_size_4byte+3) & ~0x3U,
+						   cfg->rdcu_model_adr,
+						   samples_4byte, rdcu_get_data_mtu()))
+			return -1;
+		/* wait for it */
+		sync();
+		if (cfg->icu_new_model_buf) {
+			if (rdcu_read_sram(cfg->icu_new_model_buf,
+					   last_info->rdcu_new_model_adr_used,
+					   new_model_size_4byte))
+				return -1;
+		}
+	/* write model */
+	} 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)
+			return -1;
+
+		if (rdcu_sync_mirror_to_sram(cfg->rdcu_model_adr, samples_4byte,
+					     rdcu_get_data_mtu()))
+			return -1;
+	/* read model */
+	} else if (model_mode_is_used(last_info->cmp_mode_used)) {
+		if (rdcu_read_model(last_info, cfg->icu_new_model_buf) < 0)
+			return -1;
+	}
+
+	/* ...and wait for completion */
+	sync();
+
+	if (rdcu_start_compression())
+		return -1;
+
+	return 0;
+}
+
diff --git a/lib/cmp_support.c b/lib/cmp_support.c
new file mode 100644
index 0000000..39aa61f
--- /dev/null
+++ b/lib/cmp_support.c
@@ -0,0 +1,595 @@
+/**
+ * @file   cmp_support.c
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at),
+ * @date   2019
+ *
+ * @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 compressor support library
+ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001
+ */
+
+#include <stdio.h>
+
+#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 */
+};
+
+
+/**
+ * @brief implementation of the logarithm base of floor(log2(x)) for integers
+ * @note ilog_2(0) = -1 defined
+ *
+ * @param x input parameter
+ *
+ * @returns the result of floor(log2(x))
+ */
+
+int ilog_2(uint32_t x)
+{
+	if (!x)
+		return -1;
+
+	return 31 - __builtin_clz(x);
+}
+
+
+/**
+ * @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
+ *
+ * @returns 1 if v is a power of 2, otherwise 0
+ *
+ * @note see: https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
+ */
+
+int is_a_pow_of_2(unsigned int v)
+{
+	return (((v) & ((v) - 1)) == 0);
+}
+
+
+/**
+ * @brief check if a model mode is selected
+ *
+ * @param cmp_mode compression mode
+ *
+ * @returns 1 when model mode is set, otherwise 0
+ */
+
+int model_mode_is_used(unsigned int 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:
+		return 1;
+		break;
+	default:
+		return 0;
+		break;
+	}
+}
+
+
+/**
+ * @brief check if a 1d-differencing mode is selected
+ *
+ * @param cmp_mode compression mode
+ *
+ * @returns 1 when 1d-differencing mode is set, otherwise 0
+ */
+
+int diff_mode_is_used(unsigned int 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:
+		return 1;
+		break;
+	default:
+		return 0;
+		break;
+	}
+}
+
+
+/**
+ * @brief check if the raw mode is selected
+ *
+ * @param cmp_mode compression mode
+ *
+ * @returns 1 when raw mode is set, otherwise 0
+ */
+
+int raw_mode_is_used(unsigned int cmp_mode)
+{
+	switch (cmp_mode) {
+	case MODE_RAW:
+	case MODE_RAW_S_FX:
+	case MODE_RAW_32:
+		return 1;
+		break;
+	default:
+		return 0;
+		break;
+	}
+}
+
+
+/**
+ * @brief check if the mode is supported by the RDCU compressor
+ *
+ * @param cmp_mode compression mode
+ *
+ * @returns 1 when mode is supported by the RDCU, otherwise 0
+ */
+
+int rdcu_supported_mode_is_used(unsigned int cmp_mode)
+{
+	switch (cmp_mode) {
+	case MODE_RAW:
+	case MODE_MODEL_ZERO:
+	case MODE_DIFF_ZERO:
+	case MODE_MODEL_MULTI:
+	case MODE_DIFF_MULTI:
+		return 1;
+		break;
+	default:
+		return 0;
+		break;
+	}
+}
+
+
+/**
+ * @brief check if zero escape symbol mechanism mode is used
+ *
+ * @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)
+{
+	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:
+		return 1;
+		break;
+	default:
+		return 0;
+		break;
+	}
+
+}
+
+
+/**
+ * @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(unsigned int cmp_mode)
+{
+	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:
+		return 1;
+		break;
+	default:
+		return 0;
+		break;
+	}
+}
+
+
+/**
+ * @brief method for lossy rounding
+ *
+ * @param value value to round
+ * @param round round parameter
+ *
+ * @return rounded value
+ */
+
+unsigned int round_fwd(unsigned int value, unsigned int round)
+{
+	return value >> round;
+}
+
+
+/**
+ * @brief inverse method for lossy rounding
+ *
+ * @param value value to round back
+ * @param round round parameter
+ *
+ * @return back rounded value
+ */
+
+unsigned int round_inv(unsigned int value, unsigned int round)
+{
+	return value << 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
+ *
+ * @returns (new) updated model
+ */
+
+unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int
+			  model_value)
+{
+	/* 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);
+	/* 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
+ *
+ * @param golomb_par Golomb parameter
+ * @param cmp_mode   compression mode
+ *
+ * @returns the highest still valid spill threshold value
+ */
+
+uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode)
+{
+	unsigned int cutoff;
+	unsigned int max_n_sym_offset;
+	unsigned int max_cw_bits;
+
+	if (golomb_par == 0)
+		return 0;
+
+	if (rdcu_supported_mode_is_used(cmp_mode)) {
+		max_cw_bits = 16; /* the RDCU compressor can only generate code
+				   * words with a length of maximal 16 bits.
+				   */
+	} else {
+		max_cw_bits = 32; /* the ICU compressor can generate code
+				   * words with a length of maximal 32 bits.
+				   */
+	}
+
+	cutoff = (1UL << (ilog_2(golomb_par)+1)) - golomb_par;
+	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 calculate the size of a sample for the different compression modes
+ *
+ * @param cmp_mode compression mode
+ *
+ * @returns the size of a data sample in bytes for the selected compression
+ *	mode;
+ */
+
+size_t size_of_a_sample(unsigned int cmp_mode)
+{
+	size_t sample_len;
+
+	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);
+		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);
+		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);
+		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);
+		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);
+		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);
+		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);
+		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);
+		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);
+		break;
+	default:
+		debug_print("Error: Compression mode not supported.\n");
+		return 0;
+		break;
+	}
+	return sample_len;
+}
+
+
+/**
+ * @brief calculate the need bytes to hold a bitstream
+ *
+ * @param cmp_size compressed data size, measured in bits
+ *
+ * @returns the size in bytes to sore the hole bitstream
+ */
+
+unsigned int size_of_bitstream(unsigned int cmp_size)
+{
+	return (((cmp_size >> 3) + 3) & ~0x3U);
+}
+
+
+/**
+ * @brief calculate the need bytes for the model
+ *
+ * @param cmp_size compressed data size, measured in bits
+ *
+ * @returns the size in bytes to sore the hole bitstream
+ */
+
+unsigned int size_of_model(unsigned int samples, unsigned int cmp_mode)
+{
+	return samples * size_of_a_sample(cmp_mode);
+}
+
+
+/**
+ * @brief print the cmp_cfg structure
+ *
+ * @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("golomb_par: %u\n", cfg->golomb_par);
+	printf("spill: %u\n", cfg->spill);
+	printf("model_value: %u\n", cfg->model_value);
+	printf("round: %u\n", cfg->round);
+	printf("ap1_golomb_par: %u\n", cfg->ap1_golomb_par);
+	printf("ap1_spill: %u\n", cfg->ap1_spill);
+	printf("ap2_golomb_par: %u\n", cfg->ap2_golomb_par);
+	printf("ap2_spill: %u\n", cfg->ap2_spill);
+	printf("input_buf: %p\n", (void *)cfg->input_buf);
+	if (cfg->input_buf != NULL) {
+		printf("input data:");
+		for (i = 0; i < cfg->samples; i++) {
+			printf(" %04X", ((uint16_t *)cfg->input_buf)[i]);
+		}
+		printf("\n");
+	}
+	printf("rdcu_data_adr: 0x%06X\n", cfg->rdcu_data_adr);
+	printf("model_buf: %p\n", (void *)cfg->model_buf);
+	if (cfg->model_buf != NULL) {
+		printf("model data:");
+		for (i = 0; i < cfg->samples; i++) {
+			printf(" %04X", ((uint16_t *)cfg->model_buf)[i]);
+		}
+		printf("\n");
+	}
+	printf("rdcu_model_adr: 0x%06X\n", cfg->rdcu_model_adr);
+	printf("rdcu_new_model_adr: 0x%06X\n", cfg->rdcu_new_model_adr);
+	printf("samples: %u\n", cfg->samples);
+	printf("icu_output_buf: %p\n", (void *)cfg->icu_output_buf);
+	printf("rdcu_buffer_adr: 0x%06X\n", cfg->rdcu_buffer_adr);
+	printf("buffer_length: %u\n", cfg->buffer_length);
+}
+
+
+/**
+ * @brief print the cmp_info structure
+ *
+ * @param info	 compressor information contains information of an executed
+ *		 compression
+ */
+
+void print_cmp_info(const struct cmp_info *info)
+{
+	printf("cmp_mode_used: %u\n", info->cmp_mode_used);
+	printf("model_value_used: %u\n", info->model_value_used);
+	printf("round_used: %u\n", info->round_used);
+	printf("spill_used: %u\n", info->spill_used);
+	printf("golomb_par_used: %u\n", info->golomb_par_used);
+	printf("samples_used: %u\n", info->samples_used);
+	printf("cmp_size: %u\n", info->cmp_size);
+	printf("ap1_cmp_size: %u\n", info->ap1_cmp_size);
+	printf("ap2_cmp_size: %u\n", info->ap2_cmp_size);
+	printf("rdcu_new_model_adr_used: 0x%06X\n", info->rdcu_new_model_adr_used);
+	printf("rdcu_cmp_adr_used: 0x%06X\n", info->rdcu_cmp_adr_used);
+	printf("cmp_err: %#X\n", info->cmp_err);
+}
diff --git a/lib/decmp.c b/lib/decmp.c
new file mode 100644
index 0000000..1138772
--- /dev/null
+++ b/lib/decmp.c
@@ -0,0 +1,1534 @@
+#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;
+}
+
+
+void *malloc_decompressed_data(const struct cmp_info *info)
+{
+	size_t sample_len;
+
+	if (!info)
+		return NULL;
+
+	if (info->samples_used == 0)
+		return NULL;
+
+	sample_len = size_of_a_sample(info->cmp_mode_used);
+
+	return malloc(info->samples_used * sample_len);
+}
+
+
+/**
+ * @brief decompression data pre-processing in RAW mode
+ *
+ * @note in RAW mode the data are uncompressed no pre_processing needed
+ *
+ * @param  cmp_mode_used used compression mode
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int de_raw_pre_process(uint8_t cmp_mode_used)
+{
+	if (!raw_mode_is_used(cmp_mode_used))
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * @brief model decompression pre-processing
+ *
+ * @note
+ *
+ * @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
+ */
+
+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)
+{
+	size_t i;
+	int err;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		return -1;
+
+	if (!model_buf)
+		return -1;
+
+	if (model_value_used > MAX_MODEL_VALUE)
+		return -1;
+
+	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));
+	}
+
+	err = de_lossy_rounding_16(data_buf, samples_used, round_used);
+	if (err)
+		return -1;
+
+	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;
+}
+
+
+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;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		return -1;
+
+	if (!model_buf)
+		return -1;
+
+	if (model_value_used > MAX_MODEL_VALUE)
+		return -1;
+
+	for (i = 0; i < samples_used; i++) {
+		/* overflow is intended */
+		struct S_FX round_model = model_buf[i];
+
+		lossy_rounding_S_FX(&round_model, 1, round_used);
+		data_buf[i] = add_S_FX(data_buf[i], model_buf[i]);
+	}
+
+	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);
+
+	return 0;
+}
+
+
+/**
+ * @brief 1d-differencing decompression per-processing
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int de_diff_16(uint16_t *data_buf, uint32_t samples_used, uint8_t
+		      round_used)
+{
+	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;
+
+	return 0;
+}
+
+
+static int de_diff_32(uint32_t *data_buf, uint32_t samples_used, uint8_t
+		      round_used)
+{
+	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_32(data_buf, samples_used, round_used);
+	if (err)
+		return -1;
+
+	return 0;
+}
+
+
+static int de_diff_S_FX(struct S_FX *data_buf, uint32_t samples_used, uint8_t
+			round_used)
+{
+	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] = add_S_FX(data_buf[i], data_buf[i-1]);
+	}
+
+	err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used);
+	if (err)
+		return -1;
+
+	return 0;
+}
+
+
+static int de_diff_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples_used,
+			    uint8_t round_used)
+{
+	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] = add_S_FX_EFX(data_buf[i], data_buf[i-1]);
+	}
+
+	err = de_lossy_rounding_S_FX_EFX(data_buf, samples_used, round_used);
+	if (err)
+		return -1;
+
+	return 0;
+}
+
+
+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;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		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]);
+	}
+
+	err = de_lossy_rounding_S_FX_NCOB(data_buf, samples_used, round_used);
+	if (err)
+		return -1;
+
+	return 0;
+}
+
+
+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)
+{
+	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] = add_S_FX_EFX_NCOB_ECOB(data_buf[i], data_buf[i-1]);
+	}
+
+	err = de_lossy_rounding_S_FX_EFX_NCOB_ECOB(data_buf, samples_used,
+						   round_used);
+	if (err)
+		return -1;
+
+	return 0;
+}
+
+
+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;
+
+	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;
+	}
+
+	return -1;
+}
+
+
+static uint8_t de_map_to_pos_alg_8(uint8_t value_to_unmap)
+{
+	if (value_to_unmap & 0x1) /* if uneven */
+		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)
+{
+	if (value_to_unmap & 0x1) /* if uneven */
+		return (value_to_unmap + 1) / -2;
+	else
+		return value_to_unmap / 2;
+}
+
+
+static uint32_t de_map_to_pos_alg_32(uint32_t value_to_unmap)
+{
+
+	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;
+}
+
+
+/**
+ * @brief map the unsigned output of the pre-stage to a signed value range for a
+ *	16-bit buffer
+ *
+ * @note change the data_buf in-place
+ *
+ * @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
+ */
+
+static int de_map_to_pos_16(uint16_t *data_buf, uint32_t samples_used, int
+			    zero_mode_used)
+{
+	size_t i;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		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]);
+	}
+	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
+ *
+ * @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
+ */
+
+static int de_map_to_pos_32(uint32_t *data_buf, uint32_t samples_used, int
+			    zero_mode_used)
+{
+	size_t i;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		return -1;
+
+	for (i = 0; i < samples_used; i++) {
+		if (zero_mode_used)
+			data_buf[i] -= 1;
+
+		data_buf[i] = (uint32_t)de_map_to_pos_alg_32(data_buf[i]);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief map the unsigned output of the pre-stage to a signed value range for a
+ *	S_FX buffer
+ *
+ * @note change the data_buf in-place
+ *
+ * @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 0 on success, error otherwise
+ */
+
+static int de_map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples_used, int
+			      zero_mode_used)
+{
+	size_t i;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		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].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);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief map the unsigned output of the pre-stage to a signed value range for a
+ *	S_FX_EFX buffer
+ *
+ * @note change the data_buf in-place
+ *
+ * @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
+ */
+
+static int de_map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t
+				  samples_used, int zero_mode_used)
+{
+	size_t i;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		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;
+		}
+
+		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);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief map the unsigned output of the pre-stage to a signed value range for a
+ *	S_FX_NCOB buffer
+ *
+ * @note change the data_buf in-place
+ *
+ * @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
+ */
+
+static int de_map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t
+				   samples_used, int zero_mode_used)
+{
+	size_t i;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		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].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);
+	}
+	return 0;
+}
+
+
+/**
+ * @brief map the unsigned output of the pre-stage to a signed value range for a
+ *	S_FX_EFX_NCOB_ECOB buffer
+ *
+ * @note change the data_buf in-place
+ *
+ * @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
+ */
+
+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)
+{
+	size_t i;
+
+	if (!samples_used)
+		return 0;
+
+	if (!data_buf)
+		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;
+		}
+
+		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);
+	}
+	return 0;
+}
+
+
+/**
+ * @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
+ *
+ * @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
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int de_map_to_pos_F_FX(uint32_t *data_buf, uint32_t samples_used, int
+			      zero_mode_used)
+{
+	return de_map_to_pos_32(data_buf, samples_used, zero_mode_used);
+}
+
+
+/**
+ * @brief map the unsigned output of the pre-stage to a signed value range
+ *
+ * @note change the data_buf in-place
+ *
+ * @param decompressed_data	pointer to the data to process
+ * @param info			compressor information contains information of
+ *				an executed compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int de_map_to_pos(void *decompressed_data, const struct cmp_info *info)
+{
+	int zero_mode_used;
+
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	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;
+}
+
+
+static unsigned int GetNBits32 (uint32_t *p_value, unsigned int bitOffset,
+				unsigned int nBits, const unsigned int *srcAddr)
+{
+	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;
+	/* 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;
+
+		*(p_value) = *(localAddr) >> bitsRight;
+
+		mask = (0xffffffff >> shiftRight);
+
+		*(p_value) &= mask;
+	} 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;
+	}
+	return nBits;
+}
+
+static unsigned int count_leading_ones(unsigned int value)
+{
+	unsigned int n_ones = 0; /* number of leading 1s */
+
+	while (1) {
+		unsigned int leading_bit;
+
+		leading_bit = value & 0x80000000;
+		if (!leading_bit)
+			break;
+		else {
+			n_ones++;
+			value <<= 1;
+		}
+	}
+	return n_ones;
+}
+
+
+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;
+}
+
+
+static unsigned int Golomb_decoder(unsigned int code_word, unsigned int m,
+				   unsigned int log2_m, unsigned int
+				   *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 */
+
+	q = count_leading_ones(code_word);
+
+	rl = log2_m + 1;
+	code_word <<= (q+1);  /* shift quotient code out */
+
+	r2 = code_word >> (32 - rl);
+	r1 = r2 >> 1;
+
+	cutoff = (1UL << rl) - m;
+
+	if (r1 < cutoff) {
+		cw_len = q + rl;
+		r = r1;
+	} else {
+		cw_len = q + rl + 1;
+		r = r2 - cutoff;
+	}
+
+	if (cw_len > 32)
+		return 0;
+
+	*decoded_cw = q*m + r;
+	return cw_len;
+}
+
+
+typedef unsigned int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *);
+
+static decoder_ptr select_decoder(unsigned int golomb_par)
+{
+	if (!golomb_par)
+		return NULL;
+
+	if (is_a_pow_of_2(golomb_par))
+		return &Rice_decoder;
+	else
+		return &Golomb_decoder;
+}
+
+
+static int decode_raw(const void *compressed_data, const struct cmp_info
+			*info, void *const decompressed_data)
+{
+	if (!info)
+		return -1;
+	if (info->samples_used == 0)
+		return 0;
+	if (!compressed_data)
+		return -1;
+	if (!decompressed_data)
+		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);
+
+	return 0;
+}
+
+static int decode_raw_16(const void *compressed_data, const struct cmp_info
+			*info, uint16_t *const decompressed_data)
+{
+	int err = decode_raw(compressed_data, info, decompressed_data);
+	if (err)
+		return err;
+
+#if defined(__LITTLE_ENDIAN)
+	{
+		size_t i;
+		for (i = 0; i < info->samples_used; i++) {
+			decompressed_data[i] = cpu_to_be16(decompressed_data[i]);
+		}
+	}
+#endif
+	return 0;
+}
+
+
+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 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);
+		}
+	}
+#endif
+	return 0;
+}
+
+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 = GetNBits32(&read_val, read_pos, n_read_bits,
+			       compressed_data);
+	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;
+}
+
+
+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)
+{
+	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;
+	if (*decoded_val >= info->spill_used) /* consistency check */
+		return -1U;
+
+	if (*decoded_val == 0) {/* escape symbol mechanism was used; read unencoded value */
+		unsigned int n_bits;
+		uint32_t unencoded_val;
+
+		if (read_pos + max_cw_len > info->cmp_size) /* check buffer overflow */
+			return -1U;
+		n_bits = GetNBits32(&unencoded_val, read_pos, max_cw_len,
+				    compressed_data);
+		if (!n_bits)
+			return -1U;
+		if (unencoded_val < info->spill_used && unencoded_val != 0) /* consistency check */
+			return -1U;
+
+		*decoded_val = unencoded_val;
+		read_pos += n_bits;
+	}
+	return read_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;
+
+	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;
+
+		unencoded_len = (*decoded_val - info->spill_used + 1) * 2;
+		if (unencoded_len > max_cw_len) /* consistency check */
+			return -1U;
+
+		/* check buffer overflow */
+		if ((read_pos + unencoded_len) > info->cmp_size) {
+			/*TODO: debug message */
+			return -1U;
+		}
+		n_bits = GetNBits32(&unencoded_val, read_pos, unencoded_len,
+				    compressed_data);
+		if (!n_bits)
+			return -1U;
+
+		*decoded_val = unencoded_val + info->spill_used;
+		read_pos += n_bits;
+	}
+	return read_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;
+}
+
+
+static int decode_16(const void *compressed_data, const struct cmp_info *info,
+		     uint16_t *decoded_data)
+{
+	size_t i;
+	unsigned int read_pos = 0;
+
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	if (!decoded_data)
+		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;
+		}
+
+		if (decoded_val > UINT16_MAX)
+			return -1;
+
+		decoded_data[i] = (uint16_t)decoded_val;
+	}
+
+	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;
+	}
+	return 0;
+}
+
+
+static int decode_S_FX(const void *compressed_data, const struct cmp_info *info,
+		       struct S_FX *decoded_data)
+{
+	size_t i;
+	unsigned int read_pos = 0;
+	struct cmp_info info_exp_flag = *info;
+
+	info_exp_flag.golomb_par_used = GOLOMB_PAR_EXPOSURE_FLAGS;
+
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	if (!decoded_data)
+		return -1;
+
+	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;
+
+		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 (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;
+	}
+	return 0;
+}
+
+
+static int decode_S_FX_EFX(const void *compressed_data, const struct cmp_info
+			   *info, struct S_FX_EFX *decoded_data)
+{
+	size_t i;
+	unsigned int read_pos = 0;
+
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	if (!decoded_data)
+		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].EFX = decoded_val;
+	}
+
+	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;
+	}
+	return 0;
+}
+
+
+static int decode_S_FX_NCOB(const void *compressed_data, const struct cmp_info
+			    *info, struct S_FX_NCOB *decoded_data)
+{
+	size_t i;
+	unsigned int read_pos = 0;
+
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	if (!decoded_data)
+		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;
+
+		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 (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;
+	}
+	return 0;
+}
+
+
+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)
+{
+	size_t i;
+	unsigned int read_pos = 0;
+
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	if (!decoded_data)
+		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;
+
+		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;
+
+		read_pos = decode_value(compressed_data, info, read_pos, 32,
+					&decoded_val);
+		if (read_pos == -1U)
+			return -1;
+		decoded_data[i].EFX = decoded_val;
+
+		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;
+
+		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;
+	}
+
+	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;
+	}
+	return 0;
+}
+
+
+static int decode_data(const void *compressed_data, const struct cmp_info *info,
+		       void *decompressed_data)
+{
+	if (!info)
+		return -1;
+
+	if (info->samples_used == 0)
+		return 0;
+
+	if (!compressed_data)
+		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;
+
+	}
+	return -1;
+}
+
+/* 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)
+{
+	int err;
+
+	if (!compressed_data)
+		return -1;
+
+	if (!info)
+		return -1;
+
+	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;
+}
diff --git a/lib/rdcu_cmd.c b/lib/rdcu_cmd.c
new file mode 100644
index 0000000..2154835
--- /dev/null
+++ b/lib/rdcu_cmd.c
@@ -0,0 +1,886 @@
+/**
+ * @file   rdcu_cmd.c
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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 RMAP RDCU RMAP command library
+ * @see FPGA Requirement Specification PLATO-IWF-PL-RS-005 Issue 0.7
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <rmap.h>
+#include <rdcu_cmd.h>
+#include <rdcu_rmap.h>
+
+
+/**
+ * @brief generate a read command for an arbitrary register (internal)
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the register address
+ *
+ * @note this will configure a multi-address, 4 byte wide read command, because
+ *	 the IWF RMAP core does not support single address read commands
+ */
+
+static int rdcu_read_cmd_register_internal(uint16_t trans_id, uint8_t *cmd,
+					   uint32_t addr)
+{
+	return rdcu_gen_cmd(trans_id, cmd, RMAP_READ_ADDR_INC, addr, 4);
+}
+
+
+/**
+ * @brief generate a write command for an arbitrary register (internal)
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the register address
+ *
+ * @returns the size of the command data buffer or 0 on error
+ *
+ * @note this will configure a multi-address, 4 byte wide write command, because
+ *	 the IWF RMAP core does not support single address write commands with
+ *	 reply and CRC check enabled
+ */
+
+static int rdcu_write_cmd_register_internal(uint16_t trans_id, uint8_t *cmd,
+					    uint32_t addr)
+{
+	return rdcu_gen_cmd(trans_id, cmd, RMAP_WRITE_ADDR_INC_VERIFY_REPLY,
+			    addr, 4);
+}
+
+
+/**
+ * @brief create a command to write arbitrary data to the RDCU (internal)
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the address to write to
+ * @param size the number of bytes to write
+ *
+ * @returns the size of the command data buffer or 0 on error
+ *
+ * @note this will configure a multi-address write command with reply enabled
+ */
+
+static int rdcu_write_cmd_data_internal(uint16_t trans_id, uint8_t *cmd,
+					uint32_t addr, uint32_t size)
+{
+	return rdcu_gen_cmd(trans_id, cmd, RMAP_WRITE_ADDR_INC_REPLY,
+			    addr, size);
+}
+
+
+/**
+ * @brief create a command to read arbitrary data to the RDCU (internal)
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the address to read from
+ * @param size the number of bytes to read
+ *
+ * @returns the size of the command data buffer or 0 on error
+ *
+ * @note this will configure a multi-address read command
+ *
+ */
+
+static int rdcu_read_cmd_data_internal(uint16_t trans_id, uint8_t *cmd,
+				       uint32_t addr, uint32_t size)
+{
+	return rdcu_gen_cmd(trans_id, cmd,
+			    RMAP_READ_ADDR_INC, addr, size);
+}
+
+
+/**
+ * @brief create a command to write arbitrary data to the RDCU
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the address to write to
+ * @param size the number of bytes to write
+ *
+ * @returns the size of the command data buffer or 0 on error
+ *
+ * @note this will configure a multi-address write command with reply enabled
+ */
+
+int rdcu_write_cmd_data(uint16_t trans_id, uint8_t *cmd,
+			uint32_t addr, uint32_t size)
+{
+	return rdcu_write_cmd_data_internal(trans_id, cmd, addr, size);
+}
+
+
+/**
+ *
+ * @brief create a command to read arbitrary data to the RDCU
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the address to read from
+ * @param size the number of bytes to read
+ *
+ * @returns the size of the command data buffer or 0 on error
+ *
+ * @note this will configure a multi-address read command
+ *
+ */
+
+int rdcu_read_cmd_data(uint16_t trans_id, uint8_t *cmd,
+		       uint32_t addr, uint32_t size)
+{
+	return rdcu_read_cmd_data_internal(trans_id, cmd, addr, size);
+}
+
+
+
+
+/**
+ * @brief generate a read command for an arbitrary register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the register address
+ *
+ * @note this will configure a single address, 4 byte wide read command
+ */
+
+int rdcu_read_cmd_register(uint16_t trans_id, uint8_t *cmd, uint32_t addr)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, addr);
+}
+
+
+/**
+ * @brief generate a write command for an arbitrary register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param addr the register address
+ *
+ * @returns the size of the command data buffer or 0 on error
+ *
+ * @note this will configure a single address, 4 byte wide write command with
+ *	 reply and CRC check enabled
+ */
+
+int rdcu_write_cmd_register(uint16_t trans_id, uint8_t *cmd, uint32_t addr)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, addr);
+}
+
+
+
+
+/**
+ * @brief create a command to read the RDCU FPGA version register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_fpga_version(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, FPGA_VERSION);
+}
+
+
+/**
+ * @brief create a command to read the RDCU status register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_rdcu_status(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, RDCU_STATUS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU LVDS core status register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_lvds_core_status(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, LVDS_CORE_STATUS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU SPW link status register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_spw_link_status(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, SPW_LINK_STATUS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU SPW error counters register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_spw_err_cntrs(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, SPW_ERR_CNTRS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU RMAP last error register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_rmap_last_err(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, RMAP_LAST_ERR);
+}
+
+
+/**
+ * @brief create a command to read the RDCU RMAP no reply error counter register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_rmap_no_reply_err_cntrs(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       RMAP_NO_REPLY_ERR_CNTRS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU RMAP packet error counter register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_rmap_pckt_err_cntrs(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       RMAP_PCKT_ERR_CNTRS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU ADC values 1 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_adc_values_1(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, ADC_VALUES_1);
+}
+
+
+/**
+ * @brief create a command to read the RDCU ADC values 2 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_adc_values_2(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, ADC_VALUES_2);
+}
+
+
+/**
+ * @brief create a command to read the RDCU ADC values 3 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_adc_values_3(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, ADC_VALUES_3);
+}
+
+
+/**
+ * @brief create a command to read the RDCU ADC values 4 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_adc_values_4(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, ADC_VALUES_4);
+}
+
+
+/**
+ * @brief create a command to read the RDCU ADC status register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_adc_status(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, ADC_STATUS);
+}
+
+
+/**
+ * @brief create a command to read the RDCU compressor status register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_compr_status(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, COMPR_STATUS);
+}
+
+
+
+/**
+ * @brief create a command to write the RDCU reset register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_rdcu_reset(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, RDCU_RESET);
+}
+
+
+/**
+ * @brief create a command to write the RDCU SPW link control register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_spw_link_ctrl(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, SPW_LINK_CTRL);
+}
+
+
+/**
+ * @brief create a command to write the RDCU LVDS control register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_lvds_ctrl(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, LVDS_CTRL);
+}
+
+
+/**
+ *
+ * @brief create a command to write the RDCU core control register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_core_ctrl(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, CORE_CTRL);
+}
+
+
+/**
+ *
+ * @brief create a command to write the RDCU ADC control register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_adc_ctrl(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, ADC_CTRL);
+}
+
+
+/**
+ *
+ * @brief create a command to write the RDCU compressor control register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_compr_ctrl(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, COMPR_CTRL);
+}
+
+
+/**
+ * @brief create a command to write the RDCU compressor parameter 1 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_compressor_param1(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, COMPR_PARAM_1);
+}
+
+
+/**
+ * @brief create a command to write the RDCU compressor parameter 2 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_compressor_param2(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, COMPR_PARAM_2);
+}
+
+
+/**
+ * @brief create a command to write the RDCU adaptive parameter 1 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_adaptive_param1(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd,
+						ADAPTIVE_PARAM_1);
+}
+
+
+/**
+ * @brief create a command to write the RDCU adaptive parameter 2 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_adaptive_param2(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd,
+						ADAPTIVE_PARAM_2);
+}
+
+
+/**
+ * @brief create a command to write the RDCU data start address register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_data_start_addr(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, DATA_START_ADDR);
+}
+
+
+/**
+ * @brief create a command to write the RDCU model start address register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_model_start_addr(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, MODEL_START_ADDR);
+}
+
+
+/**
+ * @brief create a command to write the RDCU number of samples register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_num_samples(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, NUM_SAMPLES);
+}
+
+
+/**
+ * @brief create a command to write the RDCU updated/new model start address register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_new_model_start_addr(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd,
+						UPDATED_MODEL_START_ADDR);
+}
+
+
+/**
+ * @brief create a command to write the RDCU compressed data buffer start
+ *	  address register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_compr_data_buf_start_addr(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd,
+						COMPR_DATA_BUF_START_ADDR);
+}
+
+
+/**
+ * @brief create a command to write the RDCU compressed data buffer length
+ *	  register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_compr_data_buf_len(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd,
+						COMPR_DATA_BUF_LEN);
+}
+
+
+
+/**
+ * @brief create a command to read the RDCU used paramter 1 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_used_param1(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       USED_COMPR_PARAM_1);
+}
+
+
+/**
+ * @brief create a command to read the RDCU unused paramter 2 register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_used_param2(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       USED_COMPR_PARAM_2);
+}
+
+
+/**
+ * @brief create a command to read the RDCU compressed data start address
+ *	  register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_compr_data_start_addr(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       COMPR_DATA_START_ADDR);
+}
+
+
+/**
+ * @brief create a command to read the RDCU compressed data size register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_compr_data_size(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, COMPR_DATA_SIZE);
+}
+
+
+/**
+ * @brief create a command to read the RDCU compressed data adaptive 1 size
+ *	  register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_compr_data_adaptive_1_size(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       COMPR_DATA_ADAPTIVE_1_SIZE);
+}
+
+
+/**
+ * @brief create a command to read the RDCU compressed data adaptive 2 size
+ *	  register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_compr_data_adaptive_2_size(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       COMPR_DATA_ADAPTIVE_2_SIZE);
+}
+
+
+/**
+ * @brief create a command to read the RDCU compression error register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_compr_error(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, COMPR_ERROR);
+}
+
+
+/**
+ * @brief create a command to read the RDCU updated model start address register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_new_model_addr_used(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       USED_UPDATED_MODEL_START_ADDR);
+}
+
+
+/**
+ * @brief create a command to read the RDCU used number of samples register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_samples_used(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd,
+					       USED_NUMBER_OF_SAMPLES);
+}
+
+
+/**
+ * @brief create a command to write the SRAM EDAC Control register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_write_cmd_sram_edac_ctrl(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_write_cmd_register_internal(trans_id, cmd, SRAM_EDAC_CTRL);
+}
+
+/**
+ * @brief create a command to read the SRAM EDAC Status register
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_read_cmd_sram_edac_status(uint16_t trans_id, uint8_t *cmd)
+{
+	return rdcu_read_cmd_register_internal(trans_id, cmd, SRAM_EDAC_STATUS);
+}
diff --git a/lib/rdcu_ctrl.c b/lib/rdcu_ctrl.c
new file mode 100644
index 0000000..a1e3b0f
--- /dev/null
+++ b/lib/rdcu_ctrl.c
@@ -0,0 +1,2491 @@
+/**
+ * @file   rdcu_ctrl.c
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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 RMAP RDCU control library
+ * @see FPGA Requirement Specification PLATO-IWF-PL-RS-005 Issue 0.7
+ *
+ * USAGE:
+ *	All sync() calls respect the direction of the sync, i.e. read-only
+ *	registers in the RDCU are synced to the local mirror
+ *	and vice-versa for write-only register
+ *	The only exception are SRAM (data) related syncs, they specifiy
+ *	the direction by a directional suffix, which is either _icu_rdcu
+ *	for ICU->RDCU, i.e. transfer local to remote, or _rdcu_icu for a
+ *	read-back
+ *
+ *	Access to the local mirror is provided by _get or _set calls, so
+ *	to configure a register in the RDCU, one would call the sequence:
+ *
+ *	set_register_xyz(someargument);
+ *	sync_register_xyz();
+ *
+ *	while(rdcu_sync_status())
+ *		wait_busy_or_do_something_else_your_choice();
+ *
+ *	[sync_comple]
+ *
+ *	and to read a register:
+ *
+ *	sync_register_uvw()
+ *
+ *	while(rdcu_sync_status())
+ *		wait_busy_or_do_something_else_your_choice();
+ *
+ *	[sync_comple]
+ *
+ *	value = get_register_uvw();
+ *
+ *
+ * WARNING: this has not been thoroughly tested and is in need of inspection
+ *	    with regards to the specification, in order to locate any
+ *	    register transcription errors or typos
+ *	    In the PLATO-IWF-PL-RS-005 Issue 0.7 (at least the one I have),
+ *	    register bits in tables and register figures are sometimes in
+ *	    conflict. Only values from tables have been used here.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <byteorder.h>
+#include <rmap.h>
+#include <rdcu_cmd.h>
+#include <rdcu_ctrl.h>
+#include <rdcu_rmap.h>
+
+
+static struct rdcu_mirror *rdcu;
+
+
+/**
+ * @brief get the 4 FPGA minor/major version digits
+ * @see RDCU-FRS-FN-0522
+ */
+
+uint16_t rdcu_get_fpga_version(void)
+{
+	return (uint16_t) (rdcu->fpga_version & 0xFFFF);
+}
+
+
+/**
+ * @brief get the RDCU board serial number
+ * @see RDCU-FRS-FN-0532
+ */
+
+uint32_t rdcu_get_rdcu_status_board_serial_number(void)
+{
+	return (rdcu->rdcu_status >> 12) & 0xFUL;
+}
+
+
+/**
+ * @brief get FPGA core power good bit
+ * @see RDCU-FRS-FN-0532
+ *
+ * @returns 0 : FPGA core power supply failure
+ *	    1 : FPGA core power supply (1.5V) is good
+ */
+
+uint32_t rdcu_get_rdcu_status_fpga_core_power_good(void)
+{
+	return (rdcu->rdcu_status >> 6) & 0x1UL;
+}
+
+
+/**
+ * @brief get core power good bit
+ * @see RDCU-FRS-FN-0532
+ *
+ * @returns 0 : FPGA core power supply failure
+ *	    1 : FPGA core power supply (1.8V) is good
+ */
+
+uint32_t rdcu_get_rdcu_status_core_power_good(void)
+{
+	return (rdcu->rdcu_status >> 5) & 0x1UL;
+}
+
+
+/**
+ * @brief get i/o power good bit
+ * @see RDCU-FRS-FN-0532
+ *
+ * @returns 0 : FPGA core power supply failure
+ *	    1 : FPGA core power supply (3.3V) is good
+ */
+
+uint32_t rdcu_get_rdcu_status_io_power_good(void)
+{
+	return (rdcu->rdcu_status >> 4) & 0x1UL;
+}
+
+
+/**
+ * @brief get reset by register bit
+ * @see RDCU-FRS-FN-0532
+ *
+ * @returns 0 : not the reset reason
+ *	    1 : reset triggered by register bit
+ */
+
+uint32_t rdcu_get_rdcu_status_reset_by_register(void)
+{
+	return (rdcu->rdcu_status >> 1) & 0x1UL;
+}
+
+
+/**
+ * @brief get power on reset bit
+ * @see RDCU-FRS-FN-0532
+ *
+ * @returns 0 : not the reset reason
+ *	    1 : reset triggered by power on
+ */
+
+uint32_t rdcu_get_rdcu_status_power_on_reset(void)
+{
+	return rdcu->rdcu_status & 0x1UL;
+}
+
+
+/**
+ * @brief get RMAP Target logical address
+ * @see RDCU-FRS-FN-0542
+ */
+
+uint8_t rdcu_get_rmap_target_logical_address(void)
+{
+	return (uint8_t) ((rdcu->lvds_core_status >> 24) & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP Target command key
+ * @see RDCU-FRS-FN-0542
+ */
+
+uint8_t rdcu_get_rmap_target_cmd_key(void)
+{
+	return (uint8_t) ((rdcu->lvds_core_status >> 16) & 0xFFUL);
+}
+
+
+/**
+ * @brief get LVDS link enabled bit
+ *
+ * @param link the link number (0-7)
+ *
+ * @see RDCU-FRS-FN-0542
+ *
+ * @returns 0 : LVDS link disabled
+ *	    1 : LVDS link enabled
+ *	    other: invalid link argument
+ */
+
+uint32_t rdcu_get_lvds_link_enabled(uint32_t link)
+{
+	if (link > 7)
+		return -1;
+
+	return (rdcu->lvds_core_status >> link) & 0x1UL;
+}
+
+
+/**
+ * @brief get SpW empty packet count
+ * @see RDCU-FRS-FN-0552
+ */
+
+uint16_t rdcu_get_spw_empty_pckt_cnt(void)
+{
+	return (uint16_t) ((rdcu->spw_link_status >> 16) & 0xFFUL);
+}
+
+
+/**
+ * @brief get SpW run-state clock divisor value
+ * @see RDCU-FRS-FN-0552
+ */
+
+uint8_t rdcu_get_spw_run_clk_div(void)
+{
+	return (uint8_t) ((rdcu->spw_link_status >> 8) & 0x3FUL);
+}
+
+
+/**
+ * @brief get SpW link run state
+ * @see RDCU-FRS-FN-0552
+ *
+ * @returns 0 : SpW link not established
+ *	    1 : SpW link is running
+ */
+
+uint8_t rdcu_get_spw_lnk_run_state(void)
+{
+	return (uint8_t) ((rdcu->spw_link_status >> 8) & 0x1UL);
+}
+
+
+/**
+ * @brief get SpW link credit errors
+ * @see RDCU-FRS-FN-0562
+ */
+
+uint8_t rdcu_get_spw_lnk_credit_errs(void)
+{
+	return (uint8_t) ((rdcu->spw_link_status >> 24) & 0xFFUL);
+}
+
+
+/**
+ * @brief get SpW link escape errors
+ * @see RDCU-FRS-FN-0562
+ */
+
+uint8_t rdcu_get_spw_lnk_escape_errs(void)
+{
+	return (uint8_t) ((rdcu->spw_link_status >> 16) & 0xFFUL);
+}
+
+
+/**
+ * @brief get SpW link parity errors
+ * @see RDCU-FRS-FN-0562
+ */
+
+uint8_t rdcu_get_spw_lnk_parity_errs(void)
+{
+	return (uint8_t) ((rdcu->spw_link_status >> 8) & 0xFFUL);
+}
+
+
+/**
+ * @brief get SpW link disconnect errors
+ * @see RDCU-FRS-FN-0562
+ */
+
+uint8_t rdcu_get_spw_lnk_disconnect_errs(void)
+{
+	return (uint8_t) (rdcu->spw_link_status & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP last error user code
+ * @see RDCU-FRS-FN-0572
+ */
+
+uint8_t rdcu_get_rmap_last_error_user_code(void)
+{
+	return (uint8_t) ((rdcu->rmap_last_err >> 8) & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP last error standard code
+ * @see RDCU-FRS-FN-0572
+ */
+
+uint8_t rdcu_get_rmap_last_error_standard_code(void)
+{
+	return (uint8_t) (rdcu->rmap_last_err & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP incomplete header error counter
+ * @see RDCU-FRS-FN-0582
+ */
+
+uint8_t rdcu_get_rmap_incomplete_hdrs(void)
+{
+	return (uint8_t) ((rdcu->rmap_no_reply_err_cntrs >> 24) & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP received reply packet counter
+ * @see RDCU-FRS-FN-0582
+ */
+
+uint8_t rdcu_get_rmap_recv_reply_pckts(void)
+{
+	return (uint8_t) ((rdcu->rmap_no_reply_err_cntrs >> 8) & 0xFFUL);
+}
+
+
+/**
+ * @brief get received non-RMAP packet counter
+ * @see RDCU-FRS-FN-0582
+ */
+
+uint8_t rdcu_get_recv_non_rmap_pckts(void)
+{
+	return (uint8_t) (rdcu->rmap_no_reply_err_cntrs & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP packet with length or content error counter
+ * @see RDCU-FRS-FN-0592
+ */
+
+uint8_t rdcu_get_rmap_pckt_errs(void)
+{
+	return (uint8_t) ((rdcu->rmap_pckt_err_cntrs >> 24) & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP operation error counter
+ * @see RDCU-FRS-FN-0592
+ */
+
+uint8_t rdcu_get_rmap_oper_errs(void)
+{
+	return (uint8_t) ((rdcu->rmap_pckt_err_cntrs >> 16) & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP command authorization error counter
+ * @see RDCU-FRS-FN-0592
+ */
+
+uint8_t rdcu_get_rmap_cmd_auth_errs(void)
+{
+	return (uint8_t) ((rdcu->rmap_pckt_err_cntrs >> 8) & 0xFFUL);
+}
+
+
+/**
+ * @brief get RMAP header error counter
+ * @see RDCU-FRS-FN-0592
+ */
+
+uint8_t rdcu_get_rmap_hdr_errs(void)
+{
+	return (uint8_t) (rdcu->rmap_pckt_err_cntrs & 0xFFUL);
+}
+
+
+/**
+ * @brief get an ADC value
+ * @param id the ADC value id to get (1-8)
+ * @see RDCU-FRS-FN-0602
+ *
+ * @return adc value, if 0xFFFF, id may be invalid
+ */
+
+uint16_t rdcu_get_adc_value(int id)
+{
+	switch (id) {
+	case 1:
+		return (uint16_t)  (rdcu->adc_values_1        & 0xFFFFUL);
+	case 2:
+		return (uint16_t) ((rdcu->adc_values_1 >> 16) & 0xFFFFUL);
+	case 3:
+		return (uint16_t)  (rdcu->adc_values_2        & 0xFFFFUL);
+	case 4:
+		return (uint16_t) ((rdcu->adc_values_2 >> 16) & 0xFFFFUL);
+	case 5:
+		return (uint16_t)  (rdcu->adc_values_3        & 0xFFFFUL);
+	case 6:
+		return (uint16_t) ((rdcu->adc_values_3 >> 16) & 0xFFFFUL);
+	case 7:
+		return (uint16_t)  (rdcu->adc_values_4        & 0xFFFFUL);
+	case 8:
+		return (uint16_t) ((rdcu->adc_values_4 >> 16) & 0xFFFFUL);
+
+	default:
+		break;
+	}
+
+	return 0xFFFF;
+}
+
+
+/**
+ * @brief get valid ADC values
+ * @see RDCU-FRS-FN-0612
+ *
+ * @returns 0: no valid ADC values in the ADC value registers
+ *	    1: the ADC value registers contain valid ADC results
+ */
+
+uint32_t rdcu_get_valid_adc_values(void)
+{
+	return ((rdcu->adc_status >> 4) & 0x1UL);
+}
+
+
+/**
+ * @brief get ADC logic reset
+ * @see RDCU-FRS-FN-0612
+ *
+ * @returns 0: normal ADC operation
+ *	    1: ADC logic is in reset state
+ */
+
+uint32_t rdcu_get_adc_logic_reset(void)
+{
+	return ((rdcu->adc_status >> 1) & 0x1UL);
+}
+
+
+/**
+ * @brief get ADC logic enabled
+ * @see RDCU-FRS-FN-0612
+ *
+ * @returns 0: ADC logic disabled
+ *	    1: ADC logic enabled (normal operation)
+ */
+
+uint32_t rdcu_get_adc_logic_enabled(void)
+{
+	return (rdcu->adc_status & 0x1UL);
+}
+
+
+/**
+ * @brief get RDCU Interrupt status
+ * @see RDCU-FRS-FN-0632
+ *
+ * @returns 0: Interrupt is disabled
+ *	    1: Interrupt is enabled
+ */
+
+uint32_t rdcu_get_rdcu_interrupt_enabled(void)
+{
+	return ((rdcu->compr_status >> 8) & 0x1UL);
+}
+
+
+/**
+ * @brief get compressor status valid
+ * @see RDCU-FRS-FN-0632
+ *
+ * @returns 0: Data is invalid
+ *	    1: Data is valid
+ */
+
+uint32_t rdcu_get_compr_status_valid(void)
+{
+	return ((rdcu->compr_status >> 5) & 0x1UL);
+}
+
+
+/**
+ * @brief get data compressor ready
+ * @see RDCU-FRS-FN-0632
+ *
+ * @returns 0: Compressor is busy
+ *	    1: Compressor is ready
+ */
+
+uint32_t rdcu_get_data_compr_ready(void)
+{
+	return ((rdcu->compr_status >> 4) & 0x1UL);
+}
+
+
+/**
+ * @brief get data compressor interrupted
+ * @see RDCU-FRS-FN-0632
+ *
+ * @returns 0: No compressor interruption
+ *	    1: Compressor was interrupted
+ */
+
+uint32_t rdcu_get_data_compr_interrupted(void)
+{
+	return ((rdcu->compr_status >> 1) & 0x1UL);
+}
+
+
+/**
+ * @brief get data compressor activce
+ * @see RDCU-FRS-FN-0632
+ *
+ * @returns 0: Compressor is on hold
+ *	    1: Compressor is active
+ */
+
+uint32_t rdcu_get_data_compr_active(void)
+{
+	return (rdcu->compr_status & 0x1UL);
+}
+
+
+/**
+ * @brief set RDCU Board Reset Keyword
+ * @see RDCU-FRS-FN-0662
+ *
+ * @note the valid key is 0x9A
+ */
+
+void rdcu_set_rdcu_board_reset_keyword(uint8_t key)
+{
+	/* clear and set */
+	rdcu->rdcu_reset &= ~(0xFUL << 24);
+	rdcu->rdcu_reset |= ((uint32_t) key << 24);
+}
+
+
+/**
+ * @brief set RDCU Internal Bus Reset bit
+ * @see RDCU-FRS-FN-0662
+ *
+ * @note The bit will auto-clear in the FPGA, to clear the local mirror,
+ *	 make sure to rdcu_clear_rdcu_bus_reset() so the FPGA internal bus
+ *	 is not reset every time rdcu_sync_rdcu_reset() is called, as
+ *	 write-only registers are note synced back from the RDCU
+ */
+
+void rdcu_set_rdcu_bus_reset(void)
+{
+	rdcu->rdcu_reset |= (0x1UL << 12);
+}
+
+
+/**
+ * @brief clear RDCU Internal Bus Reset bit
+ * @see RDCU-FRS-FN-0662
+ */
+
+void rdcu_clear_rdcu_bus_reset(void)
+{
+	rdcu->rdcu_reset &= ~(0x1UL << 12);
+}
+
+
+/**
+ * @brief set RDCU RMAP error counter Reset bit
+ * @see RDCU-FRS-FN-0662
+ *
+ * @note The bit will auto-clear in the FPGA, to clear the local mirror,
+ *	 make sure to rdcu_clear_rdcu_rmap_error_cntr_reset() so the FPGA
+ *	 does not reset the RMAP error counter every time rdcu_sync_rdcu_reset()
+ *	 is called, as write-only registers are not synced back from the RDCU.
+ */
+
+void rdcu_set_rdcu_rmap_error_cntr_reset(void)
+{
+	rdcu->rdcu_reset |= (0x1UL << 9);
+}
+
+
+/**
+ * @brief clear RDCU RMAP error counter Reset bit
+ * @see RDCU-FRS-FN-0662
+ */
+
+void rdcu_clear_rdcu_rmap_error_cntr_reset(void)
+{
+	rdcu->rdcu_reset &= ~(0x1UL << 9);
+}
+
+
+/**
+ * @brief set RDCU SpaceWire error counter Reset bit
+ * @see RDCU-FRS-FN-0662
+ *
+ * @note The bit will auto-clear in the FPGA, to clear the local mirror,
+ *	 make sure to rdcu_clear_rdcu_spw_error_cntr_reset() so the FPGA
+ *	 does not reset the SpW error counter every time rdcu_sync_rdcu_reset()
+ *	 is called, as write-only registers are not synced back from the RDCU.
+ */
+
+void rdcu_set_rdcu_spw_error_cntr_reset(void)
+{
+	rdcu->rdcu_reset |= (0x1UL << 8);
+}
+
+
+/**
+ * @brief clear RDCU SpaceWire error counter Reset bit
+ * @see RDCU-FRS-FN-0662
+ */
+
+void rdcu_clear_rdcu_spw_error_cntr_reset(void)
+{
+	rdcu->rdcu_reset &= ~(0x1UL << 8);
+}
+
+
+/**
+ * @brief set RDCU Board Reset bit
+ * @see RDCU-FRS-FN-0662
+ *
+ * @note The bit will auto-clear in the FPGA, to clear the local mirror,
+ *	 make sure to rdcu_clear_rdcu_board_reset() so the FPGA
+ *	 does not reset the SpW error counter every time rdcu_sync_rdcu_reset()
+ *	 is called, as write-only registers are not synced back from the RDCU.
+ */
+
+void rdcu_set_rdcu_board_reset(void)
+{
+	rdcu->rdcu_reset |= (0x1UL << 1);
+}
+
+
+/**
+ * @brief clear RDCU SpaceWire error counter Reset bit
+ * @see RDCU-FRS-FN-0662
+ */
+
+void rdcu_clear_rdcu_board_reset(void)
+{
+	rdcu->rdcu_reset &= ~(0x1UL << 1);
+}
+
+
+/**
+ * @brief set SpW Link Control Run-State Clock Divisor
+ * @see RDCU-FRS-FN-0672
+ *
+ * @note value is scaling factor minus 1
+ */
+
+int rdcu_set_spw_link_run_clkdiv(uint8_t div)
+{
+	if (div > 49)
+		return -1;
+
+	/* clear and set */
+	rdcu->spw_link_ctrl &= ~(0x3FUL << 8);
+	rdcu->spw_link_ctrl |= ((uint32_t) div << 8);
+
+	return 0;
+}
+
+
+/**
+ * @brief set LVDS link enabled
+ *
+ * @param link the link number (0-7)
+ *
+ * @see RDCU-FRS-FN-0682
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_lvds_link_enabled(uint32_t link)
+{
+	if (link > 7)
+		return -1;
+
+	rdcu->lvds_ctrl |= (0x1UL << link);
+
+	return 0;
+}
+
+
+/**
+ * @brief set LVDS link disabled
+ *
+ * @param link the link number (0-7)
+ *
+ * @see RDCU-FRS-FN-0682
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_lvds_link_disabled(uint32_t link)
+{
+	if (link > 7)
+		return -1;
+
+	rdcu->lvds_ctrl &= ~((0x1UL << link));
+
+	return 0;
+}
+
+
+/**
+ * @brief set RMAP Target logical address
+ * @see RDCU-FRS-FN-0692
+ */
+
+void rdcu_set_rmap_target_logical_address(uint8_t addr)
+{
+	rdcu->core_ctrl &= ~(0xFFUL << 24);
+	rdcu->core_ctrl |= ((uint32_t) addr) << 24;
+}
+
+
+/**
+ * @brief set RMAP Target command key
+ * @see RDCU-FRS-FN-0692
+ */
+
+void rdcu_set_rmap_target_cmd_key(uint8_t key)
+{
+	rdcu->core_ctrl &= ~(0xFFUL << 16);
+	rdcu->core_ctrl |= ((uint32_t) key) << 16;
+}
+
+
+/**
+ * @brief set the ADC logic reset bit
+ * @see RDCU-FRS-FN-0712
+ *
+ * @note use rdcu_clear_adc_logic_reset(), rdcu_sync_adc_ctrl() sequence
+ *	 to clear and start normal operation
+ */
+
+void rdcu_set_adc_logic_reset(void)
+{
+	rdcu->adc_ctrl |= (0x1UL << 1);
+}
+
+
+/**
+ * @brief clear the ADC logic reset bit
+ * @see RDCU-FRS-FN-0712
+ */
+
+void rdcu_clear_adc_logic_reset(void)
+{
+	rdcu->adc_ctrl &= ~(0x1UL << 1);
+}
+
+
+/**
+ * @brief set the ADC logic enabled
+ * @see RDCU-FRS-FN-0712
+ */
+
+void rdcu_set_adc_logic_enabled(void)
+{
+	rdcu->adc_ctrl |= 0x1UL;
+}
+
+
+/**
+ * @brief set the ADC logic disabled
+ * @see RDCU-FRS-FN-0712
+ */
+
+void rdcu_set_adc_logic_disabled(void)
+{
+	rdcu->adc_ctrl &= ~0x1UL;
+}
+
+
+/**
+ * @brief enable RDCU interrupt signal to the ICU
+ * @see RDCU-FRS-FN-0732
+ */
+
+void rdcu_set_rdcu_interrupt(void)
+{
+	rdcu->compr_ctrl |= (0x1UL << 8);
+}
+
+
+/**
+ * @brief disable RDCU interrupt signal to the ICU
+ * @see RDCU-FRS-FN-0732
+ */
+
+void rdcu_clear_rdcu_interrupt(void)
+{
+	rdcu->compr_ctrl &= ~(0x1UL << 8);
+}
+
+
+/**
+ * @brief set data compressor interrupt
+ * @see RDCU-FRS-FN-0732
+ *
+ * @note The bit will auto-clear in the FPGA once compression is complete.
+ *	 To clear the local mirror, make sure to
+ *	 rdcu_clear_data_compr_interrupt() so the FPGA does not interrupt
+ *	 data compression unexepectedly when rdcu_sync_compr_ctrl()
+ *	 is called, as write-only registers are not synced back from the RDCU.
+ *
+ */
+
+void rdcu_set_data_compr_interrupt(void)
+{
+	rdcu->compr_ctrl |= (0x1UL << 1);
+}
+
+
+/**
+ * @brief clear data compressor interrupt
+ * @see RDCU-FRS-FN-0732
+ */
+
+void rdcu_clear_data_compr_interrupt(void)
+{
+	rdcu->compr_ctrl &= ~(0x1UL << 1);
+}
+
+
+/**
+ * @brief set data compressor start bit
+ * @see RDCU-FRS-FN-0732
+ *
+ * @note The bit will auto-clear in the FPGA once compression is complete.
+ *	 To clear the local mirror, make sure to
+ *	 rdcu_clear_data_compr_start() so the FPGA does not start
+ *	 data compression unexepectedly when rdcu_sync_compr_ctrl()
+ *	 is called, as write-only registers are not synced back from the RDCU.
+ */
+
+void rdcu_set_data_compr_start(void)
+{
+	rdcu->compr_ctrl |= 0x1UL;
+}
+
+
+/**
+ * @brief clear data compressor start bit
+ * @see RDCU-FRS-FN-0732
+ */
+
+void rdcu_clear_data_compr_start(void)
+{
+	rdcu->compr_ctrl &= ~0x1UL;
+}
+
+
+/**
+ * @brief set number of noise bits to be rounded
+ * @see RDCU-FRS-FN-0772
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_noise_bits_rounded(uint32_t rpar)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (rpar > 3)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->compressor_param1 &= ~(0x3UL << 16);
+	rdcu->compressor_param1 |=  (rpar << 16);
+
+	return 0;
+}
+
+
+/**
+ * @brief set weighting parameter
+ * @see RDCU-FRS-FN-0772
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_weighting_param(uint32_t mval)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (mval > 16)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->compressor_param1 &= ~(0x1FUL << 8);
+	rdcu->compressor_param1 |=  (mval << 8);
+
+	return 0;
+}
+
+
+/**
+ * @brief set compression mode
+ * @see RDCU-FRS-FN-0772
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_compression_mode(uint32_t cmode)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (cmode > 4)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->compressor_param1 &= ~0xFFUL;
+	rdcu->compressor_param1 |= cmode;
+
+	return 0;
+}
+
+
+/**
+ * @brief set spillover threshold for encoding outliers
+ * @see RDCU-FRS-FN-0782
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_spillover_threshold(uint32_t spill)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (spill < 2)
+		return -1;
+
+	if (spill > 16383)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->compressor_param2 &= ~(0x3FFFUL << 8);
+	rdcu->compressor_param2 |=  (spill    << 8);
+
+	return 0;
+}
+
+
+/**
+ * @brief set Golomb parameter for dictionary selection
+ * @see RDCU-FRS-FN-0782
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_golomb_param(uint32_t gpar)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (!gpar)
+		return -1;
+
+	if (gpar > 63)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->compressor_param2 &= ~0x3FUL;
+	rdcu->compressor_param2 |= gpar;
+
+	return 0;
+}
+
+
+/**
+ * @brief set adaptive 1 spillover threshold for encoding outliers
+ * @see RDCU-FRS-FN-0792
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_adaptive_1_spillover_threshold(uint32_t spill)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (spill < 2)
+		return -1;
+
+	if (spill > 16383)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->adaptive_param1 &= ~(0x3FFFUL << 8);
+	rdcu->adaptive_param1 |=  (spill    << 8);
+
+	return 0;
+}
+
+
+/**
+ * @brief set adaptive 1 Golomb parameter for dictionary selection
+ * @see RDCU-FRS-FN-0792
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_adaptive_1_golomb_param(uint32_t gpar)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (!gpar)
+		return -1;
+
+	if (gpar > 63)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->adaptive_param1 &= ~0x3FUL;
+	rdcu->adaptive_param1 |= gpar;
+
+	return 0;
+}
+
+
+
+/**
+ * @brief set adaptive 2 spillover threshold for encoding outliers
+ * @see RDCU-FRS-FN-0802
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_adaptive_2_spillover_threshold(uint32_t spill)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (spill < 2)
+		return -1;
+
+	if (spill > 16383)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->adaptive_param2 &= ~(0x3FFFUL << 8);
+	rdcu->adaptive_param2 |=  (spill    << 8);
+
+	return 0;
+}
+
+
+/**
+ * @brief set adaptive 2 Golomb parameter for dictionary selection
+ * @see RDCU-FRS-FN-0802
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_adaptive_2_golomb_param(uint32_t gpar)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (!gpar)
+		return -1;
+
+	if (gpar > 63)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->adaptive_param2 &= ~0x3FUL;
+	rdcu->adaptive_param2 |= gpar;
+
+	return 0;
+}
+
+
+/**
+ * @brief set data start address
+ * @see RDCU-FRS-FN-0812
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_data_start_addr(uint32_t addr)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (addr > 0x00FFFFFFUL)
+		return -1;
+
+	if (addr & 0x3)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->data_start_addr &= ~0x00FFFFFFUL;
+	rdcu->data_start_addr |= addr;
+
+	return 0;
+}
+
+
+/**
+ * @brief set model start address
+ * @see RDCU-FRS-FN-0822
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_model_start_addr(uint32_t addr)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (addr > 0x00FFFFFFUL)
+		return -1;
+
+	if (addr & 0x3)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->model_start_addr &= ~0x00FFFFFFUL;
+	rdcu->model_start_addr |= addr;
+
+	return 0;
+}
+
+
+/**
+ * @brief set number of data samples (16 bit values) to compress
+ * @see RDCU-FRS-FN-0832
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_num_samples(uint32_t samples)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (samples > 0x00FFFFFFUL)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->num_samples &= ~0x00FFFFFFUL;
+	rdcu->num_samples |= samples;
+
+	return 0;
+}
+
+
+/**
+ * @brief set updated_model/new model start address
+ * @see RDCU-FRS-FN-0842
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_new_model_start_addr(uint32_t addr)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (addr > 0x00FFFFFFUL)
+		return -1;
+
+	if (addr & 0x3)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+
+	/* clear and set */
+	rdcu->new_model_start_addr &= ~0x00FFFFFFUL;
+	rdcu->new_model_start_addr |= addr;
+
+	return 0;
+}
+
+
+/**
+ * @brief set compressed data buffer start address
+ * @see RDCU-FRS-FN-0850
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_compr_data_buf_start_addr(uint32_t addr)
+{
+#ifndef SKIP_CMP_PAR_CHECK
+	if (addr > 0x00FFFFFFUL)
+		return -1;
+
+	if (addr & 0x3)
+		return -1;
+#endif /*SKIP_CMP_PAR_CHECK*/
+	/* clear and set */
+	rdcu->compr_data_buf_start_addr &= ~0x00FFFFFFUL;
+	rdcu->compr_data_buf_start_addr |= addr;
+
+	return 0;
+}
+
+
+/**
+ * @brief set compressed data buffer length (in 16 bit values)
+ * @see RDCU-FRS-FN-0862
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_set_compr_data_buf_len(uint32_t samples)
+{
+	if (samples > 0x00FFFFFFUL)
+		return -1;
+
+	/* clear and set */
+	rdcu->compr_data_buf_len &= ~0x00FFFFFFUL;
+	rdcu->compr_data_buf_len |= samples;
+
+	return 0;
+}
+
+
+/**
+ * @brief get compression mode
+ * @see RDCU-FRS-FN-0892
+ *
+ * @returns the CMODE
+ */
+
+uint32_t rdcu_get_compression_mode(void)
+{
+	return rdcu->used_param1 & 0xFFUL;
+}
+
+
+/**
+ * @brief get number of noise bits to be rounded
+ * @see RDCU-FRS-FN-0892
+ *
+ * @returns the RPAR
+ */
+
+uint32_t rdcu_get_noise_bits_rounded(void)
+{
+	return (rdcu->used_param1 >> 16) & 0x3UL;
+}
+
+
+/**
+ * @brief get weighting parameter
+ * @see RDCU-FRS-FN-0892
+ *
+ * @returns the RPAR
+ */
+
+uint32_t rdcu_get_weighting_param(void)
+{
+	return (rdcu->used_param1 >> 8) & 0x1FUL;
+}
+
+
+/**
+ * @brief get spillover threshold for encoding outliers
+ * @see RDCU-FRS-FN-0902
+ *
+ * @returns the SPILL
+ */
+
+uint32_t rdcu_get_spillover_threshold(void)
+{
+	return (rdcu->used_param2 >> 8) & 0x3FFFUL;
+}
+
+
+/**
+ * @brief get spillover threshold for encoding outliers
+ * @see RDCU-FRS-FN-0902
+ *
+ * @returns the GPAR
+ */
+
+uint32_t rdcu_get_golomb_param(void)
+{
+	return rdcu->used_param2 & 0x3FUL;
+}
+
+
+/**
+ * @brief get compressed data start address
+ * @see RDCU-FRS-FN-0912
+ *
+ * @returns the output SRAM address
+ */
+
+uint32_t rdcu_get_compr_data_start_addr(void)
+{
+	return rdcu->compr_data_start_addr & 0x00FFFFFFUL;
+}
+
+
+/**
+ * @brief get compressed data size
+ * @see RDCU-FRS-FN-0922
+ *
+ * @returns the compressed data size in bits
+ */
+
+uint32_t rdcu_get_compr_data_size(void)
+{
+	return rdcu->compr_data_size;
+}
+
+
+/**
+ * @brief get compressed data adaptive 1 size
+ * @see RDCU-FRS-FN-0932
+ *
+ * @returns the adaptive 1 compressed data size in bits
+ */
+
+uint32_t rdcu_get_compr_data_adaptive_1_size(void)
+{
+	return rdcu->compr_data_adaptive_1_size;
+}
+
+
+/**
+ * @brief get compressed data adaptive 2 size
+ * @see RDCU-FRS-FN-0942
+ *
+ * @returns the adaptive 2 compressed data size in bits
+ */
+
+uint32_t rdcu_get_compr_data_adaptive_2_size(void)
+{
+	return rdcu->compr_data_adaptive_2_size;
+}
+
+
+/**
+ * @brief get compression error code
+ * @see RDCU-FRS-FN-0954
+ *
+ * @returns the compression error code
+ */
+
+uint16_t rdcu_get_compr_error(void)
+{
+	return (uint16_t) (rdcu->compr_error & 0x3FFUL);
+}
+
+
+/**
+ * @brief get model info start address
+ * @see RDCU-FRS-FN-0960
+ *
+ */
+
+uint32_t rdcu_get_new_model_addr_used(void)
+{
+	return rdcu->new_model_addr_used & 0x00FFFFFFUL;
+}
+
+
+/**
+ * @brief get model info length
+ * @see RDCU-FRS-FN-0972
+ *
+ * @returns the number of 16-bit samples in the model
+ */
+
+uint32_t rdcu_get_samples_used(void)
+{
+	return rdcu->samples_used & 0x00FFFFFFUL;
+}
+
+
+/**
+ * @brief set EDAC sub chip die address
+ * @see RDCU-FRS-FN-1012
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_edac_set_sub_chip_die_addr(uint32_t ca)
+{
+	if (ca > 0xFUL)
+		return -1;
+
+	rdcu->sram_edac_ctrl &= ~(0xFUL << 12);
+	rdcu->sram_edac_ctrl |=  (ca    << 12);
+
+	return 0;
+}
+
+
+/**
+ * @brief set EDAC control register read operation
+ * @see RDCU-FRS-FN-1012
+ */
+
+void rdcu_edac_set_ctrl_reg_read_op(void)
+{
+	rdcu->sram_edac_ctrl |= (0x1UL << 9);
+}
+
+
+/**
+ * @brief set EDAC control register write operation
+ * @see RDCU-FRS-FN-1012
+ */
+
+void rdcu_edac_set_ctrl_reg_write_op(void)
+{
+	rdcu->sram_edac_ctrl &= ~(0x1UL << 9);
+}
+
+
+/**
+ * @brief set EDAC to bypass
+ * @see RDCU-FRS-FN-1012
+ */
+
+void rdcu_edac_set_bypass(void)
+{
+	rdcu->sram_edac_ctrl |= (0x1UL << 8);
+}
+
+
+/**
+ * @brief set EDAC to normal operation
+ * @see RDCU-FRS-FN-1012
+ */
+
+void rdcu_edac_clear_bypass(void)
+{
+	rdcu->sram_edac_ctrl &= ~(0x1UL << 8);
+}
+
+
+/**
+ * @brief set EDAC SRAM scrubbing information
+ * @see RDCU-FRS-FN-1012
+ */
+
+void rdcu_edac_set_scrub_info(uint8_t nfo)
+{
+	rdcu->sram_edac_ctrl &= ~0xFFUL;
+	rdcu->sram_edac_ctrl |= (uint32_t) nfo & 0xFFUL;
+}
+
+
+/**
+ * @brief get EDAC sub chip die address
+ * @see RDCU-FRS-FN-1032
+ */
+
+uint32_t rdcu_edac_get_sub_chip_die_addr(void)
+{
+	return (rdcu->sram_edac_status >> 12) & 0xFUL;
+}
+
+
+/**
+ * @brief get EDAC bypass status
+ * @see RDCU-FRS-FN-1032
+ *
+ * @returns 0: normal EDAC operation
+ *	    1: EDAC function will be bypassed
+ */
+
+uint32_t rdcu_edac_get_bypass_status(void)
+{
+	return (rdcu->sram_edac_status >> 8) & 0x1UL;
+}
+
+
+/**
+ * @brief get EDAC SRAM scrubbing information
+ * @see RDCU-FRS-FN-1032
+ */
+
+uint8_t rdcu_edac_get_scrub_info(void)
+{
+	return (uint8_t) (rdcu->sram_edac_ctrl & 0xFFUL);
+}
+
+
+/**
+ * @brief read data from the local SRAM mirror
+ *
+ * @param buf the buffer to read to (if NULL, the required size is returned)
+ *
+ * @param addr an address within the RDCU SRAM
+ * @param size the number of bytes read
+ *
+ * @returns the number of bytes read, < 0 on error
+ */
+
+int rdcu_read_sram(void *buf, uint32_t addr, uint32_t size)
+{
+	if (addr > RDCU_SRAM_END)
+		return -1;
+
+	if (size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if (addr + size > RDCU_SRAM_END)
+		return -1;
+
+	if (buf)
+		memcpy(buf, &rdcu->sram[addr], size);
+
+	return (int)size; /* lol */
+}
+
+
+/**
+ * @brief write arbitrary big-endian data to the local SRAM mirror
+ *
+ * @param buf the buffer to read from
+ *
+ * @param addr an address within the RDCU SRAM
+ * @param size the number of bytes read
+ *
+ * @returns the number of bytes written, < 0 on error
+ */
+
+int rdcu_write_sram(void *buf, uint32_t addr, uint32_t size)
+{
+	if (!buf)
+		return 0;
+
+	if (addr > RDCU_SRAM_END)
+		return -1;
+
+	if (size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if (addr + size > RDCU_SRAM_END)
+		return -1;
+
+	if (buf)
+		memcpy(&rdcu->sram[addr], buf, size);
+
+	return (int)size; /* lol */
+}
+
+
+/**
+ * @brief write uint8_t formatted data to the local SRAM mirror. (This function
+ *	is endian-safe.)
+ *
+ * @param buf the buffer to read from
+ *
+ * @param addr an address within the RDCU SRAM
+ * @param size the number of bytes read
+ *
+ * @returns the number of bytes written, < 0 on error
+ */
+
+int rdcu_write_sram_8(uint8_t *buf, uint32_t addr, uint32_t size)
+{
+	return rdcu_write_sram(buf, addr, size);
+}
+
+
+/**
+ * @brief write uint16_t formatted data to the local SRAM mirror. This function
+ *	is endian-safe.
+ *
+ * @param buf the buffer to read from
+ *
+ * @param addr an address within the RDCU SRAM
+ * @param size the number of bytes read
+ *
+ * @returns the number of bytes written, < 0 on error
+ */
+
+int rdcu_write_sram_16(uint16_t *buf, uint32_t addr, uint32_t size)
+{
+	if (!buf)
+		return 0;
+
+	if (size & 0x1)
+		return -1;
+
+	if (addr > RDCU_SRAM_END)
+		return -1;
+
+	if (size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if (addr + size > RDCU_SRAM_END)
+		return -1;
+
+#if !(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+	return rdcu_write_sram(buf, addr, size);
+#else
+	{
+		uint32_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]);
+		}
+	}
+	return (int)size; /* lol */
+#endif /* __BYTE_ORDER__ */
+}
+
+
+/**
+ * @brief write uint32_t formatted data to the local SRAM mirror. This function
+ *	is endian-safe.
+ *
+ * @param buf the buffer to read from
+ *
+ * @param addr an address within the RDCU SRAM
+ * @param size the number of bytes read
+ *
+ * @returns the number of bytes written, < 0 on error
+ */
+
+int rdcu_write_sram_32(uint32_t *buf, uint32_t addr, uint32_t size)
+{
+	if (!buf)
+		return 0;
+
+	if (size & 0x3)
+		return -1;
+
+	if (addr > RDCU_SRAM_END)
+		return -1;
+
+	if (size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if (addr + size > RDCU_SRAM_END)
+		return -1;
+
+#if !(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+	return rdcu_write_sram(buf, addr, size);
+#else
+	{
+		uint32_t i;
+
+	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]);
+		}
+	}
+	return (int)size; /* lol */
+#endif /* __BYTE_ORDER__ */
+}
+
+
+/**
+ * @brief sync the FPGA version (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_fpga_version(void)
+{
+	return rdcu_sync(rdcu_read_cmd_fpga_version, &rdcu->fpga_version, 0);
+}
+
+
+/**
+ * @brief sync the RDCU status register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_rdcu_status(void)
+{
+	return rdcu_sync(rdcu_read_cmd_rdcu_status, &rdcu->rdcu_status, 0);
+}
+
+
+/**
+ * @brief sync the LVDS core status register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_lvds_core_status(void)
+{
+	return rdcu_sync(rdcu_read_cmd_lvds_core_status,
+			 &rdcu->lvds_core_status, 0);
+}
+
+
+/**
+ * @brief sync the SpW link status register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_spw_link_status(void)
+{
+	return rdcu_sync(rdcu_read_cmd_spw_link_status,
+			 &rdcu->spw_link_status, 0);
+}
+
+
+/**
+ * @brief sync the SpW Error Counter register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_spw_err_cntrs(void)
+{
+	return rdcu_sync(rdcu_read_cmd_spw_err_cntrs,
+			 &rdcu->spw_err_cntrs, 0);
+}
+
+
+/**
+ * @brief sync the RMAP Last Error register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_rmap_last_err(void)
+{
+	return rdcu_sync(rdcu_read_cmd_rmap_last_err,
+			 &rdcu->rmap_last_err, 0);
+}
+
+
+/**
+ * @brief sync the RMAP No-Reply Error Counter register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_rmap_no_reply_err_cntrs(void)
+{
+	return rdcu_sync(rdcu_read_cmd_rmap_no_reply_err_cntrs,
+			 &rdcu->rmap_no_reply_err_cntrs, 0);
+}
+
+
+/**
+ * @brief sync the RMAP Packet Error Counter register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_rmap_pckt_err_cntrs(void)
+{
+	return rdcu_sync(rdcu_read_cmd_rmap_pckt_err_cntrs,
+			 &rdcu->rmap_pckt_err_cntrs, 0);
+}
+
+
+
+/**
+ * @brief sync an ADC values register (read only)
+ *
+ * @param id the ADC value register id (1-4)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_adc_values(int id)
+{
+	switch (id) {
+	case '1':
+		return rdcu_sync(rdcu_read_cmd_adc_values_1,
+				 &rdcu->adc_values_1, 0);
+	case '2':
+		return rdcu_sync(rdcu_read_cmd_adc_values_2,
+				 &rdcu->adc_values_2, 0);
+	case '3':
+		return rdcu_sync(rdcu_read_cmd_adc_values_3,
+				 &rdcu->adc_values_3, 0);
+	case '4':
+		return rdcu_sync(rdcu_read_cmd_adc_values_4,
+				 &rdcu->adc_values_4, 0);
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+
+/**
+ * @brief sync the ADC Status register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_adc_status(void)
+{
+	return rdcu_sync(rdcu_read_cmd_adc_status,
+			 &rdcu->adc_status, 0);
+}
+
+
+/**
+ * @brief sync the Compressor Status register (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_status(void)
+{
+	return rdcu_sync(rdcu_read_cmd_compr_status,
+			 &rdcu->compr_status, 0);
+}
+
+
+/**
+ * @brief sync the RDCU Reset register (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_rdcu_reset(void)
+{
+	return rdcu_sync(rdcu_write_cmd_rdcu_reset,
+			 &rdcu->rdcu_reset, 4);
+}
+
+
+/**
+ * @brief sync the SpW Link Control register (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_spw_link_ctrl(void)
+{
+	return rdcu_sync(rdcu_write_cmd_spw_link_ctrl,
+			 &rdcu->spw_link_ctrl, 4);
+}
+
+/**
+ * @brief sync the LVDS Control register (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_lvds_ctrl(void)
+{
+	return rdcu_sync(rdcu_write_cmd_lvds_ctrl,
+			 &rdcu->lvds_ctrl, 4);
+}
+
+
+/**
+ * @brief sync the Core Control register (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_core_ctrl(void)
+{
+	return rdcu_sync(rdcu_write_cmd_core_ctrl,
+			 &rdcu->core_ctrl, 4);
+}
+
+
+/**
+ * @brief sync the ADC Control register (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_adc_ctrl(void)
+{
+	return rdcu_sync(rdcu_write_cmd_adc_ctrl,
+			 &rdcu->adc_ctrl, 4);
+}
+
+
+/**
+ * @brief sync the Compressor Control register (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_ctrl(void)
+{
+	return rdcu_sync(rdcu_write_cmd_compr_ctrl,
+			 &rdcu->compr_ctrl, 4);
+}
+
+
+/**
+ * @brief sync the Compressor Parameter 1 (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compressor_param1(void)
+{
+	return rdcu_sync(rdcu_write_cmd_compressor_param1,
+			 &rdcu->compressor_param1, 4);
+}
+
+
+/**
+ * @brief sync the Compressor Parameter 2 (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compressor_param2(void)
+{
+	return rdcu_sync(rdcu_write_cmd_compressor_param2,
+			 &rdcu->compressor_param2, 4);
+}
+
+
+/**
+ * @brief sync the Adaptive Parameter 1 (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_adaptive_param1(void)
+{
+	return rdcu_sync(rdcu_write_cmd_adaptive_param1,
+			 &rdcu->adaptive_param1, 4);
+}
+
+
+/**
+ * @brief sync the Adaptive Parameter 2 (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_adaptive_param2(void)
+{
+	return rdcu_sync(rdcu_write_cmd_adaptive_param2,
+			 &rdcu->adaptive_param2, 4);
+}
+
+
+/**
+ * @brief sync the Data Start Address (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_data_start_addr(void)
+{
+	return rdcu_sync(rdcu_write_cmd_data_start_addr,
+			 &rdcu->data_start_addr, 4);
+}
+
+
+/**
+ * @brief sync the Model Start Address (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_model_start_addr(void)
+{
+	return rdcu_sync(rdcu_write_cmd_model_start_addr,
+			 &rdcu->model_start_addr, 4);
+}
+
+
+/**
+ * @brief sync the Number of Samples (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_num_samples(void)
+{
+	return rdcu_sync(rdcu_write_cmd_num_samples,
+			 &rdcu->num_samples, 4);
+}
+
+
+/**
+ * @brief sync the Model Start Address (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_new_model_start_addr(void)
+{
+	return rdcu_sync(rdcu_write_cmd_new_model_start_addr,
+			 &rdcu->new_model_start_addr, 4);
+}
+
+
+/**
+ * @brief sync the Compressed Data Buffer Start Address (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_data_buf_start_addr(void)
+{
+	return rdcu_sync(rdcu_write_cmd_compr_data_buf_start_addr,
+			 &rdcu->compr_data_buf_start_addr, 4);
+}
+
+
+/**
+ * @brief sync the Compressed Data Buffer Length (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_data_buf_len(void)
+{
+	return rdcu_sync(rdcu_write_cmd_compr_data_buf_len,
+			 &rdcu->compr_data_buf_len, 4);
+}
+
+
+/**
+ * @brief sync the Used Parameter 1 (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_used_param1(void)
+{
+	return rdcu_sync(rdcu_read_cmd_used_param1, &rdcu->used_param1, 0);
+}
+
+
+/**
+ * @brief sync the Used Parameter 2 (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_used_param2(void)
+{
+	return rdcu_sync(rdcu_read_cmd_used_param2, &rdcu->used_param2, 0);
+}
+
+
+/**
+ * @brief sync the Compressed Data Start Address (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_data_start_addr(void)
+{
+	return rdcu_sync(rdcu_read_cmd_compr_data_start_addr,
+			 &rdcu->compr_data_start_addr, 0);
+}
+
+
+/**
+ * @brief sync the Compressed Data Start Size (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_data_size(void)
+{
+	return rdcu_sync(rdcu_read_cmd_compr_data_size,
+			 &rdcu->compr_data_size, 0);
+}
+
+
+/**
+ * @brief sync the Compressed Data Adaptive 1 Size (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_data_adaptive_1_size(void)
+{
+	return rdcu_sync(rdcu_read_cmd_compr_data_adaptive_1_size,
+			 &rdcu->compr_data_adaptive_1_size, 0);
+}
+
+
+/**
+ * @brief sync the Compressed Data Adaptive 2 Size (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_data_adaptive_2_size(void)
+{
+	return rdcu_sync(rdcu_read_cmd_compr_data_adaptive_2_size,
+			 &rdcu->compr_data_adaptive_2_size, 0);
+}
+
+
+/**
+ * @brief sync the Compression Error (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_compr_error(void)
+{
+	return rdcu_sync(rdcu_read_cmd_compr_error,
+			 &rdcu->compr_error, 0);
+}
+
+
+/**
+ * @brief sync the Model Info Start Address (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_new_model_addr_used(void)
+{
+	return rdcu_sync(rdcu_read_cmd_new_model_addr_used,
+			 &rdcu->new_model_addr_used, 0);
+}
+
+
+/**
+ * @brief sync the Model Info Length (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_samples_used(void)
+{
+	return rdcu_sync(rdcu_read_cmd_samples_used,
+			 &rdcu->samples_used, 0);
+}
+
+
+/**
+ * @brief sync the SRAM EDAC Control (write only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_sram_edac_ctrl(void)
+{
+	return rdcu_sync(rdcu_write_cmd_sram_edac_ctrl,
+			 &rdcu->sram_edac_ctrl, 4);
+}
+
+
+/**
+ * @brief sync the SRAM EDAC Status (read only)
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_sram_edac_status(void)
+{
+	return rdcu_sync(rdcu_read_cmd_sram_edac_status,
+			 &rdcu->sram_edac_status, 0);
+}
+
+
+/**
+ * @brief sync a range of 32 bit words of the local mirror to the remote SRAM
+ *
+ * @param addr and address within the remote SRAM
+ * @param size the number of bytes to sync
+ * @param mtu the maximum transport unit per RMAP packet; choose wisely
+ *
+ * @note due to restrictions, the number of bytes and mtu must be a multiple
+ *	 of 4; the address must be aligned to 32-bits as well
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_mirror_to_sram(uint32_t addr, uint32_t size, uint32_t mtu)
+{
+	int ret;
+
+	uint32_t sent = 0;
+	uint32_t tx_bytes;
+
+
+	if (mtu & 0x3)
+		return -1;
+
+	if (addr & 0x3)
+		return -1;
+
+	if (size & 0x3)
+		return -1;
+
+	if (addr > RDCU_SRAM_END)
+		return -1;
+
+	if (size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if ((addr + size) > (RDCU_SRAM_END + 1))
+		return -1;
+
+
+	tx_bytes = size;
+
+	while (tx_bytes >= mtu) {
+
+		ret = rdcu_sync_data(rdcu_write_cmd_data, addr + sent,
+				     &rdcu->sram[addr + sent], mtu, 0);
+		if (ret > 0)
+			continue;
+
+		if (ret < 0)
+			return -1;
+
+
+		sent     += mtu;
+		tx_bytes -= mtu;
+	}
+
+	while (tx_bytes) {
+		ret = rdcu_sync_data(rdcu_write_cmd_data, addr + sent,
+				     &rdcu->sram[addr + sent], tx_bytes, 0);
+		if (ret > 0)
+			continue;
+
+		if (ret < 0)
+			return -1;
+
+		tx_bytes = 0;
+	}
+
+
+	return 0;
+}
+
+
+/**
+ * @brief sync a range of 32 bit words of the remote SRAM to the local mirror
+ *
+ * @param addr an address within the remote SRAM
+ * @param size the number of bytes to sync
+ * @param mtu the maximum transport unit per RMAP packet; choose wisely
+ *
+ * @note due to restrictions, the number of bytes and mtu must be a multiple
+ *	 of 4; the address must be aligned to 32-bits as well
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_sync_sram_to_mirror(uint32_t addr, uint32_t size, uint32_t mtu)
+{
+	int ret;
+
+	uint32_t recv = 0;
+	uint32_t rx_bytes;
+
+
+	if (mtu & 0x3)
+		return -1;
+
+	if (addr & 0x3)
+		return -1;
+
+	if (size & 0x3)
+		return -1;
+
+	if (addr > RDCU_SRAM_END)
+		return -1;
+
+	if (size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if ((addr + size) > (RDCU_SRAM_END + 1))
+		return -1;
+
+
+	rx_bytes = size;
+
+	while (rx_bytes >= mtu) {
+
+		ret = rdcu_sync_data(rdcu_read_cmd_data, addr + recv,
+				     &rdcu->sram[addr + recv], mtu, 1);
+
+#if 0
+		while (rdcu_rmap_sync_status() > 3)
+			;
+#endif
+
+		if (ret > 0)
+			continue;
+
+		if (ret < 0)
+			return -1;
+
+		recv     += mtu;
+		rx_bytes -= mtu;
+	}
+
+	while (rx_bytes) {
+		ret = rdcu_sync_data(rdcu_read_cmd_data, addr + recv,
+				     &rdcu->sram[addr + recv], rx_bytes, 1);
+		if (ret > 0)
+			continue;
+
+		if (ret < 0)
+			return -1;
+
+		rx_bytes = 0;
+	}
+
+
+	return 0;
+}
+
+
+/**
+ * @brief sync a range of 32 bit words of the remote SRAM to the local mirror
+ *	and form the local mirror to the remote SRAM in parallel
+ *
+ * @param rx_addr the read address within the remote SRAM
+ * @param rx_size the number of bytes to sync to the mirror
+ * @param tx_addr the write address within the remote SRAM
+ * @param tx_size the number of bytes to sync to the SRAM
+ * @param mtu the maximum transport unit per RMAP packet; choose wisely
+ *
+ * @note due to restrictions, the number of bytes and mtu must be a multiple
+ *	 of 4; the address must be aligned to 32-bits as well
+ *
+ * @returns 0 on succes, otherwise error
+ */
+
+int rdcu_sync_sram_mirror_parallel(uint32_t rx_addr, uint32_t rx_size,
+				   uint32_t tx_addr, uint32_t tx_size,
+				   uint32_t mtu)
+{
+	int ret;
+
+	uint32_t recv = 0;
+	uint32_t sent = 0;
+	uint32_t rx_bytes;
+	uint32_t tx_bytes;
+
+
+	if (mtu & 0x3)
+		return -1;
+
+	if (rx_addr & 0x3)
+		return -1;
+
+	if (tx_addr & 0x3)
+		return -1;
+
+	if (rx_size & 0x3)
+		return -1;
+
+	if (tx_size & 0x3)
+		return -1;
+
+	if (rx_addr > RDCU_SRAM_END)
+		return -1;
+
+	if (tx_addr > RDCU_SRAM_END)
+		return -1;
+
+	if (rx_size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if (tx_size > RDCU_SRAM_SIZE)
+		return -1;
+
+	if ((rx_addr + rx_size) > (RDCU_SRAM_END + 1))
+		return -1;
+
+	if ((tx_addr + tx_size) > (RDCU_SRAM_END + 1))
+		return -1;
+
+	/* check buffer overlap */
+	if (rx_addr < tx_addr+tx_size && rx_addr+rx_size > tx_addr)
+		return -1;
+
+
+	rx_bytes = rx_size;
+	tx_bytes = tx_size;
+
+	while (rx_bytes || tx_bytes) {
+		if (rx_bytes) {
+			if (rx_bytes >= mtu) {
+				ret = rdcu_sync_data(rdcu_read_cmd_data,
+						     rx_addr + recv,
+						     &rdcu->sram[rx_addr + recv],
+						     mtu, 1);
+#if 0
+				while (rdcu_rmap_sync_status() > 3)
+					;
+#endif
+
+				if (ret < 0)
+					return -1;
+
+				if (ret == 0) {
+					recv     += mtu;
+					rx_bytes -= mtu;
+				}
+			} else {
+				ret = rdcu_sync_data(rdcu_read_cmd_data,
+						     rx_addr + recv,
+						     &rdcu->sram[rx_addr + recv],
+						     rx_bytes, 1);
+				if (ret < 0)
+					return -1;
+
+				if (ret == 0)
+					rx_bytes = 0;
+			}
+		}
+
+		if (tx_bytes) {
+			if (tx_bytes >= mtu) {
+				ret = rdcu_sync_data(rdcu_write_cmd_data,
+						     tx_addr + sent,
+						     &rdcu->sram[tx_addr + sent],
+						     mtu, 0);
+
+				if (ret < 0)
+					return -1;
+
+				if (ret == 0) {
+					sent     += mtu;
+					tx_bytes -= mtu;
+				}
+			} else {
+				ret = rdcu_sync_data(rdcu_write_cmd_data,
+						     tx_addr + sent,
+						     &rdcu->sram[tx_addr + sent],
+						     tx_bytes, 0);
+
+				if (ret < 0)
+					return -1;
+
+				if (ret == 0)
+					tx_bytes = 0;
+			}
+		}
+	}
+	return 0;
+}
+
+
+
+/**
+ * @brief initialise the rdcu control library
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_ctrl_init(void)
+{
+	rdcu = (struct rdcu_mirror *) malloc(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 */
+
+	rdcu->sram = (uint8_t *) malloc(RDCU_SRAM_SIZE);
+	if (!rdcu->sram) {
+		printf("Error allocating memory for the RDCU SRAM mirror\n");
+		return -1;
+	}
+#endif
+
+	memset(rdcu->sram, 0, RDCU_SRAM_SIZE);
+	
+	return 0;
+}
diff --git a/lib/rdcu_pkt_to_file.c b/lib/rdcu_pkt_to_file.c
new file mode 100644
index 0000000..24c213e
--- /dev/null
+++ b/lib/rdcu_pkt_to_file.c
@@ -0,0 +1,472 @@
+/**
+ * @file   rdcu_pkt_to_file.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 RDCU packets to file library
+ *
+ * This library provided a rmap_rx and rmap_tx function for the rdcu_rmap
+ * library to write generated packets into text files.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#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"
+
+/* Name of directory were the RMAP packages are stored */
+static char tc_folder_dir[MAX_TC_FOLDER_DIR_LEN] = "TC_FILES";
+
+
+/**
+ * @brief set the directory name were the RMAP packages are stored
+ *
+ * @param dir_name	Name of directory were the RMAP packages are stored
+ */
+
+void set_tc_folder_dir(const char *dir_name)
+{
+	if (!dir_name)
+		return;
+
+	strncpy(tc_folder_dir, dir_name, sizeof(tc_folder_dir));
+	/*  Ensure null-termination. */
+	tc_folder_dir[sizeof(tc_folder_dir) - 1] = '\0';
+	return;
+}
+
+
+/**
+ * @brief return a file to write with the name format dir_name/XXX.tc, where XXX
+ *	is n_tc in decimal representation
+ *
+ * @param dir_name	name of directory were the RMAP packages are stored
+ * @param n_tc		number of TC commands
+ *
+ * @return	pointer to the new file stream
+ * @see https://developers.redhat.com/blog/2018/05/24/detecting-string-truncation-with-gcc-8/
+ */
+
+static FILE *open_file(const char *dir_name, int n_tc)
+{
+	char *pathname;
+	FILE *fp;
+	int n;
+
+	errno = 0;
+	n = snprintf(NULL, 0, "%s/%04d.tc", dir_name, n_tc);
+	if (n < 0) {
+		perror("snprintf failed");
+		abort();
+	}
+
+	errno = 0;
+	pathname = (char *)malloc((size_t)n + 1);
+	if (!pathname) {
+		perror("malloc failed");
+		abort();
+	}
+
+	errno = 0;
+	n = snprintf(pathname, (size_t)n + 1, "%s/%04d.tc", dir_name, n_tc);
+	if (n < 0) {
+		perror("snprintf failed");
+		abort();
+	}
+
+	fp = fopen(pathname, "w");
+	free(pathname);
+	return fp;
+}
+
+
+/**
+ * @brief Implementation of the rmap_rx function for the rdcu_rmap lib. All
+ *	generated packages are write to a file.
+ */
+
+static int32_t rmap_tx_to_file(const void *hdr, uint32_t hdr_size,
+			       const uint8_t non_crc_bytes, const void *data,
+			       uint32_t data_size)
+{
+	static int n_pkt = 1; /* number of packets */
+	static char tc_folder_dir_old[MAX_TC_FOLDER_DIR_LEN] = {0};
+	uint8_t *blob = NULL;
+	int n, i;
+	FILE *fp;
+
+	if (hdr == NULL)
+		return 0;
+
+	/* make sure that string is null-terminated */
+	tc_folder_dir[MAX_TC_FOLDER_DIR_LEN - 1] = '\0';
+
+	if (strcmp(tc_folder_dir, tc_folder_dir_old) != 0) {
+		struct stat st = { 0 };
+
+		n_pkt = 1;
+
+		/* creating a directory if that directory does not exist */
+		if (stat(tc_folder_dir, &st) == -1) {
+			int err;
+			#if defined(_WIN32) || defined(_WIN64)
+				err = mkdir(tc_folder_dir);
+			#else
+				err = mkdir(tc_folder_dir, 0700);
+			#endif
+			if (err)
+				return -1;
+		}
+
+		strncpy(tc_folder_dir_old, tc_folder_dir,
+			sizeof(tc_folder_dir_old));
+		tc_folder_dir_old[sizeof(tc_folder_dir_old) - 1] = '\0';
+	}
+
+	n = rdcu_package(NULL, hdr, hdr_size, non_crc_bytes, data, data_size);
+	blob = malloc(n);
+	if (!blob) {
+		printf("malloc for tx_pkt faild\n");
+		return -1;
+	}
+
+	n = rdcu_package(blob, hdr, hdr_size, non_crc_bytes, data, data_size);
+
+	fp = open_file(tc_folder_dir, n_pkt);
+
+	if (fp == NULL) {
+		perror("fopen()");
+		free(blob);
+		return -1;
+	}
+
+	for (i = 0; i < n; i++) {
+		/* printf("%02X ", blob[i]); */
+		fprintf(fp, "%02X ", blob[i]);
+		/* if (i && !((i + 1) % 40)) */
+		/* printf("\n"); */
+	}
+
+	/* printf("\n"); */
+	fprintf(fp, "\n");
+	fclose(fp);
+
+	free(blob);
+
+	n_pkt++;
+	return 0;
+}
+
+
+/**
+ * @brief Dummy implementation of the rmap_rx function for the rdcu_rmap lib. We
+ * do not want to receive any packages.
+ */
+
+static uint32_t rmap_rx_dummy(uint8_t *pkt)
+{
+	(void)(pkt);
+	return 0;
+}
+
+
+/**
+ * @brief read out .rdcu_pkt_mode_cfg configure file
+ *
+ * @param icu_addr	RMAP source logical address
+ * @param rdcu_addr	RMAP destination logical address
+ * @param mtu		the maximum data transfer size per unit
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+static int read_rdcu_pkt_mode_cfg(uint8_t *icu_addr, uint8_t *rdcu_addr,
+				  int *mtu)
+{
+	/* TODO: Build string" %s/.rdcu_pkt_mode_cfg", RDCU_PKT_MODE_DIR */
+	char line[256];
+	char *end;
+	unsigned int read_all = 0;
+	FILE *fp = fopen(".rdcu_pkt_mode_cfg", "r");
+
+	*icu_addr = 0;
+	*rdcu_addr = 0;
+	*mtu = 0;
+
+	if (fp == NULL) {
+		perror("fopen()");
+		return -1;
+	}
+
+	while (fgets(line, sizeof(line), fp)) {
+		size_t l;
+		long i;
+		char *p;
+
+		p = strchr(line, '\n');
+		if (p) {
+			*p = '\0';
+		} else {
+			fprintf(stderr, "Error read in line to long.\n");
+			return -1;
+		}
+
+		if (line[0] == ' ' || line[0] == '\t' || line[0] == '#')
+			continue;
+		if (!strncmp(line, "ICU_ADDR", l = strlen("ICU_ADDR"))) {
+			end = NULL;
+			errno = 0;
+			i = strtol(line + l, &end, 0);
+			if (end == line + l || errno == ERANGE || i < 0 ||
+			    i > 0xFF) {
+				fprintf(stderr, "Error reading ICU_ADDR.\n");
+				errno = 0;
+				return -1;
+			}
+			*icu_addr = (uint8_t)i;
+			read_all |= 1UL << 0;
+			continue;
+		}
+		if (!strncmp(line, "RDCU_ADDR", l = strlen("RDCU_ADDR"))) {
+			end = NULL;
+			errno = 0;
+			i = strtol(line + l, &end, 0);
+			if (end == line + l || errno == ERANGE || i < 0
+			    || i > 0xFF) {
+				fprintf(stderr, "Error reading RDCU_ADDR.\n");
+				errno = 0;
+				return -1;
+			}
+			*rdcu_addr = (uint8_t)i;
+			read_all |= 1UL << 1;
+			continue;
+		}
+		if (!strncmp(line, "MTU", l = strlen("MTU"))) {
+			end = NULL;
+			errno = 0;
+			i = strtol(line + l, &end, 0);
+			if (end == line + l || errno == ERANGE || i < 0 ||
+			    i > INT_MAX) {
+				fprintf(stderr, "Error reading MTU.\n");
+				errno = 0;
+				return -1;
+			}
+			*mtu = (int)i;
+			read_all |= 1UL << 2;
+			continue;
+		}
+	}
+	fclose(fp);
+
+	/* all keywords read? */
+	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);
+
+	return 0;
+}
+
+
+/**
+ * @brief initialise the RDCU packets to file library
+ *
+ * @note use the .rdcu_pkt_mode_cfg file to read the icu_addr, rdcu_addr and mtu
+ *	parameters
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+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;
+	rdcu_ctrl_init();
+	rdcu_set_source_logical_address(icu_addr);
+	rdcu_set_destination_logical_address(rdcu_addr);
+	rdcu_set_destination_key(RDCU_DEST_KEY);
+	rdcu_rmap_init(mtu, rmap_tx_to_file, rmap_rx_dummy);
+	return 0;
+}
+
+
+/**
+ * @brief generate the rmap packets to set up a 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
+ *	.rdcu_pkt_mode_cfg file
+ *
+ * @param cfg	compressor configuration contains all parameters required for
+ *		compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int gen_write_rdcu_pkts(const struct cmp_cfg *cfg)
+{
+	struct stat st = { 0 };
+
+	if (!cfg)
+		return -1;
+
+	/* creating TC_DIR directory if that directory does not exist */
+	if (stat(TC_DIR, &st) == -1) {
+		int err;
+		#if defined(_WIN32) || defined(_WIN64)
+			err = mkdir(TC_DIR);
+		#else
+			err = mkdir(TC_DIR, 0700);
+		#endif
+		if (err)
+			return -1;
+	}
+
+	set_tc_folder_dir(TC_DIR "/compress_data");
+	if (rdcu_compress_data(cfg))
+		return -1;
+
+	return 0;
+}
+
+
+/**
+ * @brief generate the rmap packets to read the result of a 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
+ *	.rdcu_pkt_mode_cfg file
+ *
+ * @param info	 compressor information contains information of an executed
+ *		 compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int gen_read_rdcu_pkts(const struct cmp_info *info)
+{
+	int s;
+	void *tmp_buf;
+	struct stat st = { 0 };
+
+	if (!info)
+		return -1;
+
+	/* creating TC_DIR directory if that directory does not exist */
+	if (stat(TC_DIR, &st) == -1) {
+		int err;
+		#if defined(_WIN32) || defined(_WIN64)
+			err = mkdir(TC_DIR);
+		#else
+			err = mkdir(TC_DIR, 0700);
+		#endif
+		if (err)
+			return -1;
+	}
+
+	set_tc_folder_dir(TC_DIR "/read_status");
+	if (rdcu_read_cmp_status(NULL))
+		return -1;
+
+	set_tc_folder_dir(TC_DIR "/read_info");
+	if (rdcu_read_cmp_info(NULL))
+		return -1;
+
+	set_tc_folder_dir(TC_DIR "/read_cmp_data");
+	s = rdcu_read_cmp_bitstream(info, NULL);
+	if (s < 0)
+		return -1;
+	tmp_buf = malloc((size_t)s);
+	if (!tmp_buf)
+		return -1;
+	s = rdcu_read_cmp_bitstream(info, tmp_buf);
+	free(tmp_buf);
+	if (s < 0)
+		return -1;
+
+	if (model_mode_is_used(info->cmp_mode_used)) {
+		set_tc_folder_dir(TC_DIR "/read_upmodel");
+		s = rdcu_read_model(info, NULL);
+		if (s < 0)
+			return -1;
+		tmp_buf = malloc((size_t)s);
+		if (!tmp_buf)
+			return -1;
+		s = rdcu_read_model(info, tmp_buf);
+		free(tmp_buf);
+		if (s < 0)
+			return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * @brief generate the rmap packets to set up a 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
+ *	of last_cmp_size
+ * @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
+ *	.rdcu_pkt_mode_cfg file
+ *
+ * @param cfg		compressor configuration contains all parameters required for
+ *			compression
+ * @param last_info	compression information from the last executed
+ *			compression
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int gen_rdcu_parallel_pkts(const struct cmp_cfg *cfg,
+			   const struct cmp_info *last_info)
+{
+	struct stat st = { 0 };
+
+	if (!cfg)
+		return -1;
+
+	/* creating TC_DIR directory if that directory does not exist */
+	if (stat(TC_DIR, &st) == -1) {
+		int err;
+		#if defined(_WIN32) || defined(_WIN64)
+			err = mkdir(TC_DIR);
+		#else
+			err = mkdir(TC_DIR, 0700);
+		#endif
+		if (err)
+			return -1;
+	}
+
+	set_tc_folder_dir(TC_DIR "/compress_data_parallel");
+	if (rdcu_compress_data_parallel(cfg, last_info))
+		return -1;
+
+	return 0;
+}
diff --git a/lib/rdcu_rmap.c b/lib/rdcu_rmap.c
new file mode 100644
index 0000000..e25241c
--- /dev/null
+++ b/lib/rdcu_rmap.c
@@ -0,0 +1,822 @@
+/**
+ * @file   rdcu_rmap.c
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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 RMAP RDCU link interface
+ * @see FPGA Requirement Specification PLATO-IWF-PL-RS-005 Issue 0.7
+ *
+ *
+ * Ideally, we would use asynchronous operations here, with a transaction log
+ * that is served by another thread. However, we cannot assume that such
+ * features will be available, so we'll do this by maintaining a mirror of the
+ * RDCU's registers and memory, where instead of actively blocking with get()
+ * and set() RMAP calls, they operate on the local copy and the user issues
+ * sync() calls.
+ *
+ * To monitor the syncronisation status, we maintaining a transaction log
+ * tracking the submitted command set. Response packets could be processed
+ * by interrupt (or thread), but in this variant, we process the return packets
+ * when the user calls rdcu_ctrl_sync_status()
+ *
+ * This is probably the nicest solution when it comes to call overhead, but it
+ * requires 8 MiB of memory for the SRAM mirror and the some for the registers.
+ *
+ * Note that for simplicity , we assume that there is a working heap allocator
+ * available, please adapt all malloc/free calls to your needs, or ask us
+ * to do that for you.
+ *
+ * NOTE: in order to run this on the GR712RC eval board, we set the SRAM mirror
+ *	 image to the boards SDRAM in rdcu_ctrl_init() and just malloc() it for
+ *	 the PC (see rdcu_ctrl_init)
+ *
+ *	 The interface requires that you provide an RX and a TX function,
+ *	 see rdcu_ctrl_init for the call interface.
+ *	 The TX function shall to return 0 on success, everything else
+ *	 is considered an error in submission. The RX function shall return
+ *	 the size of the packet buffer and accept NULL as call argument, on
+ *	 which it shall return the buffer size required to store the next
+ *	 pending packet.
+ *	 You can use these functions to adapt the actual backend, i.e. use
+ *	 your particular SpW interface or just redirect RX/TX to files
+ *	 or via a network connection.
+ *
+ * NOTE: We don't have to serve more than one RDCU at any given time, so we
+ *	 track addresses and paths internally in a single instance. This also
+ *	 makes the interface less cluttered. Besides, I'm lazy.
+ *
+ *
+ * @warn when operational, we expect to have exclusive control of the SpW link
+ *
+ * TODO: RMAP command response evaluation
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <byteorder.h>
+#include <rmap.h>
+#include <rdcu_rmap.h>
+
+
+
+static uint8_t rdcu_addr;
+static uint8_t icu_addr;
+
+static uint8_t *dpath;	/* destination path (to the RDCU) */
+static uint8_t *rpath;	/* return path (to the ICU) */
+static uint8_t dpath_len;
+static uint8_t rpath_len;
+
+static uint8_t dst_key;	/* destination command key */
+
+
+
+
+ /* generic calls, functions must be provided to init() */
+static int32_t (*rmap_tx)(const void *hdr,  uint32_t hdr_size,
+			  const uint8_t non_crc_bytes,
+			  const void *data, uint32_t data_size);
+static uint32_t (*rmap_rx)(uint8_t *pkt);
+
+static size_t data_mtu;	/* maximum data transfer size per unit */
+
+
+
+
+
+
+
+
+
+
+/* For now we maintain a simple transaction log that works like this:
+ * we allow up to 128 transfers, simply because this is how many response
+ * packets the GRSPW2 SpW descriptor table can hold at any one time without
+ * blocking the link.
+ *
+ * Every time a new transfer is to be submitted, we grab the first free
+ * slot we encounter in the "in_use" array and use the index as the transaction
+ * identifier of the RMAP packet. (Yes, this is potentially slow, as we may have
+ * to iterate over the whole array every time if we're very busy with
+ * transmissions, so there is room for improvement.)
+ *
+ * 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.
+ *
+ * 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
+ * data if we issue an RMAP_read command. This may be omitted for write
+ * commands.
+ *
+ * Every time a response packet is received, the data (if any) is written to the
+ * local address, using the length specified by RMAP packet, so be careful where
+ * you place your buffers or registers. On success, the "in_use" slot is cleared
+ * and the pending counter is improved.
+ *
+ * XXX: careful, no locking is used on any of the log data, so this is
+ * single-thread-use only!
+ *
+ */
+/* #define TRANS_LOG_SIZE 64	/1* GRSPW2 TX descriptor limit *1/ */
+#define TRANS_LOG_SIZE 64000	/* increased because there are no response packets during packet generation */
+static struct {
+
+	uint8_t  in_use[TRANS_LOG_SIZE];
+	void    *local_addr[TRANS_LOG_SIZE];
+
+	int pending;
+} trans_log;
+
+
+/**
+ * @brief grab a slot in the transaction log
+ *
+ * @param local_addr the local memory address
+ *
+ * @returns -1 on no slots, >= 0 for the transaction id
+ */
+
+static int trans_log_grab_slot(void *local_addr)
+{
+	int i;
+	int slot = -1;
+
+	for (i = 0; i < TRANS_LOG_SIZE; i++) {
+
+		if (trans_log.in_use[i])
+			continue;
+
+		/* got one */
+		slot = i;
+		trans_log.in_use[slot] = 1;
+		trans_log.local_addr[slot] = local_addr;
+		trans_log.pending++;
+		break;
+	}
+
+	return slot;
+}
+
+
+/**
+ * @brief release a slot in the transaction log
+ *
+ * @param slot the id of the slot
+ *
+ */
+
+static void trans_log_release_slot(int slot)
+{
+
+	if (slot < 0)
+		return;
+
+	if (slot >= TRANS_LOG_SIZE)
+		return;
+
+	if (!trans_log.in_use[slot])
+		return;
+
+	trans_log.in_use[slot] = 0;
+	trans_log.pending--;
+}
+
+
+/**
+ * @brief get the local address for a slot
+ *
+ * @param slot the id of the slot
+ *
+ * @returns the address or NULL if not found/slot not in use
+ */
+
+static void *trans_log_get_addr(int slot)
+{
+	if (slot < 0)
+		return NULL;
+
+	if (slot >= TRANS_LOG_SIZE)
+		return NULL;
+
+	if (!trans_log.in_use[slot])
+		return NULL;
+
+	return trans_log.local_addr[slot];
+}
+
+/**
+ * @brief n rmap command transaction
+ *
+ * @returns number of packets processed or < 0 on error
+ */
+
+static int rdcu_process_rx(void)
+{
+	int n;
+	int cnt = 0;
+
+	uint32_t *local_addr;
+
+	uint8_t *spw_pckt;
+
+	struct rmap_pkt *rp;
+
+
+	if (!rmap_rx)
+		return -1;
+
+	/* process all pending responses */
+	while ((n = rmap_rx(NULL))) {
+		/* we received something, allocate enough space for the packet */
+		spw_pckt = (uint8_t *) malloc(n);
+		if (!spw_pckt) {
+			printf("malloc() for packet failed!\n");
+			return -1;
+		}
+
+		/* read the packet */
+		n = rmap_rx(spw_pckt);
+
+		if (!n) {
+			printf("Unknown error in rmap_rx()\n");
+			free(spw_pckt);
+			return -1;
+		}
+
+		cnt++;
+
+		if (0)
+			rmap_parse_pkt(spw_pckt);
+
+		/* convert format */
+		rp = rmap_pkt_from_buffer(spw_pckt, n);
+		free(spw_pckt);
+
+		if (!rp) {
+			printf("Error converting to RMAP packet\n");
+			continue;
+		}
+
+		local_addr = trans_log_get_addr(rp->tr_id);
+
+		if (!local_addr) {
+			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");
+
+			trans_log_release_slot(rp->tr_id);
+			rmap_erase_packet(rp);
+			return -1;
+		}
+
+
+		if (rp->data_len) {
+
+			uint8_t crc8;
+
+			/* convert endianess if needed */
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+			{
+				unsigned int i;
+				uint32_t *p = (uint32_t *) rp->data;
+
+				for (i = 0; i < (rp->data_len / 4); i++)
+					be32_to_cpus(&p[i]);
+			}
+#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");
+
+				trans_log_release_slot(rp->tr_id);
+				rmap_erase_packet(rp);
+				return -1;
+			}
+
+			memcpy(local_addr, rp->data, rp->data_len);
+		}
+
+
+		trans_log_release_slot(rp->tr_id);
+		rmap_erase_packet(rp);
+	}
+
+	return cnt;
+}
+
+
+/**
+ * @brief submit an rmap command transaction
+ *
+ * @param cmd the rmap command
+ * @param cmd_size the size of the rmap command
+ * @param data the payload (may be NULL)
+ * @param data_size the size of the payload
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_submit_tx(const uint8_t *cmd,  int cmd_size,
+		   const uint8_t *data, int data_size)
+{
+	/* try to process pending responses */
+	rdcu_process_rx();
+
+	if (!rmap_tx)
+		return -1;
+
+	if (0)
+		printf("Transmitting RMAP command\n");
+
+	if (rmap_tx(cmd, cmd_size, dpath_len, data, data_size)) {
+		printf("rmap_tx() returned error!\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * @brief generate an rmap command packet
+ *
+ * @param trans_id a transaction identifier
+ *
+ * @param cmd the command buffer; if NULL, the function returns the needed size
+ *
+ * @param rmap_cmd_type the rmap command type of the packet
+ *
+ * @param addr the address to read from or write to
+ *
+ * @param size the number of bytes to read or write
+ *
+ * @returns the size of the command data buffer or 0 on error
+ */
+
+int rdcu_gen_cmd(uint16_t trans_id, uint8_t *cmd,
+		 uint8_t rmap_cmd_type,
+		 uint32_t addr, uint32_t size)
+{
+	int n;
+
+	struct rmap_pkt *pkt;
+
+	pkt = rmap_create_packet();
+	if (!pkt) {
+		printf("Error creating packet\n");
+		return 0;
+	}
+
+	rmap_set_dst(pkt, rdcu_addr);
+	rmap_set_src(pkt, icu_addr);
+	rmap_set_dest_path(pkt, dpath, dpath_len);
+	rmap_set_reply_path(pkt, rpath, rpath_len);
+	rmap_set_key(pkt, dst_key);
+	rmap_set_cmd(pkt, rmap_cmd_type);
+	rmap_set_tr_id(pkt, trans_id);
+	rmap_set_data_addr(pkt, addr);
+	rmap_set_data_len(pkt, size);
+
+	/* determine header size */
+	n = rmap_build_hdr(pkt, NULL);
+
+	if (!cmd) {
+		rmap_erase_packet(pkt);
+		return n;
+	}
+
+	memset(cmd, 0, n);
+
+	n = rmap_build_hdr(pkt, cmd);
+
+	rmap_erase_packet(pkt);
+
+	return n;
+}
+
+
+
+
+
+/**
+ * @brief submit a sync command
+ *
+ * @param fn the RDCU command generation function
+ * @param addr the local address of the corresponding remote address
+ * @param data_len the length of the data payload (0 for read commands)
+ *
+ * @note data_len must be a multiple of 4
+ * @note all data is treated (and byte swapped) as 32 bit words
+ *
+ * @return 0 on success, otherwise error
+ */
+
+
+int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd),
+	      void *addr, int data_len)
+{
+	int n;
+	int slot;
+
+	uint8_t *rmap_cmd;
+
+
+	if (data_len & 0x3)
+		return -1;
+
+	slot = trans_log_grab_slot(addr);
+	if (slot < 0)
+		return -1;
+
+
+	/* determine size of command */
+	n = fn(slot, NULL);
+
+	rmap_cmd = (uint8_t *) malloc(n);
+	if (!rmap_cmd) {
+		printf("Error allocating rmap cmd");
+		return -1;
+	}
+
+	/* now fill actual command */
+	n = fn(slot, rmap_cmd);
+	if (!n) {
+		printf("Error creating command packet\n");
+		free(rmap_cmd);
+		return -1;
+	}
+
+	/* convert endianess if needed */
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+	if (data_len)
+	{
+		int i;
+		uint32_t *tmp_buf = alloca(data_len);
+		uint32_t *p = (uint32_t *) addr;
+
+		for (i = 0; i < (data_len / 4); i++)
+			tmp_buf[i] = cpu_to_be32(p[i]);
+
+		addr = tmp_buf;
+	}
+#endif /* __BYTE_ORDER__ */
+
+	n = rdcu_submit_tx(rmap_cmd, n, addr, data_len);
+	free(rmap_cmd);
+
+	return n;
+}
+
+
+
+/**
+ * @brief submit a data sync command
+ *
+ * @param fn a 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
+ * @param read 0: write, otherwise read
+ *
+ * @return 0 on success, < 0: error, > 0: retry
+ *
+ * @note this one is a little redundant, but otherwise we'd have a lot of
+ *	 unused parameters on most of the control functions
+ *
+ * XXX need a paramter for read...meh...must think of something else
+ */
+
+
+int rdcu_sync_data(int (*fn)(uint16_t trans_id, uint8_t *cmd,
+			     uint32_t addr, uint32_t data_len),
+		   uint32_t addr, void *data, uint32_t data_len, int read)
+{
+	int n;
+	int slot;
+
+	uint8_t *rmap_cmd;
+
+
+
+	rdcu_process_rx();
+
+	slot = trans_log_grab_slot(data);
+	if (slot < 0) {
+		if (0)
+		printf("Error: all slots busy!\n");
+		return 1;
+	}
+
+
+	/* determine size of command */
+	n = fn(slot, NULL, addr, data_len);
+
+	rmap_cmd = (uint8_t *) malloc(n);
+	if (!rmap_cmd) {
+		printf("Error allocating rmap cmd");
+		return -1;
+	}
+
+	/* now fill actual command */
+	n = fn(slot, rmap_cmd, addr, data_len);
+	if (!n) {
+		printf("Error creating command packet\n");
+		free(rmap_cmd);
+		return -1;
+	}
+
+	if (read)
+		n = rdcu_submit_tx(rmap_cmd, n, NULL, 0);
+	else
+		n = rdcu_submit_tx(rmap_cmd, n, data, data_len);
+
+	free(rmap_cmd);
+
+	return n;
+}
+
+
+
+/**
+ * @brief create a complete package from header and payload data including CRC8
+ *
+ * @note this is a helper function to generate complete binary RMAP packet dumps
+ *
+ * @param blob the blob buffer; if NULL, the function returns the needed size
+ *
+ * @param[in]  cmd an rmap command buffer
+ * @param[in]  cmd_size the size of the rmap command buffer
+ * @param[in]  non_crc_bytes leading bytes in the header not path of the CRC
+ * @param[in]  data a data buffer (may be NULL)
+ * @param[in]  data_size the size of the data buffer (ignored if data is NULL)
+ *
+ * @note data_size must be a multiple of 4
+ * @note this function will convert all data to big endian as 32 bit words
+ *
+ * @returns the size of the blob or 0 on error
+ */
+
+int rdcu_package(uint8_t *blob,
+		 const uint8_t *cmd,  uint32_t cmd_size,
+		 const uint8_t non_crc_bytes,
+		 const uint8_t *data, uint32_t data_size)
+{
+	int n;
+	int has_data_crc = 0;
+	struct rmap_instruction *ri;
+
+
+	if (data_size & 0x3)	/* must be multiple of 4 */
+		return -1;
+
+	if (!cmd_size) {
+		blob = NULL;
+		return 0;
+	}
+
+
+	/* allocate space for header, header crc, data, data crc */
+	n = cmd_size + 1;
+
+	ri = (struct rmap_instruction *) &cmd[non_crc_bytes + RMAP_INSTRUCTION];
+
+	/* see if the type of command needs a data crc field at the end */
+		switch (ri->cmd) {
+	case RMAP_READ_MODIFY_WRITE_ADDR_INC:
+	case RMAP_WRITE_ADDR_SINGLE:
+	case RMAP_WRITE_ADDR_INC:
+	case RMAP_WRITE_ADDR_SINGLE_VERIFY:
+	case RMAP_WRITE_ADDR_INC_VERIFY:
+	case RMAP_WRITE_ADDR_SINGLE_VERIFY_REPLY:
+	case RMAP_WRITE_ADDR_INC_VERIFY_REPLY:
+	case RMAP_WRITE_ADDR_INC_REPLY:
+			has_data_crc = 1;
+			n += 1;
+			break;
+		default:
+			break;
+		}
+
+
+	if (data)
+		n += data_size;
+
+	if (!blob)
+		return n;
+
+
+	memcpy(&blob[0], cmd, cmd_size);
+
+	blob[cmd_size] = rmap_crc8(&cmd[non_crc_bytes],
+				   cmd_size - non_crc_bytes);
+
+	if (data) {
+		memcpy(&blob[cmd_size + 1], data, data_size);
+		blob[cmd_size + 1 + data_size] = rmap_crc8(&blob[cmd_size + 1], data_size);
+	} else {
+		/* if no data is present, data crc is 0x0 */
+		if (has_data_crc)
+			blob[cmd_size + 1] = 0x0;
+	}
+
+
+	return n;
+}
+
+
+/**
+ * @brief sets the logical address of the RDCU
+ * @param addr the address
+ */
+
+void rdcu_set_destination_logical_address(uint8_t addr)
+{
+	rdcu_addr = addr;
+}
+
+/**
+ * @brief sets the logical address of the ICU
+ * @param addr the address
+ */
+
+void rdcu_set_source_logical_address(uint8_t addr)
+{
+	icu_addr = addr;
+}
+
+
+/**
+ * @brief set the destination path to the RDCU
+ * @param path a byte array containing the path (may be NULL)
+ * @param len the number of elements in the array
+ *
+ * @returns 0 on success, otherwise error
+ *
+ * @note the path array is taken as a reference, make sure to keep it around
+ *	 the maximum length of the path is 15 elements
+ *	 setting either path NULL or len 0 disables destination path addressing
+ */
+
+int rdcu_set_destination_path(uint8_t *path, uint8_t len)
+{
+	if (len > RMAP_MAX_PATH_LEN)
+		return -1;
+
+	if (!path || !len) {
+		dpath     = NULL;
+		dpath_len = 0;
+		return 0;
+	}
+
+	dpath     = path;
+	dpath_len = len;
+
+	return 0;
+}
+
+
+/**
+ * @brief set the return path to the ICU
+ * @param path a byte array containing the path (may be NULL)
+ * @param len the number of elements in the array
+ *
+ * @returns 0 on success, otherwise error
+ *
+ * @note the path array is taken as a reference, make sure to keep it around
+ *	 the maximum length of the path is 12 elements
+ *	 the number of elements must be a multiple of 4 (due to RMAP protocol)
+ *	 setting either path NULL or len 0 disables return path addressing
+ */
+
+int rdcu_set_return_path(uint8_t *path, uint8_t len)
+{
+	if (len > RMAP_MAX_REPLY_PATH_LEN)
+		return -1;
+
+	if (len & 0x3)
+		return -1;	/* not a multiple of 4 */
+
+	if (!path || !len) {
+		rpath     = NULL;
+		rpath_len = 0;
+		return 0;
+	}
+
+	rpath     = path;
+	rpath_len = len;
+
+	return 0;
+}
+
+
+/**
+ * @brief set the destination command key to use
+ *
+ * @param key the destination key
+ */
+
+void rdcu_set_destination_key(uint8_t key)
+{
+	dst_key = key;
+}
+
+
+/**
+ * @brief get the configured data MTU
+ *
+ * @returns the mtu
+ */
+
+size_t rdcu_get_data_mtu(void)
+{
+	return data_mtu;
+}
+
+
+/**
+ * @brief get the RDCU <-> ICU mirror RMAP synchronisation status
+ *
+ * @returns 0: synchronised, > 0: operations pending
+ */
+
+int rdcu_rmap_sync_status(void)
+{
+	/* try to process pending responses */
+	rdcu_process_rx();
+
+	return trans_log.pending;
+}
+
+
+/**
+ * @brief reset all entries in the RMAP transaction log
+ */
+
+void rdcu_rmap_reset_log(void)
+{
+	memset(trans_log.in_use, 0, TRANS_LOG_SIZE);
+	trans_log.pending = 0;
+}
+
+
+/**
+ * @brief initialise the rdcu control library
+ *
+ * @param mtu the maximum data transfer size per unit
+ *
+ * @param rmap_tx a function pointer to transmit an rmap command
+ * @param rmap_rx function pointer to receive an rmap command
+ *
+ * @note rmap_tx is expected to return 0 on success
+ *	 rmap_rx is expected to return the number of packet bytes
+ *
+ * @returns 0 on success, otherwise error
+ */
+
+int rdcu_rmap_init(size_t mtu,
+		   int32_t (*tx)(const void *hdr,  uint32_t hdr_size,
+				 const uint8_t non_crc_bytes,
+				 const void *data, uint32_t data_size),
+		   uint32_t (*rx)(uint8_t *pkt))
+{
+	if (!tx)
+		return -1;
+
+	if (!rx)
+		return -1;
+
+	rmap_tx = tx;
+	rmap_rx = rx;
+
+	data_mtu = mtu;
+
+	return 0;
+}
diff --git a/lib/rmap.c b/lib/rmap.c
new file mode 100644
index 0000000..908b622
--- /dev/null
+++ b/lib/rmap.c
@@ -0,0 +1,778 @@
+/**
+ * @file   rmap.c
+ * @author Armin Luntzer (armin.luntzer@univie.ac.at),
+ * @date   2018
+ *
+ * @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 rmap command/reply helper functions
+ *
+ * @note the extended address byte is always set to 0x0
+ */
+
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rmap.h>
+
+
+
+
+
+/**
+ * @brief valiidates a command code
+ *
+ * @param cmd the command code
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int rmap_validate_cmd_code(uint8_t cmd)
+{
+	switch (cmd) {
+	case RMAP_READ_ADDR_SINGLE:
+	case RMAP_READ_ADDR_INC:
+	case RMAP_READ_MODIFY_WRITE_ADDR_INC:
+	case RMAP_WRITE_ADDR_SINGLE:
+	case RMAP_WRITE_ADDR_INC:
+	case RMAP_WRITE_ADDR_SINGLE_REPLY:
+	case RMAP_WRITE_ADDR_INC_REPLY:
+	case RMAP_WRITE_ADDR_SINGLE_VERIFY:
+	case RMAP_WRITE_ADDR_INC_VERIFY:
+	case RMAP_WRITE_ADDR_SINGLE_VERIFY_REPLY:
+	case RMAP_WRITE_ADDR_INC_VERIFY_REPLY:
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+
+/**
+ * @brief get the minimum header size given the RMAP instruction
+ *
+ * @param pkt a struct rmap_pkt
+ *
+ * @returns header size or -1 on error
+ */
+
+static int rmap_get_min_hdr_size(struct rmap_pkt *pkt)
+{
+
+
+	switch (pkt->ri.cmd) {
+	case RMAP_READ_ADDR_SINGLE:
+	case RMAP_READ_ADDR_INC:
+	case RMAP_READ_MODIFY_WRITE_ADDR_INC:
+
+		if (pkt->ri.cmd_resp)
+			return RMAP_HDR_MIN_SIZE_READ_CMD;
+
+		return RMAP_HDR_MIN_SIZE_READ_REP;
+
+	case RMAP_WRITE_ADDR_SINGLE:
+	case RMAP_WRITE_ADDR_INC:
+	case RMAP_WRITE_ADDR_SINGLE_REPLY:
+	case RMAP_WRITE_ADDR_INC_REPLY:
+	case RMAP_WRITE_ADDR_SINGLE_VERIFY:
+	case RMAP_WRITE_ADDR_INC_VERIFY:
+	case RMAP_WRITE_ADDR_SINGLE_VERIFY_REPLY:
+	case RMAP_WRITE_ADDR_INC_VERIFY_REPLY:
+
+		if (pkt->ri.cmd_resp)
+			return RMAP_HDR_MIN_SIZE_WRITE_CMD;
+
+		return RMAP_HDR_MIN_SIZE_WRITE_REP;
+
+	default:
+		return -1;
+	}
+}
+
+/**
+ * @brief calculate the CRC8 of a given buffer
+ *
+ * @param buf the buffer containing the data
+ * @param len the length of the buffer
+ *
+ * @returns the CRC8
+ */
+
+uint8_t rmap_crc8(const uint8_t *buf, const size_t len)
+{
+	size_t i;
+
+	uint8_t crc8 = 0;
+
+	/* crc8 lookup table from ECSS‐E‐ST‐50‐52C A.3 */
+	const uint8_t crc8_lt[256] = {
+		0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
+		0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
+		0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
+		0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
+		0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
+		0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
+		0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
+		0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
+		0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
+		0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
+		0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
+		0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
+		0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
+		0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
+		0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
+		0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
+		0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
+		0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
+		0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
+		0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
+		0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
+		0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
+		0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
+		0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
+		0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
+		0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
+		0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
+		0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
+		0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
+		0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
+		0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
+		0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf,
+	};
+
+
+
+	if (!buf)
+		return 0;
+
+
+	for (i = 0; i < len; i++)
+		crc8 = crc8_lt[crc8 ^ buf[i]];
+
+	return crc8;
+}
+
+
+/**
+ * @brief create an RMAP packet and set defaults
+ *
+ *
+ * @note initialises protocol id to 1 and all others to 0
+ *
+ * @returns a struct rmap_pkt or NULL on error
+ */
+
+struct rmap_pkt *rmap_create_packet(void)
+{
+	struct rmap_pkt *pkt;
+
+
+	pkt = (struct rmap_pkt *) calloc(sizeof(struct rmap_pkt), 1);
+	if (pkt)
+		pkt->proto_id = RMAP_PROTOCOL_ID;
+
+	return pkt;
+}
+
+
+/**
+ * @brief destroys an RMAP packet
+ *
+ * @param pkt a struct rmap_pkt
+ *
+ * @note this will NOT deallocate and pointer references assigned by the user
+ */
+
+void rmap_destroy_packet(struct rmap_pkt *pkt)
+{
+	free(pkt);
+}
+
+
+/**
+ * @brief completely destroys an RMAP packet
+ *
+ * @param pkt a struct rmap_pkt
+ *
+ * @note this will attempt to deallocate any pointer references assigned by the
+ * 	 user
+ * @warning use with care
+ */
+
+void rmap_erase_packet(struct rmap_pkt *pkt)
+{
+	free(pkt->path);
+	free(pkt->rpath);
+	free(pkt->data);
+	free(pkt);
+}
+
+/**
+ * @brief set the destination (target) logical address
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param addr	the destination logical address
+ */
+
+void rmap_set_dst(struct rmap_pkt *pkt, uint8_t addr)
+{
+	if (pkt)
+		pkt->dst = addr;
+}
+
+
+/**
+ * @brief set the source (initiator) logical address
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param addr	the source logical address
+ */
+
+void rmap_set_src(struct rmap_pkt *pkt, uint8_t addr)
+{
+	if (pkt)
+		pkt->src = addr;
+}
+
+
+/**
+ * @brief set the command authorisation key
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param key	the authorisation key
+ */
+
+void rmap_set_key(struct rmap_pkt *pkt, uint8_t key)
+{
+	if (pkt)
+		pkt->key = key;
+}
+
+
+/**
+ * @brief set the reply address path
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param rpath the reply path
+ * @param len   the number of elements in the reply path (multiple of 4)
+ *
+ * @note see ECSS‐E‐ST‐50‐52C 5.1.6 for return path rules
+ *
+ * @returns 0 on success, -1 on error
+ */
+
+int rmap_set_reply_path(struct rmap_pkt *pkt, const uint8_t *rpath, uint8_t len)
+{
+	if (!pkt)
+		return -1;
+
+	if (!rpath && len)
+		return -1;
+
+	if (len > RMAP_MAX_REPLY_PATH_LEN)
+		return -1;
+
+	if (len & 0x3)
+		return -1;
+
+	pkt->rpath_len = len;
+
+	pkt->rpath = (uint8_t *) malloc(pkt->rpath_len);
+	if (!pkt->rpath)
+		return -1;
+
+	memcpy(pkt->rpath, rpath, pkt->rpath_len);
+
+	/* number of 32 bit words needed to contain the path */
+	pkt->ri.reply_addr_len = len >> 2;
+
+	return 0;
+}
+
+
+/**
+ * @brief set the destination address path
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param path the destination path
+ * @param len   the number of elements in the destination path
+ *
+ * @note see ECSS‐E‐ST‐50‐52C 5.1.6 for return path rules
+ *
+ * @returns 0 on success, -1 on error
+ */
+
+int rmap_set_dest_path(struct rmap_pkt *pkt, const uint8_t *path, uint8_t len)
+{
+	if (!pkt)
+		return -1;
+
+	if (!path && len)
+		return -1;
+
+	if (len > RMAP_MAX_PATH_LEN)
+		return -1;
+
+	pkt->path_len = len;
+
+	pkt->path = (uint8_t *) malloc(pkt->path_len);
+	if (!pkt->path)
+		return -1;
+
+	memcpy(pkt->path, path, pkt->path_len);
+
+	return 0;
+}
+
+
+/**
+ * @brief set an RMAP command
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param cmd	the selected command
+ *
+ * @returns -1 on error
+ */
+
+int rmap_set_cmd(struct rmap_pkt *pkt, uint8_t cmd)
+{
+	if (!pkt)
+		return -1;
+
+	if (rmap_validate_cmd_code(cmd))
+		return -1;
+
+
+	pkt->ri.cmd      = cmd & 0xF;
+	pkt->ri.cmd_resp = 1;
+
+	return 0;
+}
+
+
+/**
+ * @brief set an RMAP transaction identifier
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param id	the transaction identifier
+ */
+
+void rmap_set_tr_id(struct rmap_pkt *pkt, uint16_t id)
+{
+	if (!pkt)
+		return;
+
+	pkt->tr_id = id;
+}
+
+
+/**
+ * @brief set a data address
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param addr	the address
+ */
+
+void rmap_set_data_addr(struct rmap_pkt *pkt, uint32_t addr)
+{
+	if (!pkt)
+		return;
+
+	pkt->addr = addr;
+}
+
+/**
+ * @brief set an RMAP command
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param len	the data length (in bytes)
+ *
+ * @returns -1 on error
+ *
+ * @note the length is at most 2^24-1 bytes
+ * @note if the RMAP command is of 'SINGLE' type, only multiples of 4
+ *	 will result in successfull execution of the command (at least
+ *	 with the GRSPW2 core)
+ */
+
+int rmap_set_data_len(struct rmap_pkt *pkt, uint32_t len)
+{
+	if (!pkt)
+		return -1;
+
+	if (len > RMAP_MAX_DATA_LEN)
+		return -1;
+
+	pkt->data_len = len;
+
+	return 0;
+}
+
+
+/**
+ * @brief build an rmap header
+ *
+ * @param pkt	a struct rmap_pkt
+ * @param hdr	the header buffer; if NULL, the function returns the needed size
+ *
+ * @returns -1 on error, size of header otherwise
+ */
+
+int rmap_build_hdr(struct rmap_pkt *pkt, uint8_t *hdr)
+{
+	int i;
+	int n = 0;
+
+
+	if (!pkt)
+		return -1;
+
+	if (!hdr) {
+		n = rmap_get_min_hdr_size(pkt);
+		n += pkt->path_len;
+		n += pkt->rpath_len;
+		return n;
+	}
+
+
+	for (i = 0; i < pkt->path_len; i++)
+		hdr[n++] = pkt->path[i];	/* routing path to target */
+
+	hdr[n++] = pkt->dst;			/* target logical address */
+	hdr[n++] = pkt->proto_id;		/* protocol id */
+	hdr[n++] = pkt->instruction;		/* instruction */
+	hdr[n++] = pkt->key;			/* key/status */
+
+	for (i = 0; i < pkt->rpath_len; i++)
+		hdr[n++] = pkt->rpath[i];	/* return path to source */
+
+	hdr[n++] = pkt->src;			/* source logical address */
+	hdr[n++] = (uint8_t) (pkt->tr_id >> 8);	/* MSB of transaction id */
+	hdr[n++] = (uint8_t)  pkt->tr_id;	/* LSB of transaction id */
+
+
+	/* commands have a data address */
+	if (pkt->ri.cmd_resp) {
+		hdr[n++] = 0x0;	/* extended address field (unused) */
+		hdr[n++] = (uint8_t) (pkt->addr >> 24); /* data addr MSB */
+		hdr[n++] = (uint8_t) (pkt->addr >> 16);
+		hdr[n++] = (uint8_t) (pkt->addr >>  8);
+		hdr[n++] = (uint8_t)  pkt->addr;	/* data addr LSB */
+	} else if (!pkt->ri.cmd_resp && pkt->ri.cmd & RMAP_CMD_BIT_WRITE) {
+		/* all headers have data length unless they are a write reply */
+		return n;
+	} else {
+		hdr[n++] = 0x0;	/* on other replies, this is a reserved field */
+	}
+
+	hdr[n++] = (uint8_t) (pkt->data_len >> 16); /* data len MSB */
+	hdr[n++] = (uint8_t) (pkt->data_len >>  8);
+	hdr[n++] = (uint8_t)  pkt->data_len;	    /* data len LSB */
+
+	return n;
+}
+
+
+/**
+ * @brief create an rmap packet from a buffer
+ *
+ * @param buf the buffer, with the target path stripped away, i.e.
+ *	  starting with <logical address>, <protocol id>, ...
+ * @param len the data length of the buffer (in bytes)
+ *
+ * @returns an rmap packet, containing the decoded buffer including any data,
+ *	    NULL on error
+ */
+
+struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len)
+{
+	size_t n = 0;
+	size_t i;
+	int min_hdr_size;
+
+	struct rmap_pkt *pkt = NULL;
+
+
+	if (!buf)
+		goto error;
+
+	if (len < RMAP_HDR_MIN_SIZE_WRITE_REP) {
+		printf("buffer len is smaller than the smallest RMAP packet\n");
+		goto error;
+	}
+
+	if (buf[RMAP_PROTOCOL_ID] != RMAP_PROTOCOL_ID) {
+		printf("Not an RMAP packet, got %x but expected %x\n",
+		       buf[RMAP_PROTOCOL_ID], RMAP_PROTOCOL_ID);
+		goto error;
+	}
+
+	pkt = rmap_create_packet();
+	if (!pkt) {
+		printf("Error creating packet\n");
+		goto error;
+	}
+
+	pkt->dst         = buf[RMAP_DEST_ADDRESS];
+	pkt->proto_id    = buf[RMAP_PROTOCOL_ID];
+	pkt->instruction = buf[RMAP_INSTRUCTION];
+	pkt->key         = buf[RMAP_CMD_DESTKEY];
+
+	min_hdr_size = rmap_get_min_hdr_size(pkt);
+	if (min_hdr_size < 0)
+		goto error;
+
+	if (len < (uint32_t)min_hdr_size) {
+		printf("buffer len is smaller than the contained RMAP packet\n");
+		goto error;
+	}
+
+
+	if (pkt->ri.cmd_resp) {
+		pkt->rpath_len = pkt->ri.reply_addr_len << 2;
+		if (len < (uint32_t)min_hdr_size + pkt->rpath_len) {
+			printf("buffer is smaller than the contained RMAP packet\n");
+			goto error;
+		}
+
+		pkt->rpath = (uint8_t *) malloc(pkt->rpath_len);
+		if (!pkt->rpath)
+			goto error;
+
+		for (i = 0; i < pkt->rpath_len; i++)
+			pkt->rpath[i] = buf[RMAP_REPLY_ADDR_START + i];
+
+		n = pkt->rpath_len; /* rpath skip */
+	}
+
+	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];
+
+	/* commands have a data address */
+	if (pkt->ri.cmd_resp) {
+		pkt->addr = ((uint32_t) buf[RMAP_ADDR_BYTE0 + n] << 24) |
+			    ((uint32_t) buf[RMAP_ADDR_BYTE1 + n] << 16) |
+			    ((uint32_t) buf[RMAP_ADDR_BYTE2 + n] <<  8) |
+			     (uint32_t) buf[RMAP_ADDR_BYTE3 + n];
+		n += 4; /* addr skip, extended byte is incorporated in define */
+	}
+
+	/* 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];
+	}
+
+	pkt->hdr_crc  = buf[RMAP_HEADER_CRC];
+
+	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: %lu bytes needed\n",
+				len , RMAP_DATA_START + n + pkt->data_len);
+			goto error;
+		}
+		if (len > RMAP_DATA_START + n + pkt->data_len + 1)  /* +1 for data CRC */
+			printf("warning: the buffer is larger than the included RMAP packet\n");
+
+		pkt->data = (uint8_t *) malloc(pkt->data_len);
+		if (!pkt->data)
+			goto error;
+
+		for (i = 0; i < pkt->data_len; i++)
+			pkt->data[i] = buf[RMAP_DATA_START + n + i];
+
+		/* final byte is data crc */
+		pkt->data_crc = buf[RMAP_DATA_START + n + i];
+	}
+
+
+	return pkt;
+
+error:
+	if (pkt) {
+		free(pkt->data);
+		free(pkt->rpath);
+		free(pkt);
+	}
+
+	return NULL;
+}
+
+
+
+/**** UNFINISHED INFO STUFF BELOW ******/
+
+__extension__
+static int rmap_check_status(uint8_t status)
+{
+
+
+	printf("\tStatus: ");
+
+	switch (status) {
+	case RMAP_STATUS_SUCCESS:
+		printf("Command executed successfully");
+		break;
+	case RMAP_STATUS_GENERAL_ERROR:
+		printf("General error code");
+		break;
+	case RMAP_STATUS_UNUSED_TYPE_OR_CODE:
+		printf("Unused RMAP Packet Type or Command Code");
+		break;
+	case RMAP_STATUS_INVALID_KEY:
+		printf("Invalid key");
+		break;
+	case RMAP_STATUS_INVALID_DATA_CRC:
+		printf("Invalid Data CRC");
+		break;
+	case RMAP_STATUS_EARLY_EOP:
+		printf("Early EOP");
+		break;
+	case RMAP_STATUS_TOO_MUCH_DATA:
+		printf("Too much data");
+		break;
+	case RMAP_STATUS_EEP:
+		printf("EEP");
+		break;
+	case RMAP_STATUS_RESERVED:
+		printf("Reserved");
+		break;
+	case RMAP_STATUS_VERIFY_BUFFER_OVERRRUN:
+		printf("Verify buffer overrrun");
+		break;
+	case RMAP_STATUS_CMD_NOT_IMPL_OR_AUTH:
+		printf("RMAP Command not implemented or not authorised");
+		break;
+	case RMAP_STATUS_RMW_DATA_LEN_ERROR:
+		printf("RMW Data Length error");
+		break;
+	case RMAP_STATUS_INVALID_TARGET_LOGICAL_ADDR:
+		printf("Invalid Target Logical Address");
+		break;
+	default:
+		printf("Reserved unused error code %d", status);
+		break;
+	}
+
+	printf("\n");
+
+
+	return status;
+}
+
+
+
+static void rmap_process_read_reply(uint8_t *pkt)
+{
+	uint32_t i;
+
+	uint32_t len = 0;
+
+
+	len |= ((uint32_t) pkt[RMAP_DATALEN_BYTE0]) << 16;
+	len |= ((uint32_t) pkt[RMAP_DATALEN_BYTE1]) <<  8;
+	len |= ((uint32_t) pkt[RMAP_DATALEN_BYTE2]) <<  0;
+
+#if (__sparc__)
+	printf("\tData length is %lu bytes:\n\t", len);
+#else
+	printf("\tData length is %u bytes:\n\t", len);
+#endif
+
+
+	for (i = 0; i < len; i++)
+		printf("%02x:", pkt[RMAP_DATA_START + i]);
+
+	printf("\b \n");
+}
+
+
+
+
+static void rmap_parse_cmd_pkt(uint8_t *pkt)
+{
+	(void) pkt;
+	printf("\trmap_parse_cmd_pkt() not implemented\n");
+}
+
+
+static void rmap_parse_reply_pkt(uint8_t *pkt)
+{
+	struct rmap_instruction *ri;
+
+
+	ri = (struct rmap_instruction *) &pkt[RMAP_INSTRUCTION];
+
+	printf("\tInstruction: ");
+
+	switch (ri->cmd) {
+
+	case RMAP_READ_ADDR_SINGLE:
+		printf("Read single address\n");
+		rmap_process_read_reply(pkt);
+		break;
+	case RMAP_READ_ADDR_INC:
+		printf("Read incrementing address\n");
+		rmap_process_read_reply(pkt);
+		break;
+	case RMAP_READ_MODIFY_WRITE_ADDR_INC:
+		printf("RMW incrementing address verify reply\n");
+		break;
+	case RMAP_WRITE_ADDR_INC_VERIFY_REPLY:
+		printf("Write incrementing address verify reply\n");
+		break;
+	case RMAP_WRITE_ADDR_INC_REPLY:
+		printf("Write incrementing address reply\n");
+		break;
+	default:
+		printf("decoding of instruction 0x%02X not implemented\n",
+		       ri->cmd);
+		break;
+	}
+}
+
+
+/**
+ * parse an RMAP packet:
+ *
+ * expected format: <logical address> <protocol id> ...
+ */
+
+void rmap_parse_pkt(uint8_t *pkt)
+{
+	struct rmap_instruction *ri;
+
+	if (pkt[RMAP_PROTOCOL_ID] != RMAP_PROTOCOL_ID) {
+		printf("\nNot an RMAP packet, got %x but expected %x\n",
+		       pkt[RMAP_PROTOCOL_ID], RMAP_PROTOCOL_ID);
+		return;
+	}
+
+
+	ri = (struct rmap_instruction *) &pkt[RMAP_INSTRUCTION];
+
+	if (ri->cmd_resp) {
+		printf("This is a command packet\n");
+		if (!rmap_check_status(pkt[RMAP_REPLY_STATUS]))
+			rmap_parse_cmd_pkt(pkt);
+	} else {
+		printf("This is a reply packet\n");
+		if (!rmap_check_status(pkt[RMAP_REPLY_STATUS]))
+			rmap_parse_reply_pkt(pkt);
+	}
+}
+
diff --git a/lib/tool_lib.c b/lib/tool_lib.c
new file mode 100644
index 0000000..5318366
--- /dev/null
+++ b/lib/tool_lib.c
@@ -0,0 +1,1206 @@
+/**
+ * @file   tool_lib.c
+ * @author Johannes Seelig (johannes.seelig@univie.ac.at)
+ * @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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include "../include/tool_lib.h"
+#include "../include/cmp_support.h"
+#include "../include/rdcu_cmd.h"
+#include "../include/byteorder.h"
+
+
+/**
+ * @brief print help information
+ *
+ * @param argv	argument vector
+ */
+
+void Print_Help(const char *argv)
+{
+	printf("usage: %s [options] [<argument>]\n", &argv[0]);
+	printf("General Options:\n");
+	printf("  -h, --help               Print this help text and exit\n");
+	printf("  -V, --version            Print program version and exit\n");
+	printf("  -v, --verbose            Print various debugging information\n");
+	printf("  -n, --model_cfg          Print a default model configuration and exit\n");
+	printf("  --diff_cfg               Print a default 1d-differencing configuration and exit\n");
+	printf("  -a, --rdcu_par           Print additional RDCU control parameters\n");
+	printf("  -o <prefix>              Use the <prefix> for output files\n");
+	printf("Compression Options:\n");
+	printf("  -c <file>                File containing the compressing configuration\n");
+	printf("  -d <file>                File containing the data to be compressed\n");
+	printf("  -m <file>                File containing the model of the data to be compressed\n");
+	printf("  --rdcu_pkt               Generate RMAP packets for a RDCU compression\n");
+	printf("Decompression Options:\n");
+	printf("  -i <file>                File containing the decompression information\n");
+	printf("  -d <file>                File containing the compressed data\n");
+	printf("  -m <file>                File containing the model of the compressed data\n");
+	printf("\n");
+}
+
+
+/**
+ * @brief opens a file with a name that is a concatenation of directory and file
+ *	name.
+ *
+ * @param dirname	first sting of concatenation
+ * @param filename	security sting of concatenation
+ *
+ * @return a pointer to the opened file
+ *
+ * @see https://developers.redhat.com/blog/2018/05/24/detecting-string-truncation-with-gcc-8/
+ */
+
+static FILE *open_file(const char *dirname, const char *filename)
+{
+	FILE *fp;
+	char *pathname;
+	int n;
+
+	if (!dirname)
+		return NULL;
+
+	if(!filename)
+		return NULL;
+
+	errno = 0;
+	n = snprintf(0, 0, "%s%s", dirname, filename);
+
+	if (n < 0) {
+		perror("snprintf failed");
+		abort();
+	}
+
+	errno = 0;
+	pathname = (char *) malloc((size_t)n + 1);
+	if (!pathname) {
+		perror("malloc failed");
+		abort();
+	}
+
+	errno = 0;
+	n = snprintf(pathname, (size_t)n + 1, "%s%s", dirname, filename);
+	if (n < 0) {
+		perror("snprintf failed");
+		abort();
+	}
+
+	fp = fopen(pathname, "w");
+	free(pathname);
+	return fp;
+}
+
+
+/**
+ * @brief write a uint16_t buffer to a output file
+ *
+ * @param buf		the buffer to write a file
+ * @param buf_len	length of the buffer
+ *
+ * @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)
+{
+	uint32_t i;
+	FILE *fp;
+
+	if (!buf)
+		abort();
+
+	if (buf_len == 0)
+		return 0;
+
+	fp = open_file(output_prefix, name_extension);
+	if (fp == NULL) {
+		fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix,
+			name_extension, strerror(errno));
+		return -1;
+	}
+
+	for (i = 0; i < buf_len; i++) {
+		fprintf(fp, "%02X %02X",buf[i] >> 8 ,buf[i] & 0xFF);
+		if ((i + 1) % 16 == 0)
+			fprintf(fp, "\n");
+		else
+			fprintf(fp, " ");
+	}
+	fprintf(fp, "\n");
+
+	fclose(fp);
+
+	if (verbose) {
+		printf("\n\n");
+			for (i = 0; i < buf_len; i++) {
+				printf("%02X %02X",buf[i] >> 8 ,buf[i] & 0xFF);
+			if ((i + 1) % 16 == 0)
+				printf("\n");
+			else
+				printf(" ");
+		}
+
+		printf("\n\n");
+	}
+
+	return 0;
+}
+
+
+/**
+ * @brief write a buffer to a output file
+ *
+ * @param buf		the buffer to write a file
+ * @param buf_size	size of the buffer 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_cmp_data_file(const void *buf, uint32_t buf_size, const char
+		    *output_prefix, const char *name_extension, int verbose)
+{
+	unsigned int i;
+	FILE *fp;
+	uint8_t *p = (uint8_t *)buf;
+
+	if (!buf)
+		abort();
+
+	if (buf_size == 0)
+		return 0;
+
+	fp = open_file(output_prefix, name_extension);
+	if (fp == NULL) {
+		fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix,
+			name_extension, strerror(errno));
+		return -1;
+	}
+
+	for (i = 0; i < buf_size; i++) {
+		fprintf(fp, "%02X", p[i]);
+		if ((i + 1) % 32 == 0)
+			fprintf(fp, "\n");
+		else
+			fprintf(fp, " ");
+	}
+	fprintf(fp, "\n");
+
+	fclose(fp);
+
+	if (verbose) {
+		printf("\n\n");
+		for (i = 0; i < buf_size; i++) {
+			printf("%02X", p[i]);
+			if ((i + 1) % 32 == 0)
+				printf("\n");
+			else
+				printf(" ");
+		}
+		printf("\n\n");
+	}
+	return 0;
+}
+
+
+/**
+ * @brief remove white spaces and tabs
+ *
+ * @param s input string
+ */
+
+static void remove_spaces(char *s)
+{
+	const char *d;
+
+	if (!s)
+		return;
+
+	d = s;
+
+	do {
+		while (*d == ' ' || *d == '\t')
+			++d;
+	} while ((*s++ = *d++) != '\0');
+}
+
+
+/**
+ * @brief remove comments (starting with # or /) and \n
+ *
+ * @param s input string
+ */
+
+static void remove_comments(char *s)
+{
+	if (!s)
+		return;
+
+	while (*s) {
+		if (*s == '#' || *s == '/' || *s == '\n') {
+			*s = '\0';
+			break;
+		}
+		s++;
+	}
+
+}
+
+
+/**
+ * @brief convert RDCU SRAM Address sting to integer
+ *
+ * @param addr	string of the address
+ *
+ * @returns the value of the address, < 0 on error
+ */
+
+static int sram_addr_to_int(const char *addr)
+{
+	unsigned long i;
+	char *end = NULL;
+
+	if (addr == NULL)
+		return -1;
+
+	i = strtoul(addr, &end, 0);
+
+	if (end == addr || errno == ERANGE) {
+		printf("range error, got\n");
+		errno = 0;
+		return -1;
+	}
+
+	if (i > RDCU_SRAM_END) {
+		printf("%s: The sram address is out of the rdcu range\n",
+		       PROGRAM_NAME);
+		return -1;
+	}
+
+	if (i & 0x3) {
+		printf("The SRAM address is not 32 bit aligned\n");
+		return -1;
+	}
+
+	return (int) i;
+}
+
+
+/**
+ * @brief Interprets an uint32_t integer value in a byte string
+ *
+ * @param dep_str	description sting of the read in value
+ * @param val_str	value sting contain the value to convert in uint32_t
+ * @param red_val	address for storing the converted result
+ *
+ * @returns 0 on success, error otherwise
+ *
+ * @see https://eternallyconfuzzled.com/atoi-is-evil-c-learn-why-atoi-is-awful
+ */
+
+static int atoui32(const char *dep_str , const char *val_str, uint32_t *red_val)
+{
+	long temp;
+	char *end = NULL;
+
+	if (!dep_str)
+		return -1;
+
+	if (!val_str)
+		return -1;
+
+	if (!red_val)
+		return -1;
+
+	temp = strtol(val_str, &end, 10);
+	if (end != val_str && errno != ERANGE && temp >= 0 && temp <=
+	    UINT32_MAX) {
+		*red_val = (uint32_t)temp;
+		return 0;
+	} else {
+		fprintf(stderr, "%s: Error read in %s.\n", PROGRAM_NAME,
+			dep_str);
+		*red_val = 0;
+		return -1;
+	}
+}
+
+
+/**
+* @brief  parse a file containing a compressing configuration
+*
+* @param fp	FILE pointer
+* @param cfg	compression configuration structure holding the read in
+*		configuration
+*
+* @returns 0 on success, error otherwise
+*/
+
+static int parse_cfg(FILE *fp, struct cmp_cfg *cfg)
+{
+	char *token1, *token2;
+	char line[MAX_CONFIG_LINE];
+
+	if (!fp)
+		return -1;
+
+	if (!cfg)
+		return -1;
+
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		if (line[0] == '#' || line[0] == '\n')
+			continue; /* skip #'ed or empty lines */
+
+		if (!strchr(line, '\n')){ /* detect a to long line */
+			fprintf(stderr, "%s: Error read in line to long. Maximal line length is %d characters.\n",
+				PROGRAM_NAME, MAX_CONFIG_LINE-1);
+			return -1;
+		}
+
+		remove_comments(line);
+		remove_spaces(line);
+
+		token1 = strtok(line, "=");
+		token2 = strtok(NULL, "=");
+		if (token1 == NULL)
+			continue;
+		if (token2 == NULL)
+			continue;
+
+
+		if (!strcmp(token1, "cmp_mode")) {
+			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);
+			} else {
+				if (atoui32(token1, token2, &cfg->cmp_mode))
+					return -1;
+				continue;
+			}
+		}
+		if (!strcmp(token1, "golomb_par")) {
+			if (atoui32(token1, token2, &cfg->golomb_par))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "spill")) {
+			if (atoui32(token1, token2, &cfg->spill))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "model_value")) {
+			if (atoui32(token1, token2, &cfg->model_value))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "round")) {
+			if (atoui32(token1, token2, &cfg->round))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "ap1_golomb_par")) {
+			if (atoui32(token1, token2, &cfg->ap1_golomb_par))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "ap1_spill")) {
+			if (atoui32(token1, token2, &cfg->ap1_spill))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "ap2_golomb_par")) {
+			if (atoui32(token1, token2, &cfg->ap2_golomb_par))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "ap2_spill")) {
+			if (atoui32(token1, token2, &cfg->ap2_spill))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "rdcu_data_adr")) {
+			int i = sram_addr_to_int(token2);
+
+			if (i < 0) {
+				printf("%s: Error read in rdcu_data_adr_par\n",
+				       PROGRAM_NAME);
+				return -1;
+			}
+			cfg->rdcu_data_adr = (uint32_t)i;
+			continue;
+		}
+		if (!strcmp(token1, "rdcu_model_adr")) {
+			int i = sram_addr_to_int(token2);
+
+			if (i < 0) {
+				printf("%s: Error read in rdcu_model_adr_par\n",
+				       PROGRAM_NAME);
+				return -1;
+			}
+			cfg->rdcu_model_adr = (uint32_t)i;
+			continue;
+		}
+		if (!strcmp(token1, "rdcu_new_model_adr")) {
+			int i = sram_addr_to_int(token2);
+
+			if (i < 0) {
+				printf("%s: Error read in rdcu_new_model_adr_par\n",
+				       PROGRAM_NAME);
+				return -1;
+			}
+			cfg->rdcu_new_model_adr = (uint32_t)i;
+			continue;
+		}
+		if (!strcmp(token1, "samples")) {
+			if (atoui32(token1, token2, &cfg->samples))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "rdcu_buffer_adr")) {
+			int i = sram_addr_to_int(token2);
+
+			if (i < 0) {
+				printf("%s: Error read in rdcu_buffer_adr_par\n",
+				       PROGRAM_NAME);
+				return -1;
+			}
+			cfg->rdcu_buffer_adr = (uint32_t)i;
+			continue;
+		}
+		if (!strcmp(token1, "buffer_length")) {
+			if (atoui32(token1, token2, &cfg->buffer_length))
+				return -1;
+			continue;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * @brief reading a compressor configuration file
+ *
+ * @param file_name	file containing the compression configuration file
+ * @param cfg		compression configuration structure holding the read in
+ *			configuration
+ * @param verbose_en	print verbose output if not zero
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int read_cmp_cfg(const char *file_name, struct cmp_cfg *cfg, int verbose_en)
+{
+	FILE *fp;
+
+	if (!file_name)
+		abort();
+
+	if (!cfg)
+		abort();
+
+	if (strstr(file_name, ".info")) {
+	    fprintf(stderr, "%s: %s: .info file extension found on configuration file. You may have selected the wrong file.\n",
+		    PROGRAM_NAME, file_name);
+	}
+
+	fp = fopen(file_name, "r");
+
+	if (fp == NULL) {
+		fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name,
+			strerror(errno));
+		return -1;
+	}
+
+	if (parse_cfg(fp, cfg))
+		return -1;
+
+	fclose(fp);
+
+	if (verbose_en) {
+		printf("\n\n");
+		print_cmp_cfg(cfg);
+		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
+ *
+ * @param fp	FILE pointer
+ * @param info	decompression information structure holding the read in
+ *		information
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+static int parse_info(FILE *fp, struct cmp_info *info)
+{
+	char *token1, *token2;
+	char line[MAX_CONFIG_LINE];
+
+	if (!fp)
+		return -1;
+
+	if (!info)
+		return -1;
+
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		if (line[0] == '#' || line[0] == '\n')
+			continue; /* skip #'ed or empty lines */
+
+		if (!strchr(line, '\n')){ /* detect a to long line */
+			fprintf(stderr, "%s: Error read in line to long. Maximal line length is %d characters.\n",
+				PROGRAM_NAME, MAX_CONFIG_LINE-1);
+			return -1;
+		}
+
+		remove_comments(line);
+		remove_spaces(line);
+
+		/* Token will point to the part before the search-var. */
+		token1 = strtok(line, "=");
+		token2 = strtok(NULL, "=");
+		if (token1 == NULL)
+			continue;
+		if (token2 == NULL)
+			continue;
+
+
+		if (!strcmp(token1, "cmp_mode_used")) {
+			if (isalpha(*token2)) { /* check if mode is given as text or val*/
+				if (!strcmp(token2, "MODE_RAW")) {
+					info->cmp_mode_used = 0;
+					continue;
+				}
+				if (!strcmp(token2, "MODE_MODEL_ZERO")) {
+					info->cmp_mode_used = 1;
+					continue;
+				}
+				if (!strcmp(token2, "MODE_DIFF_ZERO")) {
+					info->cmp_mode_used = 2;
+					continue;
+				}
+				if (!strcmp(token2, "MODE_MODEL_MULTI")) {
+					info->cmp_mode_used = 3;
+					continue;
+				}
+				if (!strcmp(token2, "MODE_DIFF_MULTI")) {
+					info->cmp_mode_used = 4;
+					continue;
+				}
+				fprintf(stderr, "%s: Error read in cmp_mode_used.\n",
+					PROGRAM_NAME);
+					return -1;
+			} else {
+				uint32_t tmp;
+
+				if (atoui32(token1, token2, &tmp))
+					return -1;
+				info->cmp_mode_used = tmp;
+			}
+			continue;
+		}
+		if (!strcmp(token1, "model_value_used")) {
+			uint32_t tmp;
+
+			if (atoui32(token1, token2, &tmp))
+				return -1;
+			if (tmp <= UINT8_MAX) {
+				info->model_value_used = (uint8_t)tmp;
+			} else {
+				fprintf(stderr, "%s: Error read in %s.\n",
+					PROGRAM_NAME, token1);
+				return -1;
+			}
+			continue;
+		}
+		if (!strcmp(token1, "round_used")) {
+			uint32_t tmp;
+
+			if (atoui32(token1, token2, &tmp))
+				return -1;
+			if (tmp <= 0xF) { /* max value of 4 bits */
+				info->round_used = (uint8_t)tmp;
+			} else {
+				fprintf(stderr, "%s: Error read in %s.\n",
+					PROGRAM_NAME, token1);
+				return -1;
+			}
+			continue;
+		}
+		if (!strcmp(token1, "spill_used")) {
+			uint32_t tmp;
+
+			if (atoui32(token1, token2, &tmp))
+				return -1;
+			info->spill_used = (unsigned char)tmp;
+			continue;
+		}
+		if (!strcmp(token1, "golomb_par_used")) {
+			uint32_t tmp;
+
+			if (atoui32(token1, token2, &tmp))
+				return -1;
+			info->golomb_par_used = tmp;
+			continue;
+		}
+		if (!strcmp(token1, "samples_used")) {
+			if (atoui32(token1, token2, &info->samples_used))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_size")) {
+			if (atoui32(token1, token2, &info->cmp_size))
+				return -1;
+			continue;
+		}
+
+		if (!strcmp(token1, "ap1_cmp_size")) {
+			if (atoui32(token1, token2, &info->ap1_cmp_size))
+				return -1;
+			continue;
+		}
+		if (!strcmp(token1, "ap2_cmp_size")) {
+			if (atoui32(token1, token2, &info->ap2_cmp_size))
+				return -1;
+			continue;
+		}
+
+		if (!strcmp(token1, "rdcu_new_model_adr_used")) {
+			int i = sram_addr_to_int(token2);
+
+			if (i < 0) {
+				fprintf(stderr, "%s: Error read in rdcu_new_model_adr_used\n",
+				       PROGRAM_NAME);
+				return -1;
+			}
+			info->rdcu_new_model_adr_used = (uint32_t)i;
+			continue;
+		}
+		if (!strcmp(token1, "rdcu_cmp_adr_used")) {
+			int i = sram_addr_to_int(token2);
+
+			if (i < 0) {
+				fprintf(stderr,"%s: Error read in "
+				       "rdcu_cmp_adr_used\n",
+				       PROGRAM_NAME);
+				return -1;
+			}
+			info->rdcu_cmp_adr_used = (uint32_t)i;
+			continue;
+		}
+		if (!strcmp(token1, "cmp_err")) {
+			uint32_t tmp;
+
+			if (atoui32(token1, token2, &tmp))
+				return -1;
+			if (tmp <= UINT16_MAX) {
+				info->cmp_err = (uint16_t)tmp;
+			} else {
+				fprintf(stderr, "%s: Error read in %s.\n",
+					PROGRAM_NAME, token1);
+				return -1;
+			}
+			continue;
+		}
+	}
+	return 0;
+}
+
+
+/**
+ * @brief reading a compressor decompression information file
+ *
+ * @param file_name	file containing the compression configuration file
+ * @param info		decompression information structure holding the read in
+ *			information
+ * @param verbose_en	print verbose output if not zero
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int read_cmp_info(const char *file_name, struct cmp_info *info, int verbose_en)
+{
+	FILE *fp;
+
+	if (!file_name)
+		abort();
+
+	if (!info)
+		abort();
+
+	if (strstr(file_name, ".cfg")) {
+	    fprintf(stderr, "%s: %s: .cfg file extension found on decompression information file. You may have selected the wrong file.\n",
+		    PROGRAM_NAME, file_name);
+	}
+
+	fp = fopen(file_name, "r");
+	if (fp == NULL) {
+		fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name,
+			strerror(errno));
+		return -1;
+	}
+
+	parse_info(fp, info);
+
+	fclose(fp);
+
+	if (verbose_en) {
+		printf("\n\n");
+		print_cmp_info(info);
+		printf("\n");
+	}
+
+	return 0;
+}
+
+
+/**
+ * @brief reads a hex encoded uint8_t data (or model) file, returns a buffer
+ *	containing the read in data
+ *
+ * @note data must be encode has 4 hex digits separated by a white space or new
+ *	line character e.g. "ABCD 1234 AB12\n"
+ *
+ * @param file_name	data file name
+ * @param samples	amount of uint16_t data samples to read in
+ * @param verbose_en	print verbose output if not zero
+ *
+ * @returns address to the buffer containing the read in data, NULL on error
+ */
+
+uint8_t *read_file8(const char *file_name, uint32_t samples, int verbose_en)
+{
+	uint32_t i;
+	FILE *fp;
+	uint8_t *buffer;
+	char tmp_str[4]; /* 6 = 2 hex digit's + 1 white space + 1 \0 */
+
+	if (!file_name)
+		abort();
+
+	if (!samples)
+		return NULL;
+
+	fp = fopen(file_name, "r");
+	if (fp == NULL) {
+		fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name,
+			strerror(errno));
+		return NULL;
+	}
+
+	buffer = (uint8_t *)malloc(samples * SAM2BYT);
+	if (buffer == NULL) {
+		fprintf(stderr, "%s: Error allocating memory.\n", PROGRAM_NAME);
+		fclose(fp);
+		return NULL;
+	}
+
+	for (i = 0; i < samples; i++) {
+		int j;
+		unsigned long read_val;
+		char *end;
+
+		if (!fgets(tmp_str, sizeof(tmp_str), fp)) {
+			fprintf(stderr, "%s: %s: Error: The files does not contain enough data as given by the samples parameter.\n",
+				PROGRAM_NAME, file_name);
+			goto error;
+		}
+
+		if (tmp_str[0] == '#' || tmp_str[0] == '\n') {
+			i--; /* a comment or empty line does not count as sample */
+			continue;
+		}
+
+		for (j = 0; j < 2; j++) {
+			if (!isxdigit(tmp_str[j])) {
+				fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected format is like: 12 AB 23 CD .. ..\n", PROGRAM_NAME,
+					file_name);
+				goto error;
+			}
+		}
+
+		if (!(isspace(tmp_str[2]) || tmp_str[2] == '\n')) {
+			fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected format is: 12 AB 23 CD .. ..\n", PROGRAM_NAME, file_name);
+			goto error;
+		}
+
+		read_val = strtoul(tmp_str, &end, 16);
+
+		if (tmp_str == end || errno == ERANGE || read_val > UINT8_MAX) {
+			fprintf(stderr, "%s: %s: Error: The data can not be converted to integer.\n",
+				PROGRAM_NAME, file_name);
+			goto error;
+		}
+
+		buffer[i] = (uint16_t)read_val;
+
+		if (verbose_en) {
+			if (i == 0)
+				printf("\n\n");
+
+			printf("%02X", buffer[i]);
+			if (i && !((i + 1) % 28))
+				printf("\n");
+			else
+				printf(" ");
+		}
+	}
+	if (verbose_en)
+		printf("\n\n");
+
+	fgets(tmp_str, sizeof(tmp_str), fp);
+	if (!feof(fp) && tmp_str[0] == '\n') /* read last line break */
+		fgets(tmp_str, sizeof(tmp_str), fp);
+
+	if (!feof(fp)) {
+		fprintf(stderr, "%s: %s: Warning: The file may contain more data than specified by the samples parameter.\n",
+			PROGRAM_NAME, file_name);
+	}
+
+	fclose(fp);
+
+	return buffer;
+
+	error:
+		free(buffer);
+		fclose(fp);
+		return NULL;
+}
+
+
+/**
+ * @brief reads a hex encoded uint16_t data (or model) file, returns a buffer
+ *	containing the read in data
+ *
+ * @note data must be encode has 4 hex digits separated by a white space or new
+ *	line character e.g. "ABCD 1234 AB12\n"
+ *
+ * @param file_name	data file name
+ * @param samples	amount of uint16_t data samples to read in
+ * @param verbose_en	print verbose output if not zero
+ *
+ * @returns address to the buffer containing the read in data, NULL on error
+ */
+
+uint16_t *read_file16(const char *file_name, uint32_t samples, int verbose_en)
+{
+	size_t i;
+	uint16_t *buf = (uint16_t *)read_file8(file_name, samples*2, verbose_en);
+
+	if (!buf)
+		return NULL;
+
+	for (i=0; i < samples; i++)
+		be16_to_cpus(&buf[i]);
+
+	return buf;
+}
+
+
+/**
+ * @brief reads a hex encoded uint32_t data file, returns a buffer containing
+ *	the read in data
+ *
+ * @note data must be encode has 2 hex digits separated by a white space or new
+ *	line character e.g. AB CD 12 34
+ *
+ * @param file_name	data file name
+ * @param buf_len	amount of uint32_t data samples to read in
+ * @param verbose_en	print verbose output if not zero
+ *
+ * @returns address to the buffer containing the read in data, NULL on error
+ */
+
+uint32_t *read_file32(const char *file_name, uint32_t buf_len, int verbose_en)
+{
+	size_t i;
+
+	uint32_t *buf = (uint32_t *)read_file8(file_name, buf_len*sizeof(uint32_t),
+					       verbose_en);
+
+	if (!buf)
+		return NULL;
+
+	for (i=0; i < buf_len; i++)
+		be32_to_cpus(&buf[i]);
+
+	return buf;
+}
+
+
+/**
+ * @brief prints config struct
+ *
+ * @param cfg		configuration to print
+ * @param rdcu_cfg	if set additional RDCU parameter are printed as well
+ */
+
+void print_cfg(const struct cmp_cfg *cfg, int rdcu_cfg)
+{
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Default Configuration File\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Selected compression mode\n");
+	printf("# 0: raw mode\n");
+	printf("# 1: model mode with zero escape symbol mechanism\n");
+	printf("# 2: 1d differencing mode without input model with zero escape symbol mechanism\n");
+	printf("# 3: model mode with multi escape symbol mechanism\n");
+	printf("# 4: 1d differencing mode without input model multi escape symbol mechanism\n");
+	printf("\n");
+	printf("cmp_mode = %u\n", cfg->cmp_mode);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Number of samples (16 bit value) to compress, length of the data and model buffer\n");
+	printf("\n");
+	printf("samples = %u\n", cfg->samples);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Length of the compressed data buffer in number of samples (16 bit values)\n");
+	printf("\n");
+	printf("buffer_length = %u\n", cfg->buffer_length);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Golomb parameter for dictionary selection\n");
+	printf("\n");
+	printf("golomb_par = %u\n", cfg->golomb_par);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Spillover threshold for encoding outliers\n");
+	printf("\n");
+	printf("spill = %u\n", cfg->spill);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Model weighting parameter\n");
+	printf("\n");
+	printf("model_value = %u\n", cfg->model_value);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+	printf("# Number of noise bits to be rounded\n");
+	printf("\n");
+	printf("round = %u\n", cfg->round);
+	printf("\n");
+	printf("#-------------------------------------------------------------------------------\n");
+
+	if (rdcu_cfg) {
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# Hardware Compressor Settings (not need for SW compression)\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("\n");
+		printf("# Adaptive 1 Golomb parameter; HW only\n");
+		printf("\n");
+		printf("ap1_golomb_par = %u\n", cfg->ap1_golomb_par);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# Adaptive 1 spillover threshold; HW only\n");
+		printf("\n");
+		printf("ap1_spill = %u\n", cfg->ap1_spill);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# Adaptive 2 Golomb parameter; HW only\n");
+		printf("\n");
+		printf("ap2_golomb_par = %u\n", cfg->ap2_golomb_par);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# Adaptive 2 spillover threshold; HW only\n");
+		printf("\n");
+		printf("ap2_spill = %u\n", cfg->ap2_spill);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# RDCU data to compress start address, the first data address in the RDCU SRAM; HW only\n");
+		printf("\n");
+		printf("rdcu_data_adr = 0x%06X\n",
+		       cfg->rdcu_data_adr);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# RDCU model start address, the first model address in the RDCU SRAM\n");
+		printf("\n");
+		printf("rdcu_model_adr = 0x%06X\n",
+		       cfg->rdcu_model_adr);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# RDCU updated model start address, the address in the RDCU SRAM where the updated model is stored\n");
+		printf("\n");
+		printf("rdcu_new_model_adr = 0x%06X\n",
+		       cfg->rdcu_new_model_adr);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+		printf("# RDCU compressed data start address, the first output data address in the RDCU SRAM\n");
+		printf("\n");
+		printf("rdcu_buffer_adr = 0x%06X\n", cfg->rdcu_buffer_adr);
+		printf("\n");
+		printf("#-------------------------------------------------------------------------------\n");
+	}
+}
+
+/**
+ * @brief write a decompression information structure to a file
+ *
+ * @param info	 compressor information contains information of an executed
+ *		 compression
+ * @param output_prefix prefix of the written file (.info is added to the prefix)
+ * @param machine_cfg - if set write additional RDCU parameter in the file
+ *
+ * @returns 0 on success, error otherwise
+ */
+
+int write_info(const struct cmp_info *info, const char *output_prefix,
+	       int machine_cfg)
+{
+	FILE *fp = open_file(output_prefix, ".info");
+
+	if (fp == NULL) {
+		fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix,
+			".info", strerror(errno));
+		return -1;
+	}
+
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Decompression Information File\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Compression mode used\n");
+	fprintf(fp, "# 0: raw mode\n");
+	fprintf(fp, "# 1: model mode with zero escape symbol mechanism\n");
+	fprintf(fp, "# 2: 1d differencing mode without input model with zero escape symbol mechanism\n");
+	fprintf(fp, "# 3: model mode with multi escape symbol mechanism\n");
+	fprintf(fp, "# 4: 1d differencing mode without input model multi escape symbol mechanism\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "cmp_mode_used = %u\n", info->cmp_mode_used);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Number of samples used, measured in 16 bit units, length of the data and model buffer\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "samples_used = %u\n", info->samples_used);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Compressed data size; measured in bits\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "cmp_size = %u\n", info->cmp_size);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Golomb parameter used\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "golomb_par_used = %u\n", info->golomb_par_used);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Spillover threshold used\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "spill_used = %u\n", info->spill_used);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Model weighting parameter used\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "model_value_used = %u\n", info->model_value_used);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fprintf(fp, "# Number of noise bits to be rounded used\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "round_used = %u\n", info->round_used);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+
+	if (machine_cfg) {
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+		fprintf(fp, "# Hardware Compressor Settings (not need for SW compression)\n");
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+		fprintf(fp, "\n");
+		fprintf(fp, "# Adaptive compressed data size 1; measured in bits\n");
+		fprintf(fp, "\n");
+		fprintf(fp, "ap1_cmp_size = %u\n", info->ap1_cmp_size);
+		fprintf(fp, "\n");
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+		fprintf(fp, "# Adaptive compressed data size 2; measured in bits\n");
+		fprintf(fp, "\n");
+		fprintf(fp, "ap2_cmp_size = %u\n", info->ap2_cmp_size);
+		fprintf(fp, "\n");
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+		fprintf(fp, "# Updated model info start address used\n");
+		fprintf(fp, "\n");
+		fprintf(fp, "rdcu_new_model_adr_used = 0x%06X\n", info->rdcu_new_model_adr_used);
+		fprintf(fp, "\n");
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+		fprintf(fp, " #RDCU compressed data start address\n");
+		fprintf(fp, "\n");
+		fprintf(fp, "rdcu_cmp_adr_used = 0x%06X\n", info->rdcu_cmp_adr_used);
+		fprintf(fp, "\n");
+		fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	}
+	fprintf(fp, "# Compressor errors\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "# [bit 0] small_buffer_err; The length for the compressed data buffer is too small\n");
+	fprintf(fp, "# [bit 1] cmp_mode_err; The cmp_mode parameter is not set correctly\n");
+	fprintf(fp, "# [bit 2] model_value_err; The model_value parameter is not set correctly\n");
+	fprintf(fp, "# [bit 3] cmp_par_err; The spill, golomb_par combination is not set correctly\n");
+	fprintf(fp, "# [bit 4] ap1_cmp_par_err; The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression)\n");
+	fprintf(fp, "# [bit 5] ap2_cmp_par_err; The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression)\n");
+	fprintf(fp, "# [bit 6] mb_err; Multi bit error detected by the memory controller (only HW compression)\n");
+	fprintf(fp, "# [bit 7] slave_busy_err; The bus master has received the 'slave busy' status (only HW compression)\n");
+	fprintf(fp, "# [bit 8] slave_blocked_err; The bus master has received the “slave blocked” status (only HW compression)\n");
+	fprintf(fp, "# [bit 9] invalid address_err; The bus master has received the “invalid address” status (only HW compression)\n");
+	fprintf(fp, "\n");
+	fprintf(fp, "cmp_err = %x\n", info->cmp_err);
+	fprintf(fp, "\n");
+	fprintf(fp, "#-------------------------------------------------------------------------------\n");
+	fclose(fp);
+
+	return 0;
+}
diff --git a/test_data/test_data1.dat b/test_data/test_data1.dat
new file mode 100644
index 0000000..a040702
--- /dev/null
+++ b/test_data/test_data1.dat
@@ -0,0 +1,4 @@
+01 00 00 0B C1 C1 7F 57 A6 00 0B C1 C1 7F 00 00 00 01 10 00 FF C0 04 80 04 82 04 83 04 80 04 85
+04 83 04 82 04 89 04 87 04 89 04 8A 04 7F 04 87 04 86 04 9A 04 DA 04 CD 04 8D 04 83 04 8D 04 9D
+04 FD 04 E7 04 8F 04 84 04 7F 04 8B 04 9E 04 9A 04 89 04 90 04 84 04 7F 04 89 04 8E 04 80 04 82
+04 83 04 80 
diff --git a/test_data/test_data2.dat b/test_data/test_data2.dat
new file mode 100644
index 0000000..d891fd1
--- /dev/null
+++ b/test_data/test_data2.dat
@@ -0,0 +1,4 @@
+01 00 00 0B C1 C1 7F 57 A6 00 0B C1 C1 7F 00 00 00 01 10 00 FF C0 04 7F 04 81 04 84 04 83 04 81
+04 7D 04 85 04 84 04 85 04 8D 04 8B 04 81 04 83 04 8C 04 99 04 D8 04 CB 04 8E 04 85 04 8F 04 A1
+04 FF 04 ED 04 91 04 83 04 86 04 8D 04 A8 04 9B 04 85 04 90 04 7F 04 83 04 89 04 8A 04 86 04 81
+04 84 04 83 
-- 
GitLab