diff --git a/CHANGELOG.md b/CHANGELOG.md index 18386d43e4eb8acb3468acf9d855a11e4a916584..57a3c6e5c9412d9ab5d671eab32f047683c208e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. ## [Unreleased] + +## [0.09] - 30-09-2022 +### Added +- decompression/compression for non-imagette data +- functions to create and configure a compression configuration +- add max_used_bits feature +- add max used bit version field to the compression entity +###Changed +- Change the build system form make to meson +- Change DEFAULT_CFG_MODEL and DEFAULT_CFG_DIFF to CMP_DIF_XXX constats +### Fixed +- now the adaptive compression size (ap1_cmp_size, ap2_cmp_size) is calculate when the --rdcu_par option is used + ## [0.08] - 19-01-2021 ### Added - Relax the requirements on the input format @@ -16,6 +29,9 @@ E.g. "# comment\n ABCD 1 2\n34B 12\n" are interpreted as {0xAB, 0xCD, ### Changed - update the header definition according to PLATO-UVIE-PL-UM-0001 Draft 6 - changed version_id from 16 to 32 bit in the generic header. Add spare bits to the adaptive imagette header and the non-imagette header, so that the compressed data start address is 4 byte-aligned. +### Fixed +- Fix a bug in the definition in imagette header +### Changed - Rename cmp_tool_lib.c to cmp_io.c ## [0.07] - 13-12-2021 diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000000000000000000000000000000000000..7665bcb92bd15a7bb678129d1bb3eda586d10873 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,145 @@ +# Installation Instructions +## Getting started + +### Install git and python 3.7+ + +If you're on Linux, you probably already have these. On macOS and Windows, you can use the +[official Python installer](https://www.python.org/downloads). + +### Install meson and ninja + +Meson 0.56 or newer is required. +You can get meson through your package manager or using: + +```pip3 install meson``` + +Check if meson is included in your PATH. + +You should get `ninja` using your [package manager](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages) or download the [official +release](https://github.com/ninja-build/ninja/releases) and put the `ninja` +binary in your PATH. + +### Get the Source Code + +We use the version control system [git](https://git-scm.com/downloads) to get a copy of the source code. + +``` +git clone https://gitlab.phaidra.org/loidoltd15/cmp_tool.git +cd cmp_tool +``` +## Build the cmp\_tool +### Build the cmp\_tool for Debugging + +First, we create the `builddir` directory. Everything we build will be inside this directory. + +``` +meson setup builddir +``` + +We change to the build directory and build the cmp_tool: + +``` +cd builddir +meson compile cmp_tool +``` + +Now you should find the cmp\_tool executable in the folder. + +### Release Build + +If you want to create an optimized release version, we can create a build directory for it: + +``` +meson setup build_relase_dir --buildtype=release +cd build_relase_dir +meson compile cmp_tool +``` + +You find the build executable in the `build_relase_dir` directory + +### Build for Windows + +Unfortunately, the cmp\_tool does not support the Microsoft MSVC compiler. To build the cmp\_tool for Windows you can use the Mingw-w64 GCC compiler. +For this, you need the [Mingw-w64 toolchain](https://www.mingw-w64.org/downloads/). To compile on Windows, do this in the Cygwin64 Terminal: + +``` +meson setup buiddir_win --native-file=mingw-w64-64.txt +cd buiddir_win +meson compile +``` + +### Cross-compile for Windows +Cross-compile for Windows is also possible with the [Mingw-w64 toolchain](https://www.mingw-w64.org/downloads/). To cross-compile for Windows use the following commands: + +``` +meson setup buiddir_cross_win --cross-file=mingw-w64-64.txt +cd buiddir_cross_win +meson compile +``` + +## Tests +### External dependencies + +To run the unit tests you need the [ruby interpreter](https://www.ruby-lang.org/en/documentation/installation/). +To run the cmp\_tool interface test you need the [pytest](https://docs.pytest.org/en/7.0.x/index.html) framework. The easiest way to install pytest is with `pip3`: + +``` +pip3 install pytest +``` +### Run tests +First, cd in the build directory: + +``` +cd <name of the build directory> +``` + +You can easily run the test of all the components: + +``` +meson test +``` + +To list all available tests: + +``` +meson test --list +``` + +Meson also supports running the tests under GDB. Just doing this: + +``` +meson test --gdb <testname> +``` + +### Producing a coverage report + +First, configure the build with this command. + +``` +cd <name of the build directory> +meson configure -Db_coverage=true +``` + +Then issue the following commands. + +``` +meson test +ninja coverage-html +``` + +The coverage report can be found in the `meson-logs/coveragereport` subdirectory. + +## Documentation +### External dependencies +To generate the documentation you need the [Doxygen](https://www.doxygen.nl/index.html) program. +Optional you can install the "dot" tool from [graphviz](http://www.graphviz.org/) to generate more advanced diagrams and graphs. + +### Generate Documentation + +To generate the documentation you need to run: + +``` +cd <name of the build directory> +meson compile doc +``` + diff --git a/Makefile b/Makefile deleted file mode 100644 index 6038a8737bfa8f1b32d8555b46980b2a074adc24..0000000000000000000000000000000000000000 --- a/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -CC = gcc -SOURCEDIR = lib -INCLUDEDIR = include -BUILDDIR = ./ -CFLAGS := -Wall -Wextra -std=gnu99 -mno-ms-bitfields -pedantic -Wshadow \ - -Wunreachable-code #-Wdocumentation #-Wsign-conversion -RELCFLAGS := -O2 # Release flags -DBCFLAGS := -O0 -g3 -fsanitize=address -fsanitize=undefined #debug flags -COVFLAGS := -fprofile-arcs -ftest-coverage #coverage flags -CPPFLAGS := -I $(INCLUDEDIR) -LDFLAGS := -lm -SOURCES := cmp_tool.c \ - $(SOURCEDIR)/rmap.c \ - $(SOURCEDIR)/rdcu_ctrl.c \ - $(SOURCEDIR)/rdcu_cmd.c \ - $(SOURCEDIR)/rdcu_rmap.c \ - $(SOURCEDIR)/cmp_support.c \ - $(SOURCEDIR)/cmp_data_types.c \ - $(SOURCEDIR)/cmp_rdcu.c \ - $(SOURCEDIR)/cmp_icu.c \ - $(SOURCEDIR)/decmp.c \ - $(SOURCEDIR)/rdcu_pkt_to_file.c \ - $(SOURCEDIR)/cmp_guess.c \ - $(SOURCEDIR)/cmp_io.c \ - $(SOURCEDIR)/cmp_entity.c -TARGET := cmp_tool - -DEBUG?=1 -ifeq "$(shell expr $(DEBUG) \> 1)" "1" - CFLAGS += -DDEBUGLEVEL=$(DEBUG) -else - CFLAGS += -DDEBUGLEVEL=1 -endif - - -all: $(SOURCES) - $(CC) $(CPPFLAGS) $(CFLAGS) $(RELCFLAGS) $^ -o $(TARGET) $(LDFLAGS) - -debug: $(SOURCES) - $(CC) $(CPPFLAGS) $(CFLAGS) $(DBCFLAGS) $^ -o $(TARGET) $(LDFLAGS) - -integration: $(SOURCES) - $(CC) $(CPPFLAGS) $(CFLAGS) $(DBCFLAGS) $(COVFLAGS) $^ -o $(TARGET) $(LDFLAGS) - pytest test/cmp_tool/cmp_tool_integration_test.py - lcov --rc lcov_branch_coverage=1 --capture --directory ./ --output-file coverage.info - genhtml --rc lcov_branch_coverage=1 --branch-coverage coverage.info --output-directory out -#firefox out/index.html - -clean: - rm -rf $(TARGET) *.gcno *.gcda coverage.info out diff --git a/README.md b/README.md index 325a24c78f8767358abc5604d6463f301955ecf9..cad1887c99f2df6c0a2a992a434bd911858f06e1 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ If you find a bug or have a feature request please file an [issue][1] or send me an [email][2]. -Compiled executables can be found [here][3]. +Compiled executables can be found [here][3]. The building instructions can be found [here](INSTALL.md). ## Usage @@ -86,7 +86,7 @@ You can find the user manual [here](doc). A simple example to show how the compression tool works. Instructions on how to perform compression without headers can be found [here](how_to_no_header.md). -0. Download the [tool][3] or run `make` to build the tool +0. Download the [tool][3] or [build the tool](INSTALL.md) yourself 1. Create a configuration file * Create a cfg directory diff --git a/cmp_tool.c b/cmp_tool.c old mode 100755 new mode 100644 index fd8401f96975fd06a4c82b7a0216758ab33aae2a..3572c23398944893dd291d74cca53bb76d7b836c --- a/cmp_tool.c +++ b/cmp_tool.c @@ -25,23 +25,34 @@ #include <getopt.h> #include <time.h> -#include "include/cmp_io.h" -#include "include/cmp_icu.h" -#include "include/decmp.h" -#include "include/cmp_guess.h" -#include "include/cmp_entity.h" -#include "include/rdcu_pkt_to_file.h" +#include "cmp_tool-config.h" +#include "cmp_io.h" +#include "cmp_icu.h" +#include "cmp_rdcu.h" /*TODO: shift setup to support */ +#include "decmp.h" +#include "cmp_guess.h" +#include "cmp_entity.h" +#include "rdcu_pkt_to_file.h" +#include "cmp_data_types.h" -#define VERSION "0.08" - #define BUFFER_LENGTH_DEF_FAKTOR 2 - #define DEFAULT_MODEL_ID 53264 /* random default id */ #define DEFAULT_MODEL_COUNTER 0 +/* find a good set of compression parameters for a given dataset */ +static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode, + int guess_level); + +/* compress the data and write the results to files */ +static int compression(struct cmp_cfg *cfg, struct cmp_info *info); + +/* decompress the data and write the results in file(s)*/ +static int decompression(struct cmp_entity *ent, uint16_t *input_model_buf); + + /* * For long options that have no equivalent short option, use a * non-character as a pseudo short option, starting with CHAR_MAX + 1. @@ -79,7 +90,7 @@ static const char *output_prefix = DEFAULT_OUTPUT_PREFIX; /* if non zero additional RDCU parameters are included in the compression * configuration and decompression information files */ -static int print_rdcu_cfg; +static int add_rdcu_pars; /* if non zero generate RDCU setup packets */ static int rdcu_pkt_mode; @@ -94,17 +105,6 @@ static int verbose_en; /* if non zero add a compression entity header in front of the compressed data */ static int include_cmp_header = 1; -/* find a good set of compression parameters for a given dataset */ -static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode, - int guess_level); - -/* compress the data and write the results to files */ -static int compression(struct cmp_cfg *cfg, struct cmp_info *info); - -/* decompress the data and write the results in file(s)*/ -static int decompression(uint32_t *cmp_data_adr, uint16_t *input_model_buf, - struct cmp_info *info); - /* model ID string set by the --model_id option */ static const char *model_id_str; @@ -140,16 +140,16 @@ int main(int argc, char **argv) int guess_level = DEFAULT_GUESS_LEVEL; int print_diff_cfg = 0; - struct cmp_cfg cfg = {0}; /* compressor configuration struct */ - struct cmp_info info = {0}; /* decompression information struct */ - - /* buffer containing all read in compressed data for decompression (including header if used) */ - void *decomp_input_buf = NULL; - /* address to the compressed data for the decompression */ - uint32_t *cmp_data_adr = NULL; + /* buffer containing all read in compressed data for decompression */ + struct cmp_entity *decomp_entity = NULL; /* buffer containing the read in model */ uint16_t *input_model_buf = NULL; + struct cmp_info info = {0}; /* decompression information struct */ + struct cmp_cfg cfg = {0}; /* compressor configuration struct */ + + cfg.data_type = DATA_TYPE_IMAGETTE; /* use imagette as default data type */ + /* show help if no arguments are provided */ if (argc < 2) { print_help(program_name); @@ -160,7 +160,7 @@ int main(int argc, char **argv) NULL)) != -1) { switch (opt) { case 'a': /* --rdcu_par */ - print_rdcu_cfg = 1; + add_rdcu_pars = 1; break; case 'c': cmp_operation = 1; @@ -190,7 +190,7 @@ int main(int argc, char **argv) verbose_en = 1; break; case 'V': /* --version */ - printf("%s version %s\n", PROGRAM_NAME, VERSION); + printf("%s version %s\n", PROGRAM_NAME, CMP_TOOL_VERSION); exit(EXIT_SUCCESS); break; case DIFF_CFG_OPTION: @@ -262,20 +262,38 @@ int main(int argc, char **argv) #endif if (print_model_cfg == 1) { - print_cfg(&DEFAULT_CFG_MODEL, print_rdcu_cfg); + cfg = rdcu_cfg_create(CMP_DEF_IMA_MODEL_DATA_TYPE, CMP_DEF_IMA_MODEL_CMP_MODE, + CMP_DEF_IMA_MODEL_MODEL_VALUE, CMP_DEF_IMA_MODEL_LOSSY_PAR); + rdcu_cfg_buffers(&cfg, NULL, 0, NULL, CMP_DEF_IMA_MODEL_RDCU_DATA_ADR, + CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR, CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR, + CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR, 0); + rdcu_cfg_imagette(&cfg, + CMP_DEF_IMA_MODEL_GOLOMB_PAR, CMP_DEF_IMA_MODEL_SPILL_PAR, + CMP_DEF_IMA_MODEL_AP1_GOLOMB_PAR, CMP_DEF_IMA_MODEL_AP1_SPILL_PAR, + CMP_DEF_IMA_MODEL_AP2_GOLOMB_PAR, CMP_DEF_IMA_MODEL_AP2_SPILL_PAR); + print_cfg(&cfg, add_rdcu_pars); exit(EXIT_SUCCESS); } if (print_diff_cfg == 1) { - print_cfg(&DEFAULT_CFG_DIFF, print_rdcu_cfg); + cfg = rdcu_cfg_create(CMP_DEF_IMA_DIFF_DATA_TYPE, CMP_DEF_IMA_DIFF_CMP_MODE, + CMP_DEF_IMA_DIFF_MODEL_VALUE, CMP_DEF_IMA_DIFF_LOSSY_PAR); + rdcu_cfg_buffers(&cfg, NULL, 0, NULL, CMP_DEF_IMA_DIFF_RDCU_DATA_ADR, + CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR, CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR, + CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR, 0); + rdcu_cfg_imagette(&cfg, + CMP_DEF_IMA_DIFF_GOLOMB_PAR, CMP_DEF_IMA_DIFF_SPILL_PAR, + CMP_DEF_IMA_DIFF_AP1_GOLOMB_PAR, CMP_DEF_IMA_DIFF_AP1_SPILL_PAR, + CMP_DEF_IMA_DIFF_AP2_GOLOMB_PAR, CMP_DEF_IMA_DIFF_AP2_SPILL_PAR); + print_cfg(&cfg, add_rdcu_pars); exit(EXIT_SUCCESS); } printf("#########################################################\n"); printf("### PLATO Compression/Decompression Tool Version %s ###\n", - VERSION); + CMP_TOOL_VERSION); printf("#########################################################\n"); - if (!strcmp(VERSION, "0.07") || !strcmp(VERSION, "0.08")) + if (!strcmp(CMP_TOOL_VERSION, "0.07") || !strcmp(CMP_TOOL_VERSION, "0.08")) printf("Info: Note that the behaviour of the cmp_tool has changed. From now on, the compressed data will be preceded by a header by default. The old behaviour can be achieved with the --no_header option.\n\n"); if (!data_file_name) { @@ -293,6 +311,7 @@ int main(int argc, char **argv) if (cmp_operation || guess_operation) { ssize_t size; + uint32_t input_size; if (cmp_operation) { printf("## Starting the compression ##\n"); @@ -308,21 +327,26 @@ int main(int argc, char **argv) printf("Importing data file %s ... ", data_file_name); /* count the samples in the data file when samples == 0 */ if (cfg.samples == 0) { - size = read_file16(data_file_name, NULL, 0, 0); - if (size <= 0) /* empty file is treated as an error */ + int samples; + size = read_file_data(data_file_name, cfg.data_type, NULL, 0, 0); + if (size <= 0 || size > UINT32_MAX) /* empty file is treated as an error */ + goto fail; + samples = cmp_input_size_to_samples(size, cfg.data_type); + if (samples < 0) goto fail; - cfg.samples = size/size_of_a_sample(cfg.cmp_mode); + cfg.samples = (uint32_t)samples; printf("\nNo samples parameter set. Use samples = %u.\n... ", cfg.samples); } - cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.cmp_mode)); + input_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type); + cfg.input_buf = malloc(input_size); if (!cfg.input_buf) { fprintf(stderr, "%s: Error allocating memory for input data buffer.\n", PROGRAM_NAME); goto fail; } - size = read_file16(data_file_name, cfg.input_buf, cfg.samples, - verbose_en); + size = read_file_data(data_file_name, cfg.data_type, cfg.input_buf, + input_size, verbose_en); if (size < 0) goto fail; printf("DONE\n"); @@ -330,7 +354,8 @@ int main(int argc, char **argv) } else { /* decompression mode*/ printf("## Starting the decompression ##\n"); if (info_file_name) { - ssize_t size; + ssize_t f_size; + size_t ent_size; uint32_t cmp_size_byte; printf("Importing decompression information file %s ... ", info_file_name); @@ -341,75 +366,76 @@ int main(int argc, char **argv) printf("Importing compressed data file %s ... ", data_file_name); cmp_size_byte = cmp_bit_to_4byte(info.cmp_size); - cmp_data_adr = decomp_input_buf = malloc(cmp_size_byte); - if (!decomp_input_buf) { + + ent_size = cmp_ent_create(NULL, DATA_TYPE_IMAGETTE, info.cmp_mode_used == CMP_MODE_RAW, + cmp_size_byte); + if (!ent_size) + goto fail; + decomp_entity = malloc(ent_size); + if (!decomp_entity) { fprintf(stderr, "%s: Error allocating memory for decompression input buffer.\n", PROGRAM_NAME); goto fail; } + ent_size = cmp_ent_create(decomp_entity, DATA_TYPE_IMAGETTE, info.cmp_mode_used == CMP_MODE_RAW, + cmp_size_byte); + if (!ent_size) + goto fail; - size = read_file32(data_file_name, decomp_input_buf, - cmp_size_byte/4, verbose_en); - if (size < 0) + if (info.cmp_mode_used == CMP_MODE_RAW) + /* the raw data does not have to be a multiple of 4 bytes */ + cmp_size_byte = (info.cmp_size+7)/CHAR_BIT; + + f_size = read_file8(data_file_name, cmp_ent_get_data_buf(decomp_entity), + cmp_size_byte, verbose_en); + if (f_size < 0) + goto fail; + + error = cmp_ent_write_rdcu_cmp_pars(decomp_entity, &info, NULL); + if (error) goto fail; } else { /* read in compressed data with header */ ssize_t size; size_t buf_size; - struct cmp_entity *ent; printf("Importing compressed data file %s ... ", data_file_name); buf_size = size = read_file_cmp_entity(data_file_name, NULL, 0, 0); - if (size < 0) + if (size < 0 || size > UINT32_MAX) goto fail; /* to be save allocate at least the size of the cmp_entity struct */ if (buf_size < sizeof(struct cmp_entity)) buf_size = sizeof(struct cmp_entity); - decomp_input_buf = ent = malloc(buf_size); - if (!ent) { + decomp_entity = malloc(buf_size); + if (!decomp_entity) { fprintf(stderr, "%s: Error allocating memory for the compression entity buffer.\n", PROGRAM_NAME); goto fail; } - size = read_file_cmp_entity(data_file_name, ent, size, - verbose_en); - if (size < 0) - goto fail; - printf("DONE\n"); - - printf("Parse the compression entity header ... "); - error = cmp_ent_read_imagette_header(ent, &info); - if (error) - goto fail; - if (verbose_en) - print_cmp_info(&info); - - /* we reuse the entity buffer for the compressed data */ - cmp_data_adr = (uint32_t *)decomp_input_buf; - size = cmp_ent_get_cmp_data(ent, cmp_data_adr, buf_size); - ent = NULL; + size = read_file_cmp_entity(data_file_name, decomp_entity, + size, verbose_en); if (size < 0) goto fail; if (verbose_en) { - size_t i; - printf("\ncompressed data:\n"); - for (i = 0; i < size/sizeof(uint32_t); i++) { - printf("%08X ", cmp_data_adr[i]); - if (i && !((i+1) % 4)) - printf("\n"); - } + cmp_ent_print(decomp_entity); printf("\n"); } } printf("DONE\n"); } + if (model_file_name && !guess_operation && + ((cmp_operation && !model_mode_is_used(cfg.cmp_mode)) || + (!cmp_operation && !model_mode_is_used(cmp_ent_get_cmp_mode(decomp_entity))))) + printf("Warring: Model file (-m option) specified but no model is used.\n"); + /* read in model */ if ((cmp_operation && model_mode_is_used(cfg.cmp_mode)) || - (!cmp_operation && model_mode_is_used(info.cmp_mode_used)) || + (!cmp_operation && model_mode_is_used(cmp_ent_get_cmp_mode(decomp_entity))) || (guess_operation && model_file_name)) { ssize_t size; - uint32_t model_length; + uint32_t model_size; + enum cmp_data_type data_type; printf("Importing model file %s ... ", model_file_name ? model_file_name : ""); if (!model_file_name) { @@ -417,24 +443,28 @@ int main(int argc, char **argv) goto fail; } - if (cmp_operation || guess_operation) - model_length = cfg.samples; - else - model_length = info.samples_used; + if (cmp_operation || guess_operation) { + data_type = cfg.data_type; + model_size = cmp_cal_size_of_data(cfg.samples, cfg.data_type); + } else { + data_type = cmp_ent_get_data_type(decomp_entity); + model_size = cmp_ent_get_original_size(decomp_entity); + } - input_model_buf = malloc(model_length * size_of_a_sample(cfg.cmp_mode)); + input_model_buf = malloc(model_size); if (!input_model_buf) { fprintf(stderr, "%s: Error allocating memory for model buffer.\n", PROGRAM_NAME); goto fail; } - size = read_file16(model_file_name, input_model_buf, - model_length, verbose_en); + size = read_file_data(model_file_name, data_type, input_model_buf, + model_size, verbose_en); if (size < 0) goto fail; printf("DONE\n"); cfg.model_buf = input_model_buf; + cfg.icu_new_model_buf = input_model_buf; /* in-place model update */ } if (guess_operation) { @@ -446,7 +476,7 @@ int main(int argc, char **argv) if (error) goto fail; } else { - error = decompression(cmp_data_adr, input_model_buf, &info); + error = decompression(decomp_entity, input_model_buf); if (error) goto fail; } @@ -454,17 +484,28 @@ int main(int argc, char **argv) /* write our the updated model for compressed or decompression */ if (!guess_operation && ((cmp_operation && model_mode_is_used(cfg.cmp_mode)) || - (!cmp_operation && model_mode_is_used(info.cmp_mode_used)))) { + (!cmp_operation && model_mode_is_used(cmp_ent_get_cmp_mode(decomp_entity))))) { + enum cmp_data_type data_type = DATA_TYPE_UNKNOWN; + uint32_t model_size; + printf("Write updated model to file %s_upmodel.dat ... ", output_prefix); - error = write_to_file16(input_model_buf, info.samples_used, - output_prefix, "_upmodel.dat", verbose_en); + if (cmp_operation) { + data_type = cfg.data_type; + model_size = cmp_cal_size_of_data(cfg.samples, data_type); + } else { + data_type = cmp_ent_get_data_type(decomp_entity); + model_size = cmp_ent_get_original_size(decomp_entity); + } + + error = write_input_data_to_file(input_model_buf, model_size, data_type, + output_prefix, "_upmodel.dat", verbose_en); if (error) goto fail; printf("DONE\n"); } free(cfg.input_buf); - free(decomp_input_buf); + free(decomp_entity); free(input_model_buf); exit(EXIT_SUCCESS); @@ -473,56 +514,33 @@ fail: printf("FAILED\n"); free(cfg.input_buf); - free(decomp_input_buf); + free(decomp_entity); free(input_model_buf); exit(EXIT_FAILURE); } -static enum cmp_ent_data_type cmp_ent_map_cmp_mode_data_type(uint32_t cmp_mode) -{ - enum cmp_ent_data_type data_type; - - switch (cmp_mode) { - case MODE_RAW: - case MODE_MODEL_ZERO: - case MODE_DIFF_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_MULTI: - if (print_rdcu_cfg) - data_type = DATA_TYPE_IMAGETTE_ADAPTIVE; - else - data_type = DATA_TYPE_IMAGETTE; - break; - default: - printf("No mapping between compression mode and header data type\n!"); - return DATA_TYPE_UNKOWN; - } - - /* set raw bit if needed */ - if (raw_mode_is_used(cmp_mode)) - data_type |= 1UL << RAW_BIT_DATA_TYPE_POS; - - return data_type; -} - - /* find a good set of compression parameters for a given dataset */ static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode, int guess_level) { int error; uint32_t cmp_size_bit; - float cr; + double cr; printf("Search for a good set of compression parameters (level: %d) ... ", guess_level); if (!strcmp(guess_cmp_mode, "RDCU")) { + if (add_rdcu_pars) + cfg->data_type = DATA_TYPE_IMAGETTE_ADAPTIVE; + else + cfg->data_type = DATA_TYPE_IMAGETTE; if (cfg->model_buf) cfg->cmp_mode = CMP_GUESS_DEF_MODE_MODEL; else cfg->cmp_mode = CMP_GUESS_DEF_MODE_DIFF; } else { + cfg->data_type = DATA_TYPE_IMAGETTE; /* TODO*/ error = cmp_mode_parse(guess_cmp_mode, &cfg->cmp_mode); if (error) { fprintf(stderr, "%s: Error: unknown compression mode: %s\n", PROGRAM_NAME, guess_cmp_mode); @@ -540,24 +558,24 @@ static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode, if (include_cmp_header) cmp_size_bit = CHAR_BIT * (cmp_bit_to_4byte(cmp_size_bit) + - cmp_ent_cal_hdr_size(cmp_ent_map_cmp_mode_data_type(cfg->cmp_mode))); + cmp_ent_cal_hdr_size(cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW)); printf("DONE\n"); printf("Write the guessed compression configuration to file %s.cfg ... ", output_prefix); - error = write_cfg(cfg, output_prefix, print_rdcu_cfg, verbose_en); + error = write_cfg(cfg, output_prefix, add_rdcu_pars, verbose_en); if (error) return -1; printf("DONE\n"); - cr = (8.0 * cfg->samples * size_of_a_sample(cfg->cmp_mode))/cmp_size_bit; + cr = (8.0 * cmp_cal_size_of_data(cfg->samples, cfg->data_type))/cmp_size_bit; printf("Guessed parameters can compress the data with a CR of %.2f.\n", cr); return 0; } -/* generate packets to setup a RDCU compression */ +/* generate packets to setup an RDCU compression */ static int gen_rdcu_write_pkts(struct cmp_cfg *cfg) { int error; @@ -594,47 +612,76 @@ static int gen_rdcu_write_pkts(struct cmp_cfg *cfg) } -/* add a compression entity header in front of the data */ -static int add_cmp_ent_hdr(struct cmp_cfg *cfg, struct cmp_info *info, - uint64_t start_time) +/** + * @brief generate the compression information used based on the compression + * configuration, to emulate the RDCU behaviour + * + * @param cfg compression configuration struct + * @param cmp_size_bit length of the bitstream in bits + * @param info compressor information struct to set the used compression + * parameters (can be NULL) + * + * @note set cmp_size, ap1_cmp_size, ap2_cmp_size will be set to 0 + * + * @returns 0 on success, error otherwise + * TODO: set cmp_mode_err, set model_value_err, etc, in error case + */ + +static int cmp_gernate_rdcu_info(const struct cmp_cfg *cfg, int cmp_size_bit, + struct cmp_info *info) { - int error; - uint32_t red_val; - uint8_t model_counter = DEFAULT_MODEL_COUNTER; - uint16_t model_id = DEFAULT_MODEL_ID; - size_t s, cmp_hdr_size; - struct cmp_entity *ent; - enum cmp_ent_data_type data_type = cmp_ent_map_cmp_mode_data_type(cfg->cmp_mode); + if (!cfg) + return -1; - if (model_id_str) { - error = atoui32("model_id", model_id_str, &red_val); - if (error || red_val > UINT16_MAX) - return -1; - model_id = red_val; - } - if (model_counter_str) { - error = atoui32("model_counter", model_counter_str, &red_val); - if (error || red_val > UINT8_MAX) - return -1; - model_counter = red_val; - } else { - if (model_mode_is_used(cfg->cmp_mode)) - model_counter = DEFAULT_MODEL_COUNTER + 1; - } + if (cfg->cmp_mode > UINT8_MAX) + return -1; - cmp_hdr_size = cmp_ent_cal_hdr_size(data_type); - if (!cmp_hdr_size) + if (cfg->round > UINT8_MAX) return -1; - memmove((uint8_t *)cfg->icu_output_buf+cmp_hdr_size, cfg->icu_output_buf, - cmp_bit_to_4byte(info->cmp_size)); - ent = (struct cmp_entity *)cfg->icu_output_buf; - s = cmp_ent_build(ent, data_type, cmp_tool_gen_version_id(VERSION), - start_time, cmp_ent_create_timestamp(NULL), model_id, - model_counter, info, cfg); - if (!s) { - fprintf(stderr, "%s: error occurred while creating the compression entity header.\n", PROGRAM_NAME); + if (cfg->model_value > UINT8_MAX) return -1; + + if (info) { + info->cmp_err = 0; + info->cmp_mode_used = (uint8_t)cfg->cmp_mode; + info->model_value_used = (uint8_t)cfg->model_value; + info->round_used = (uint8_t)cfg->round; + info->spill_used = cfg->spill; + info->golomb_par_used = cfg->golomb_par; + info->samples_used = cfg->samples; + info->rdcu_new_model_adr_used = cfg->rdcu_new_model_adr; + info->rdcu_cmp_adr_used = cfg->rdcu_buffer_adr; + + if (cmp_size_bit == CMP_ERROR_SMALL_BUF) + /* the icu_output_buf is to small to store the whole bitstream */ + info->cmp_err |= 1UL << SMALL_BUFFER_ERR_BIT; /* set small buffer error */ + if (cmp_size_bit < 0) { + info->cmp_size = 0; + info->ap1_cmp_size = 0; + info->ap2_cmp_size = 0; + } else { + info->cmp_size = (uint32_t)cmp_size_bit; + + if (add_rdcu_pars) { + struct cmp_cfg cfg_cpy = *cfg; + + cfg_cpy.icu_output_buf = NULL; + cfg_cpy.icu_new_model_buf = NULL; + + cfg_cpy.golomb_par = cfg_cpy.ap1_golomb_par; + cfg_cpy.spill = cfg_cpy.ap1_spill; + info->ap1_cmp_size = icu_compress_data(&cfg_cpy); + if ((int)info->ap1_cmp_size < 0) + info->ap1_cmp_size = 0; + + cfg_cpy.golomb_par = cfg_cpy.ap2_golomb_par; + cfg_cpy.spill = cfg_cpy.ap2_spill; + info->ap2_cmp_size = icu_compress_data(&cfg_cpy); + if ((int)info->ap2_cmp_size < 0) + info->ap2_cmp_size = 0; + } + } } return 0; } @@ -643,12 +690,14 @@ static int add_cmp_ent_hdr(struct cmp_cfg *cfg, struct cmp_info *info, /* compress the data and write the results to files */ static int compression(struct cmp_cfg *cfg, struct cmp_info *info) { - int error; - uint32_t cmp_size_byte; - size_t out_buf_size; + int cmp_size, error; + uint32_t cmp_size_byte, out_buf_size; + size_t s; uint64_t start_time = cmp_ent_create_timestamp(NULL); - - cfg->icu_output_buf = NULL; + struct cmp_entity *cmp_entity = NULL; + uint8_t model_counter = DEFAULT_MODEL_COUNTER; + uint16_t model_id = DEFAULT_MODEL_ID; + void *data_to_write_to_file; if (cfg->buffer_length == 0) { cfg->buffer_length = (cfg->samples+1) * BUFFER_LENGTH_DEF_FAKTOR; /* +1 to prevent malloc(0)*/ @@ -666,30 +715,60 @@ static int compression(struct cmp_cfg *cfg, struct cmp_info *info) printf("Compress data ... "); /* round up to a multiple of 4 */ - out_buf_size = (cmp_cal_size_of_data(cfg->buffer_length, cfg->cmp_mode) + 3) & ~0x3U; + out_buf_size = (cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type) + 3) & ~0x3U; - cfg->icu_output_buf = malloc(out_buf_size + sizeof(struct cmp_entity)); - if (cfg->icu_output_buf == NULL) { + cmp_entity = calloc(1, out_buf_size + sizeof(struct cmp_entity)); + if (cmp_entity == NULL) { fprintf(stderr, "%s: Error allocating memory for output buffer.\n", PROGRAM_NAME); goto error_cleanup; } + s = cmp_ent_create(cmp_entity, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, out_buf_size); + if (!s) { + fprintf(stderr, "%s: error occurred while creating the compression entity header.\n", PROGRAM_NAME); + goto error_cleanup; + } + cfg->icu_output_buf = cmp_ent_get_data_buf(cmp_entity); - error = icu_compress_data(cfg, info); - if (error || info->cmp_err != 0) { - printf("\nCompression error 0x%02X\n... ", info->cmp_err); - /* TODO: add a parse cmp error function */ - /* if ((info->cmp_err >> SMALL_BUFFER_ERR_BIT) & 1U) */ - /* fprintf(stderr, "%s: the buffer for the compressed data is too small. Try a larger buffer_length parameter.\n", PROGRAM_NAME); */ + cmp_size = icu_compress_data(cfg); + if (cmp_size < 0) goto error_cleanup; + + if (model_id_str) { + uint32_t red_val; + error = atoui32("model_id", model_id_str, &red_val); + if (error || red_val > UINT16_MAX) + return -1; + model_id = (uint16_t)red_val; + } + if (model_counter_str) { + uint32_t red_val; + error = atoui32("model_counter", model_counter_str, &red_val); + if (error || red_val > UINT8_MAX) + return -1; + model_counter = (uint8_t)red_val; + } else { + if (model_mode_is_used(cfg->cmp_mode)) + model_counter = DEFAULT_MODEL_COUNTER + 1; } + s = cmp_ent_build(cmp_entity, cmp_tool_gen_version_id(CMP_TOOL_VERSION), + start_time, cmp_ent_create_timestamp(NULL), model_id, + model_counter, cfg, cmp_size); + if (!s) { + fprintf(stderr, "%s: error occurred while creating the compression entity header.\n", PROGRAM_NAME); + goto error_cleanup; + } if (include_cmp_header) { - error = add_cmp_ent_hdr(cfg, info, start_time); - if (error) - goto error_cleanup; - cmp_size_byte = cmp_ent_get_size((struct cmp_entity *)cfg->icu_output_buf); + data_to_write_to_file = cmp_entity; + cmp_size_byte = cmp_ent_get_size(cmp_entity); } else { - cmp_size_byte = cmp_bit_to_4byte(info->cmp_size); + if (cmp_gernate_rdcu_info(cfg, cmp_size, info)) + goto error_cleanup; + data_to_write_to_file = cmp_ent_get_data_buf(cmp_entity); + if (cfg->cmp_mode == CMP_MODE_RAW) + cmp_size_byte = info->cmp_size/CHAR_BIT; + else + cmp_size_byte = cmp_bit_to_4byte(info->cmp_size); } printf("DONE\n"); @@ -703,7 +782,7 @@ static int compression(struct cmp_cfg *cfg, struct cmp_info *info) } printf("Write compressed data to file %s.cmp ... ", output_prefix); - error = write_cmp_data_file(cfg->icu_output_buf, cmp_size_byte, + error = write_cmp_data_file(data_to_write_to_file, cmp_size_byte, output_prefix, ".cmp", verbose_en); if (error) goto error_cleanup; @@ -712,64 +791,68 @@ static int compression(struct cmp_cfg *cfg, struct cmp_info *info) if (!include_cmp_header) { printf("Write decompression information to file %s.info ... ", output_prefix); - error = write_info(info, output_prefix, print_rdcu_cfg); + error = write_info(info, output_prefix, add_rdcu_pars); if (error) goto error_cleanup; printf("DONE\n"); - } - if (verbose_en) { - printf("\n"); - print_cmp_info(info); - printf("\n"); + if (verbose_en) { + printf("\n"); + print_cmp_info(info); + printf("\n"); + } } - free(cfg->icu_output_buf); + free(cmp_entity); cfg->icu_output_buf = NULL; return 0; error_cleanup: - free(cfg->icu_output_buf); + free(cmp_entity); cfg->icu_output_buf = NULL; + return -1; } /* decompress the data and write the results in file(s)*/ -static int decompression(uint32_t *cmp_data_adr, uint16_t *input_model_buf, - struct cmp_info *info) +static int decompression(struct cmp_entity *ent, uint16_t *input_model_buf) { int error; + int decomp_size; uint16_t *decomp_output; printf("Decompress data ... "); - if (info->samples_used == 0) { + decomp_size = decompress_cmp_entiy(ent, input_model_buf, input_model_buf, NULL); + if (decomp_size < 0) + return -1; + if (decomp_size == 0) { printf("\nWarring: No data are decompressed.\n... "); printf("DONE\n"); return 0; } - decomp_output = malloc(cmp_cal_size_of_data(info->samples_used, - info->cmp_mode_used)); + decomp_output = malloc((size_t)decomp_size); if (decomp_output == NULL) { fprintf(stderr, "%s: Error allocating memory for decompressed data.\n", PROGRAM_NAME); return -1; } - error = decompress_data(cmp_data_adr, input_model_buf, info, - decomp_output); - if (error) { + decomp_size = decompress_cmp_entiy(ent, input_model_buf, input_model_buf, decomp_output); + if (decomp_size <= 0) { free(decomp_output); return -1; } + printf("DONE\n"); printf("Write decompressed data to file %s.dat ... ", output_prefix); - error = write_to_file16(decomp_output, info->samples_used, - output_prefix, ".dat", verbose_en); + error = write_input_data_to_file(decomp_output, (uint32_t)decomp_size, cmp_ent_get_data_type(ent), + output_prefix, ".dat", verbose_en); + free(decomp_output); if (error) return -1; diff --git a/doc/PLATO-UVIE-PL-UM-0001_0r6.pdf b/doc/PLATO-UVIE-PL-UM-0001_1r0.pdf similarity index 71% rename from doc/PLATO-UVIE-PL-UM-0001_0r6.pdf rename to doc/PLATO-UVIE-PL-UM-0001_1r0.pdf index 581a47061c76f787b75e04ccf88a5064f370704e..bc2bb546c36edbf8fcfa043a9735e321cf0597e4 100644 Binary files a/doc/PLATO-UVIE-PL-UM-0001_0r6.pdf and b/doc/PLATO-UVIE-PL-UM-0001_1r0.pdf differ diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile new file mode 100644 index 0000000000000000000000000000000000000000..5bcc6daebd49549c8f68764627e5b1331513975f --- /dev/null +++ b/doc/doxygen/Doxyfile @@ -0,0 +1,2658 @@ +# Doxyfile 1.9.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "PLATO cmp_tool" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 0.09 #TODO + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "PLATO Compression/Decompression Tool" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = "/bin/sh -c 'git log --pretty=\"format:%ci, author:%aN <%aE>, commit:%h\" -1 \"${1}\" || echo no git'" + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.l \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = customdoxygen.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = YES + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html +# #tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using JavaScript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. +# +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = ../include + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. +# The default value is: YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag UML_LOOK is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = YES + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate +# files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. +# The default value is: YES. + +DOT_CLEANUP = YES diff --git a/doc/doxygen/Doxyfile.in b/doc/doxygen/Doxyfile.in new file mode 100644 index 0000000000000000000000000000000000000000..08f1e393dfc96d96f6300a1754b7ab66993be9ee --- /dev/null +++ b/doc/doxygen/Doxyfile.in @@ -0,0 +1,2660 @@ +# Doxyfile 1.9.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "PLATO cmp_tool" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = @VERSION@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "PLATO Compression/Decompression Tool" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = NO + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = YES + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = "/bin/sh -c 'git log --pretty=\"format:%ci, author:%aN <%aE>, commit:%h\" -1 \"${1}\" || echo no git'" + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = @DOXYDIR@/DoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = @SRCDIR@ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.l \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = @BUILDDIR@ + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = images #TODO + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = NO + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = @DOXYDIR@/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = @DOXYDIR@/footer.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = @DOXYDIR@/customdoxygen.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = @DOXYDIR@/bootstrap.min.css \ + @DOXYDIR@/bootstrap.min.js \ + @DOXYDIR@/doxy-boot.js + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = YES + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html +# #tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using JavaScript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. +# +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = @SRCDIR@/include @BUILDDIR@/include + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = @HAVE_DOT@ + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a +# graph for each documented class showing the direct and indirect inheritance +# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, +# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set +# to TEXT the direct and indirect inheritance relations will be shown as texts / +# links. +# Possible values are: NO, YES, TEXT and GRAPH. +# The default value is: YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag UML_LOOK is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will wrapped across multiple lines. Some heuristics are apply +# to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = svg + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = YES + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate +# files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. +# The default value is: YES. + +DOT_CLEANUP = YES diff --git a/doc/doxygen/DoxygenLayout.xml b/doc/doxygen/DoxygenLayout.xml new file mode 100644 index 0000000000000000000000000000000000000000..7479687ef34ccb9d265a30c64f63b44943fceee6 --- /dev/null +++ b/doc/doxygen/DoxygenLayout.xml @@ -0,0 +1,194 @@ +<doxygenlayout version="1.0"> + <!-- Generated by doxygen 1.8.11 --> + <!-- Navigation index tabs for HTML output --> + <navindex> + <tab type="mainpage" visible="yes" title=""/> + <tab type="pages" visible="yes" title="" intro=""/> + <tab type="modules" visible="yes" title="" intro=""/> + <tab type="namespaces" visible="yes" title=""> + <tab type="namespacelist" visible="yes" title="" intro=""/> + <tab type="namespacemembers" visible="yes" title="" intro=""/> + </tab> + <tab type="classes" visible="yes" title=""> + <tab type="classlist" visible="yes" title="" intro=""/> + <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> + <tab type="hierarchy" visible="yes" title="" intro=""/> + <tab type="classmembers" visible="yes" title="" intro=""/> + </tab> + <tab type="files" visible="yes" title=""> + <tab type="filelist" visible="yes" title="" intro=""/> + <tab type="globals" visible="yes" title="" intro=""/> + </tab> + <tab type="examples" visible="yes" title="" intro=""/> + </navindex> + + <!-- Layout definition for a class page --> + <class> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <inheritancegraph visible="$CLASS_GRAPH"/> + <collaborationgraph visible="$COLLABORATION_GRAPH"/> + <detaileddescription title=""/> + <memberdecl> + <nestedclasses visible="yes" title=""/> + <publictypes title=""/> + <services title=""/> + <interfaces title=""/> + <publicslots title=""/> + <signals title=""/> + <publicmethods title=""/> + <publicstaticmethods title=""/> + <publicattributes title=""/> + <publicstaticattributes title=""/> + <protectedtypes title=""/> + <protectedslots title=""/> + <protectedmethods title=""/> + <protectedstaticmethods title=""/> + <protectedattributes title=""/> + <protectedstaticattributes title=""/> + <packagetypes title=""/> + <packagemethods title=""/> + <packagestaticmethods title=""/> + <packageattributes title=""/> + <packagestaticattributes title=""/> + <properties title=""/> + <events title=""/> + <privatetypes title=""/> + <privateslots title=""/> + <privatemethods title=""/> + <privatestaticmethods title=""/> + <privateattributes title=""/> + <privatestaticattributes title=""/> + <friends title=""/> + <related title="" subtitle=""/> + <membergroups visible="yes"/> + </memberdecl> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <services title=""/> + <interfaces title=""/> + <constructors title=""/> + <functions title=""/> + <related title=""/> + <variables title=""/> + <properties title=""/> + <events title=""/> + </memberdef> + <allmemberslink visible="yes"/> + <usedfiles visible="$SHOW_USED_FILES"/> + <authorsection visible="yes"/> + </class> + + <!-- Layout definition for a namespace page --> + <namespace> + <briefdescription visible="yes"/> + <detaileddescription title=""/> + <memberdecl> + <nestednamespaces visible="yes" title=""/> + <constantgroups visible="yes" title=""/> + <classes visible="yes" title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection visible="yes"/> + </namespace> + + <!-- Layout definition for a file page --> + <file> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <includegraph visible="$INCLUDE_GRAPH"/> + <includedbygraph visible="$INCLUDED_BY_GRAPH"/> + <sourcelink visible="yes"/> + <detaileddescription title=""/> + <memberdecl> + <classes visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <constantgroups visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <memberdef> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection/> + </file> + + <!-- Layout definition for a group page --> + <group> + <briefdescription visible="yes"/> + <groupgraph visible="$GROUP_GRAPHS"/> + <detaileddescription title=""/> + <memberdecl> + <nestedgroups visible="yes" title=""/> + <dirs visible="yes" title=""/> + <files visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + <membergroups visible="yes"/> + </memberdecl> + <memberdef> + <pagedocs/> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + </memberdef> + <authorsection visible="yes"/> + </group> + + <!-- Layout definition for a directory page --> + <directory> + <briefdescription visible="yes"/> + <directorygraph visible="yes"/> + <memberdecl> + <dirs visible="yes"/> + <files visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + </directory> +</doxygenlayout> diff --git a/doc/doxygen/bootstrap.min.css b/doc/doxygen/bootstrap.min.css new file mode 100644 index 0000000000000000000000000000000000000000..4cf729e4342a51d8b300e8d43f2f78b0a6faf403 --- /dev/null +++ b/doc/doxygen/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/doc/doxygen/bootstrap.min.js b/doc/doxygen/bootstrap.min.js new file mode 100644 index 0000000000000000000000000000000000000000..e79c065134f2cfcf3e44a59cffcb5f090232f98f --- /dev/null +++ b/doc/doxygen/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>2)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.6",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.6",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.6",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.6",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.6",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.6",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.6",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active"); +d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.6",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.6",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/doc/doxygen/customdoxygen.css b/doc/doxygen/customdoxygen.css new file mode 100644 index 0000000000000000000000000000000000000000..6a32ca7cc14ef237589954afbe62418891459d9e --- /dev/null +++ b/doc/doxygen/customdoxygen.css @@ -0,0 +1,306 @@ +/* +h1, .h1, h2, .h2, h3, .h3{ + font-weight: 200 !important; +} +*/ + +h1,.h1 { + font-size: 24px; +} + +h2,.h2 { + font-size: 20px; +} + +h3,.h3 { + font-size: 16px; +} + +h4,.h4 { + font-size: 14px; +} + +h5,.h5 { + font-size: 12px; +} + +h6,.h6 { + font-size: 10px; +} + + + +#navrow1, #navrow2, #navrow3, #navrow4, #navrow5{ + border-bottom: 1px solid #706d6e; +} + +.adjust-right { +margin-left: 30px !important; +font-size: 1.15em !important; +} +.navbar{ + border: 0px solid #222 !important; +} + + +/* Sticky footer styles +-------------------------------------------------- */ +html, +body { + height: 100%; + /* The html and body elements cannot have any padding or margin. */ +} + +img { +max-width:100%; +max-height:100%; +} + +/* Wrapper for page content to push down footer */ +#wrap { + min-height: 100%; + height: auto; + /* Negative indent footer by its height */ + margin: 0 auto -60px; + /* Pad bottom by footer height */ + padding: 0 0 60px; +} + +/* Set the fixed height of the footer here */ +#footer { + font-size: 0.9em; + padding: 8px 0px; + background-color: #f5f5f5; +} + +.footer-row { + line-height: 44px; +} + +#footer > .container { + padding-left: 15px; + padding-right: 15px; +} + +.footer-follow-icon { + margin-left: 3px; + text-decoration: none !important; +} + +.footer-follow-icon img { + width: 20px; +} + +.footer-link { + padding-top: 5px; + display: inline-block; + color: #999999; + text-decoration: none; +} + +.footer-copyright { + text-align: center; +} + + +@media (min-width: 992px) { + .footer-row { + text-align: left; + } + + .footer-icons { + text-align: right; + } +} +@media (max-width: 991px) { + .footer-row { + text-align: center; + } + + .footer-icons { + text-align: center; + } +} + +/* DOXYGEN Code Styles +----------------------------------- */ + + +div.ingroups { + font-size: 16pt; + width: 50%; + text-align: left; + padding-top: 10px; +} + +a.qindex { + font-size: 8pt; +} + +a.qindexHL { + font-size: 9pt; + font-weight: bold; + background-color: #9CAFD4; + color: #ffffff; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 8pt; + line-height: 125%; + font-family: monospace, fixed; +} + +div.navtab { + text-align: left; + padding-left: 5px; + margin-right: 5px; +} + +div.fragment { + padding: 4px 6px; + margin: 4px 8px 4px 2px; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +.caption { + font-weight: bold; + padding-top: 10px; + padding-bottom: 20px; +} +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + diff --git a/doc/doxygen/doxy-boot.js b/doc/doxygen/doxy-boot.js new file mode 100644 index 0000000000000000000000000000000000000000..f045d16f2b2aa6bded9165c8ad19f1a04eb3c9da --- /dev/null +++ b/doc/doxygen/doxy-boot.js @@ -0,0 +1,121 @@ +$( document ).ready(function() { + + $("div.headertitle").addClass("page-header"); + $("div.title").addClass("h1"); + + $('li > a[href="index.html"] > span').before("<i class='fa fa-cog'></i> "); + $('li > a[href="index.html"] > span').text("CHEOPS IBSW"); + $('li > a[href="modules.html"] > span').before("<i class='fa fa-square'></i> "); + $('li > a[href="namespaces.html"] > span').before("<i class='fa fa-bars'></i> "); + $('li > a[href="annotated.html"] > span').before("<i class='fa fa-list-ul'></i> "); + $('li > a[href="classes.html"] > span').before("<i class='fa fa-book'></i> "); + $('li > a[href="inherits.html"] > span').before("<i class='fa fa-sitemap'></i> "); + $('li > a[href="functions.html"] > span').before("<i class='fa fa-list'></i> "); + $('li > a[href="functions_func.html"] > span').before("<i class='fa fa-list'></i> "); + $('li > a[href="functions_vars.html"] > span').before("<i class='fa fa-list'></i> "); + $('li > a[href="functions_enum.html"] > span').before("<i class='fa fa-list'></i> "); + $('li > a[href="functions_eval.html"] > span').before("<i class='fa fa-list'></i> "); + $('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> '); + $('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> '); + + $("ul.tablist").addClass("nav nav-pills nav-justified"); + $("ul.tablist").css("margin-top", "0.5em"); + $("ul.tablist").css("margin-bottom", "0.5em"); + $("li.current").addClass("active"); + $("iframe").attr("scrolling", "yes"); + + $("#nav-path > ul").addClass("breadcrumb"); + + $("table.params").addClass("table"); + $("div.ingroups").wrapInner("<small></small>"); + $("div.levels").css("margin", "0.5em"); + $("div.levels > span").addClass("btn btn-default btn-xs"); + $("div.levels > span").css("margin-right", "0.25em"); + + $("table.directory").addClass("table table-striped"); + $("div.summary > a").addClass("btn btn-default btn-xs"); + $("table.fieldtable").addClass("table"); + $(".fragment").addClass("well"); + $(".memitem").addClass("panel panel-default"); + $(".memproto").addClass("panel-heading"); + $(".memdoc").addClass("panel-body"); + $("span.mlabel").addClass("label label-info"); + + $("table.memberdecls").addClass("table"); + $("[class^=memitem]").addClass("active"); + + $("div.ah").addClass("btn btn-default"); + $("span.mlabels").addClass("pull-right"); + $("table.mlabels").css("width", "100%") + $("td.mlabels-right").addClass("pull-right"); + + $("div.ttc").addClass("panel panel-primary"); + $("div.ttname").addClass("panel-heading"); + $("div.ttname a").css("color", 'white'); + $("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body"); + + $('#MSearchBox').parent().remove(); + + $('div.fragment.well div.line:first').css('margin-top', '15px'); + $('div.fragment.well div.line:last').css('margin-bottom', '15px'); + + $('table.doxtable').removeClass('doxtable').addClass('table table-striped table-bordered').each(function(){ + $(this).prepend('<thead></thead>'); + $(this).find('tbody > tr:first').prependTo($(this).find('thead')); + + $(this).find('td > span.success').parent().addClass('success'); + $(this).find('td > span.warning').parent().addClass('warning'); + $(this).find('td > span.danger').parent().addClass('danger'); + }); + + + + if($('div.fragment.well div.ttc').length > 0) + { + $('div.fragment.well div.line:first').parent().removeClass('fragment well'); + } + + $('table.memberdecls').find('.memItemRight').each(function(){ + $(this).contents().appendTo($(this).siblings('.memItemLeft')); + $(this).siblings('.memItemLeft').attr('align', 'left'); + }); + + function getOriginalWidthOfImg(img_element) { + var t = new Image(); + t.src = (img_element.getAttribute ? img_element.getAttribute("src") : false) || img_element.src; + return t.width; + } + + $('div.dyncontent').find('img').each(function(){ + if(getOriginalWidthOfImg($(this)[0]) > $('#content>div.container').width()) + $(this).css('width', '100%'); + }); + + $(".memitem").removeClass('memitem'); + $(".memproto").removeClass('memproto'); + $(".memdoc").removeClass('memdoc'); + $("span.mlabel").removeClass('mlabel'); + $("table.memberdecls").removeClass('memberdecls'); + $("[class^=memitem]").removeClass('memitem'); + $("span.mlabels").removeClass('mlabels'); + $("table.mlabels").removeClass('mlabels'); + $("td.mlabels-right").removeClass('mlabels-right'); + $(".navpath").removeClass('navpath'); + $("li.navelem").removeClass('navelem'); + $("a.el").removeClass('el'); + $("div.ah").removeClass('ah'); + $("div.header").removeClass("header"); + + $('.mdescLeft').each(function(){ + if($(this).html()==" ") { + $(this).siblings('.mdescRight').attr('colspan', 2); + $(this).remove(); + } + }); + $('td.memItemLeft').each(function(){ + if($(this).siblings('.memItemRight').html()=="") { + $(this).attr('colspan', 2); + $(this).siblings('.memItemRight').remove(); + } + }); +}); diff --git a/doc/doxygen/footer.html b/doc/doxygen/footer.html new file mode 100644 index 0000000000000000000000000000000000000000..f2fa20497a366600145ea79809f6250cf08f2704 --- /dev/null +++ b/doc/doxygen/footer.html @@ -0,0 +1,26 @@ +<!-- HTML footer for doxygen 1.8.8--> +<!-- start footer part --> +<!--BEGIN GENERATE_TREEVIEW--> +<div id="nav-path" class="navpath"><!-- id is needed for treeview function! --> + <ul> + $navpath + <li class="footer">$generatedby + <a href="http://www.doxygen.org/index.html"> + <img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li> + </ul> +</div> +<!--END GENERATE_TREEVIEW--> +</div> +</div> +</div> +</div> +</div> +<!--BEGIN !GENERATE_TREEVIEW--> +<hr class="footer"/><address class="footer"><small> +$generatedby  <a href="http://www.doxygen.org/index.html"> +<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/> +</a> $doxygenversion +</small></address> +<!--END !GENERATE_TREEVIEW--> +</body> +</html> diff --git a/doc/doxygen/header.html b/doc/doxygen/header.html new file mode 100644 index 0000000000000000000000000000000000000000..d4b85eb86c9df8e6cc1f10c931e7e3626d0e4cf1 --- /dev/null +++ b/doc/doxygen/header.html @@ -0,0 +1,47 @@ +<!-- HTML header for doxygen 1.8.8--> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <!-- For Mobile Devices --> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/> + <meta name="generator" content="Doxygen $doxygenversion"/> + + <script type="text/javascript" src="jquery.js"></script> + + <!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME--> + <!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME--> + <!--<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>--> + <script type="text/javascript" src="$relpath^dynsections.js"></script> + $treeview + $search + $mathjax + <link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" /> + + <link rel="stylesheet" href="$relpath^bootstrap.min.css"> + + $extrastylesheet + + <script src="$relpath^bootstrap.min.js"></script> + <script type="text/javascript" src="$relpath^doxy-boot.js"></script> + </head> + <body> + + <nav class="navbar navbar-default" role="navigation"> + <div class="container"> + <div class="navbar-header"> + <a class="navbar-brand"> + <img alt="Logo" align="left" style="margin-right: 1em;" src=$projectlogo/> + $projectname $projectnumber</a> + </div> + </div> + </nav> + <div id="top"><!-- do not remove this div, it is closed by doxygen! --> + <div class="content" id="content"> + <div class="container"> + <div class="row"> + <div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;"> + <div style="margin-bottom: 15px;"> +<!-- end header part --> diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..f7facf3ce893be7c518ec203750ea43434a88f51 --- /dev/null +++ b/doc/doxygen/meson.build @@ -0,0 +1,42 @@ +doc_layout_files = files([ + 'DoxygenLayout.xml', + 'bootstrap.min.css', + 'customdoxygen.css', + 'bootstrap.min.js', + 'doxy-boot.js', + 'header.html', + 'footer.html' +]) + + +#Build a Doxyfile based on Doxyfile.in +cdata_doc = configuration_data() +cdata_doc.set('VERSION', meson.project_version()) +cdata_doc.set('SRCDIR', meson.project_source_root()) +cdata_doc.set('DOXYDIR', meson.current_source_dir()) +cdata_doc.set('BUILDDIR', meson.project_build_root()) +if find_program('dot', required : false).found() + cdata_doc.set('HAVE_DOT', 'YES') +else + cdata_doc.set('HAVE_DOT', 'NO') +endif + +doxygen = find_program('doxygen', required : false) + +if doxygen.found() + doxy_file = configure_file( + input : 'Doxyfile.in', + output : 'Doxyfile', + configuration : cdata_doc, + install : false, + ) + + custom_target('doc', + input : doxy_file, + output : 'html', + depend_files : [doc_layout_files, main, cmplib_sources], + command : [doxygen, '@INPUT@'], + build_by_default : false, + console : true, + ) +endif diff --git a/include/cmp_data_types.h b/include/cmp_data_types.h index 345c0ae185cb488cd877daaaf6236d0b332b5d8e..41a39f7b7464a0704223408429fcec1b8eef0c78 100644 --- a/include/cmp_data_types.h +++ b/include/cmp_data_types.h @@ -14,17 +14,20 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * + * @see for N-DPU packed definition: PLATO-LESIA-PL-RP-0031 Issue: 1.9 (N-DPU->ICU data rate) + * @see for calculation of the max used bits: PLATO-LESIA-PDC-TN-0054 Issue: 1.7 * - * Three data rates: + * Three data rates (for N-DPU): * fast cadence (nominally 25s) * short cadence (nominally 50s) * long cadence (nominally 600s) * * The science products are identified as this: - * FX = normal light flux - * NCOB = normal center of brightness - * EFX = extended flux - * ECOB = extended center of brightness + * exp_flags = selected exposure flags + * fx = normal light flux + * ncob = normal center of brightness + * efx = extended flux + * ecob = extended center of brightness * The prefixes F, S and L stand for Fast, Short and Long cadence */ @@ -33,158 +36,245 @@ #include <stdint.h> -#define MODE_RAW_S_FX 100 -#define MODE_MODEL_ZERO_S_FX 101 -#define MODE_DIFF_ZERO_S_FX 102 -#define MODE_MODEL_MULTI_S_FX 103 -#define MODE_DIFF_MULTI_S_FX 104 - -#define MODE_MODEL_ZERO_S_FX_EFX 110 -#define MODE_DIFF_ZERO_S_FX_EFX 111 -#define MODE_MODEL_MULTI_S_FX_EFX 112 -#define MODE_DIFF_MULTI_S_FX_EFX 113 - -#define MODE_MODEL_ZERO_S_FX_NCOB 120 -#define MODE_DIFF_ZERO_S_FX_NCOB 121 -#define MODE_MODEL_MULTI_S_FX_NCOB 122 -#define MODE_DIFF_MULTI_S_FX_NCOB 123 - -#define MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB 130 -#define MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB 131 -#define MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB 132 -#define MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB 133 - -#define MODE_MODEL_ZERO_F_FX 140 -#define MODE_DIFF_ZERO_F_FX 141 -#define MODE_MODEL_MULTI_F_FX 142 -#define MODE_DIFF_MULTI_F_FX 143 - -#define MODE_MODEL_ZERO_F_FX_EFX 150 -#define MODE_DIFF_ZERO_F_FX_EFX 151 -#define MODE_MODEL_MULTI_F_FX_EFX 152 -#define MODE_DIFF_MULTI_F_FX_EFX 153 - -#define MODE_MODEL_ZERO_F_FX_NCOB 160 -#define MODE_DIFF_ZERO_F_FX_NCOB 161 -#define MODE_MODEL_MULTI_F_FX_NCOB 162 -#define MODE_DIFF_MULTI_F_FX_NCOB 163 - -#define MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB 170 -#define MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB 171 -#define MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB 172 -#define MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB 173 - -#define MODE_RAW_32 200 -#define MODE_DIFF_ZERO_32 201 -#define MODE_DIFF_MULTI_32 202 -#define MODE_MODEL_ZERO_32 203 -#define MODE_MODEL_MULTI_32 204 - -int lossy_rounding_16(uint16_t *data_buf, unsigned int samples, unsigned int - round); -int de_lossy_rounding_16(uint16_t *data_buf, uint32_t samples_used, uint32_t - round_used); - -int lossy_rounding_32(uint32_t *data_buf, unsigned int samples, unsigned int - round); -int de_lossy_rounding_32(uint32_t *data_buf, uint32_t samples_used, uint32_t - round_used); - -/* @see PLATO-LESIA-PL-RP-0031 Issue: 1.9 (N-DPU->ICU data rate) */ -struct __attribute__((packed)) S_FX { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; +#include <compiler.h> +#include <cmp_support.h> + +#define MAX_USED_NC_IMAGETTE_BITS 16 +#define MAX_USED_SATURATED_IMAGETTE_BITS 16 /* TBC */ +#define MAX_USED_FC_IMAGETTE_BITS 16 /* TBC */ + +#define MAX_USED_F_FX_BITS 21 /* max exp. int value: (1.078*10^5)/0.1 = 1,078,000 -> 21 bits */ +#define MAX_USED_F_EFX_BITS MAX_USED_F_FX_BITS /* we use the same as f_fx */ +#define MAX_USED_F_NCOB_BITS 20 /* max exp. int value: 6/10^−5 = 6*10^5 -> 20 bits */ +#define MAX_USED_F_ECOB_BITS 32 /* TBC */ + +#define MAX_USED_S_FX_EXPOSURE_FLAGS_BITS 2 /* 2 flags + 6 spare bits */ +#define MAX_USED_S_FX_BITS 24 /* max exp. int value: (1.078*10^5-34.71)/0.01 = 10,780,000-> 24 bits */ +#define MAX_USED_S_EFX_BITS MAX_USED_S_FX_BITS /* we use the same as s_fx */ +#define MAX_USED_S_NCOB_BITS MAX_USED_F_NCOB_BITS +#define MAX_USED_S_ECOB_BITS 32 /* TBC */ + +#define MAX_USED_L_FX_EXPOSURE_FLAGS_BITS 24 /* 24 flags */ +#define MAX_USED_L_FX_BITS MAX_USED_S_FX_BITS +#define MAX_USED_L_FX_VARIANCE_BITS 32 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */ +#define MAX_USED_L_EFX_BITS MAX_USED_L_FX_BITS /* we use the same as l_fx */ +#define MAX_USED_L_NCOB_BITS MAX_USED_F_NCOB_BITS +#define MAX_USED_L_ECOB_BITS 32 /* TBC */ +#define MAX_USED_L_COB_VARIANCE_BITS 25 /* max exp int value: 0.1739/10^−8 = 17390000 -> 25 bits */ + +#define MAX_USED_NC_OFFSET_MEAN_BITS 2 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */ +#define MAX_USED_NC_OFFSET_VARIANCE_BITS 10 /* max exp. int value: 9.31/0.01 = 931 -> 10 bits */ + +#define MAX_USED_NC_BACKGROUND_MEAN_BITS 16 /* max exp. int value: (391.8-(-50))/0.01 = 44,180 -> 16 bits */ +#define MAX_USED_NC_BACKGROUND_VARIANCE_BITS 16 /* max exp. int value: 6471/0.1 = 64710 -> 16 bit */ +#define MAX_USED_NC_BACKGROUND_OUTLIER_PIXELS_BITS 5 /* maximum = 16 -> 5 bits */ + +#define MAX_USED_SMEARING_MEAN_BITS 15 /* max exp. int value: (219.9 - -50)/0.01 = 26.990 */ +#define MAX_USED_SMEARING_VARIANCE_MEAN_BITS 16 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */ +#define MAX_USED_SMEARING_OUTLIER_PIXELS_BITS 11 /* maximum = 1200 -> 11 bits */ + +#define MAX_USED_FC_OFFSET_MEAN_BITS 32 /* no maximum value is given in PLATO-LESIA-PDC-TN-0054 */ +#define MAX_USED_FC_OFFSET_VARIANCE_BITS 9 /* max exp. int value: 342/1 = 342 -> 9 bits */ +#define MAX_USED_FC_OFFSET_PIXEL_IN_ERROR_BITS 16 /* TBC */ + +#define MAX_USED_FC_BACKGROUND_MEAN_BITS 10 /* max exp. int value: (35.76-(-50))/0.1 = 858 -> 10 bits*/ +#define MAX_USED_FC_BACKGROUND_VARIANCE_BITS 6 /* max exp. int value: 53.9/1 = 54 -> 6 bits */ +#define MAX_USED_FC_BACKGROUND_OUTLIER_PIXELS_BITS 16 /* TBC */ + + +/* struct holding the maximum length of the different data products types in bits */ +struct cmp_max_used_bits { + uint8_t version; + unsigned int s_exp_flags; + unsigned int s_fx; + unsigned int s_efx; + unsigned int s_ncob; /* s_ncob_x and s_ncob_y */ + unsigned int s_ecob; /* s_ecob_x and s_ncob_y */ + unsigned int f_fx; + unsigned int f_efx; + unsigned int f_ncob; /* f_ncob_x and f_ncob_y */ + unsigned int f_ecob; /* f_ecob_x and f_ncob_y */ + unsigned int l_exp_flags; + unsigned int l_fx; + unsigned int l_fx_variance; + unsigned int l_efx; + unsigned int l_ncob; /* l_ncob_x and l_ncob_y */ + unsigned int l_ecob; /* l_ecob_x and l_ncob_y */ + unsigned int l_cob_variance; /* l_cob_x_variance and l_cob_y_variance */ + unsigned int nc_imagette; + unsigned int saturated_imagette; + unsigned int nc_offset_mean; + unsigned int nc_offset_variance; + unsigned int nc_background_mean; + unsigned int nc_background_variance; + unsigned int nc_background_outlier_pixels; + unsigned int smearing_mean; + unsigned int smearing_variance_mean; + unsigned int smearing_outlier_pixels; + unsigned int fc_imagette; + unsigned int fc_offset_mean; + unsigned int fc_offset_variance; + unsigned int fc_offset_pixel_in_error; + unsigned int fc_background_mean; + unsigned int fc_background_variance; + unsigned int fc_background_outlier_pixels; }; -struct S_FX sub_S_FX(struct S_FX a, struct S_FX b); -struct S_FX add_S_FX(struct S_FX a, struct S_FX b); -int lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples, - unsigned int round); -int de_lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples_used, - unsigned int round_used); -struct S_FX cal_up_model_S_FX(struct S_FX data_buf, struct S_FX model_buf, - unsigned int model_value); - - -struct S_FX_EFX { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; - uint32_t EFX; -}__attribute__((packed)); - -struct S_FX_EFX sub_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b); -struct S_FX_EFX add_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b); -int lossy_rounding_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples, - unsigned int round); -int de_lossy_rounding_S_FX_EFX(struct S_FX_EFX *data_buf, unsigned int - samples_used, unsigned int round_used); -struct S_FX_EFX cal_up_model_S_FX_EFX(struct S_FX_EFX data_buf, struct S_FX_EFX - model_buf, unsigned int model_value); - - -struct S_FX_NCOB { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; - uint32_t NCOB_X; - uint32_t NCOB_Y; -}__attribute__((packed)); - -struct S_FX_NCOB sub_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b); -struct S_FX_NCOB add_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b); -int lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int samples, - unsigned int round); -int de_lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int - samples_used, unsigned int round_used); -struct S_FX_NCOB cal_up_model_S_FX_NCOB(struct S_FX_NCOB data_buf, struct - S_FX_NCOB model_buf, unsigned int - model_value); - - -struct S_FX_EFX_NCOB_ECOB { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; - uint32_t NCOB_X; - uint32_t NCOB_Y; - uint32_t EFX; - uint32_t ECOB_X; - uint32_t ECOB_Y; -}__attribute__((packed)); - -struct S_FX_EFX_NCOB_ECOB sub_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a, - struct S_FX_EFX_NCOB_ECOB b); -struct S_FX_EFX_NCOB_ECOB add_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a, - struct S_FX_EFX_NCOB_ECOB b); -int lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - unsigned int samples, unsigned int round); -int de_lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - unsigned int samples, - unsigned int round); - -struct F_FX { - uint32_t FX; -}__attribute__((packed)); - - -struct F_FX_EFX { - uint32_t FX; - uint32_t EFX; -}__attribute__((packed)); - - -struct F_FX_NCOB { - uint32_t FX; - uint32_t NCOB_X; - uint32_t NCOB_Y; -}__attribute__((packed)); - - -struct F_FX_EFX_NCOB_ECOB { - uint32_t FX; - uint32_t NCOB_X; - uint32_t NCOB_Y; - uint32_t EFX; - uint32_t ECOB_X; - uint32_t ECOB_Y; -}__attribute__((packed)); + +/* Set and read the max_used_bits, which specify how many bits are needed to + * represent the highest possible value. + */ +void cmp_set_max_used_bits(const struct cmp_max_used_bits *set_max_used_bits); +struct cmp_max_used_bits cmp_get_max_used_bits(void); + +uint8_t cmp_get_max_used_bits_version(void); + + +/* Source data header structure for multi entry packet */ +#define MULTI_ENTRY_HDR_SIZE 12 +compile_time_assert(MULTI_ENTRY_HDR_SIZE % sizeof(uint32_t) == 0, N_DPU_ICU_MULTI_ENTRY_HDR_NOT_4_BYTE_ALLIED); + +__extension__ +struct multi_entry_hdr { + uint32_t timestamp_coarse; + uint16_t timestamp_fine; + uint16_t configuration_id; + uint16_t collection_id; + uint16_t collection_length; + uint8_t entry[]; +} __attribute__((packed)); +compile_time_assert(sizeof(struct multi_entry_hdr) == MULTI_ENTRY_HDR_SIZE, N_DPU_ICU_MULTI_ENTRY_HDR_SIZE_IS_NOT_CORRECT); + + +struct s_fx { + uint8_t exp_flags; /* selected exposure flags (2 flags + 6 spare bits) */ + uint32_t fx; /* normal light flux */ +} __attribute__((packed)); + + +struct s_fx_efx { + uint8_t exp_flags; + uint32_t fx; + uint32_t efx; +} __attribute__((packed)); + + +struct s_fx_ncob { + uint8_t exp_flags; + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; +} __attribute__((packed)); + + +struct s_fx_efx_ncob_ecob { + uint8_t exp_flags; + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; + uint32_t efx; + uint32_t ecob_x; + uint32_t ecob_y; +} __attribute__((packed)); + + +struct f_fx { + uint32_t fx; +} __attribute__((packed)); + + +struct f_fx_efx { + uint32_t fx; + uint32_t efx; +} __attribute__((packed)); + + +struct f_fx_ncob { + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; +} __attribute__((packed)); + + +struct f_fx_efx_ncob_ecob { + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; + uint32_t efx; + uint32_t ecob_x; + uint32_t ecob_y; +} __attribute__((packed)); + + +__extension__ +struct l_fx { + uint32_t exp_flags:24; /* selected exposure flags (24 flags) */ + uint32_t fx; + uint32_t fx_variance; +} __attribute__((packed)); + + +__extension__ +struct l_fx_efx { + uint32_t exp_flags:24; /* selected exposure flags (24 flags) */ + uint32_t fx; + uint32_t efx; + uint32_t fx_variance; +} __attribute__((packed)); + + +__extension__ +struct l_fx_ncob { + uint32_t exp_flags:24; /* selected exposure flags (24 flags) */ + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; + uint32_t fx_variance; + uint32_t cob_x_variance; + uint32_t cob_y_variance; +} __attribute__((packed)); + + +__extension__ +struct l_fx_efx_ncob_ecob { + uint32_t exp_flags:24; /* selected exposure flags (24 flags) */ + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; + uint32_t efx; + uint32_t ecob_x; + uint32_t ecob_y; + uint32_t fx_variance; + uint32_t cob_x_variance; + uint32_t cob_y_variance; +} __attribute__((packed)); + + +struct nc_offset { + uint32_t mean; + uint32_t variance; +} __attribute__((packed)); + + +struct nc_background { + uint32_t mean; + uint32_t variance; + uint16_t outlier_pixels; +} __attribute__((packed)); + + +struct smearing { + uint32_t mean; + uint16_t variance_mean; + uint16_t outlier_pixels; +} __attribute__((packed)); + + +size_t size_of_a_sample(enum cmp_data_type data_type); +unsigned int cmp_cal_size_of_data(unsigned int samples, enum cmp_data_type data_type); +int cmp_input_size_to_samples(unsigned int size, enum cmp_data_type data_type); + +int cmp_input_big_to_cpu_endianness(void *data, uint32_t data_size_byte, + enum cmp_data_type data_type); #endif /* CMP_DATA_TYPE_H */ diff --git a/include/cmp_entity.h b/include/cmp_entity.h index 2d6bf542f1ec5b0c25f63fd257a2c3fbb325f78d..c56cef5dd37705ac618266443e0a329f01175308 100644 --- a/include/cmp_entity.h +++ b/include/cmp_entity.h @@ -29,37 +29,9 @@ #include <stdint.h> -#include "compiler.h" -#include "cmp_support.h" - - -/* Defined Compression Data Product Types */ -enum cmp_ent_data_type { - DATA_TYPE_IMAGETTE = 1, - DATA_TYPE_IMAGETTE_ADAPTIVE, - DATA_TYPE_SAT_IMAGETTE, - DATA_TYPE_SAT_IMAGETTE_ADAPTIVE, - DATA_TYPE_OFFSET, - DATA_TYPE_BACKGROUND, - DATA_TYPE_SMEARING, - DATA_TYPE_S_FX, - DATA_TYPE_S_FX_DFX, - DATA_TYPE_S_FX_NCOB, - DATA_TYPE_S_FX_DFX_NCOB_ECOB, - DATA_TYPE_L_FX, - DATA_TYPE_L_FX_DFX, - DATA_TYPE_L_FX_NCOB, - DATA_TYPE_L_FX_DFX_NCOB_ECOB, - DATA_TYPE_F_FX, - DATA_TYPE_F_FX_DFX, - DATA_TYPE_F_FX_NCOB, - DATA_TYPE_F_FX_DFX_NCOB_ECOB, - DATA_TYPE_F_CAM_IMAGETTE, - DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE, - DATA_TYPE_F_CAM_OFFSET, - DATA_TYPE_F_CAM_BACKGROUND, - DATA_TYPE_UNKOWN = 0x7FFF, -}; +#include <compiler.h> +#include <cmp_support.h> + #define GENERIC_HEADER_SIZE 32 #define SPECIFIC_IMAGETTE_HEADER_SIZE 4 @@ -144,7 +116,7 @@ struct cmp_entity { uint8_t model_value_used; /* used Model Updating Weighing Value */ uint16_t model_id; /* Model ID */ uint8_t model_counter; /* Model Counter */ - uint8_t spare; + uint8_t max_used_bits_version; uint16_t lossy_cmp_par_used; /* used Lossy Compression Parameters */ union { /* specific Compression Entity Header for the different Data Product Types */ struct imagette_header ima; @@ -155,21 +127,31 @@ compile_time_assert(sizeof(struct cmp_entity) == NON_IMAGETTE_HEADER_SIZE, CMP_E -/* brief create a compression entity by setting the size of the - * compression entity and the data product type in the entity header +/* create a compression entity by setting the size of the compression entity and + * the data product type in the entity header */ -size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type, - uint32_t cmp_size_byte); +uint32_t cmp_ent_create(struct cmp_entity *ent, enum cmp_data_type data_type, + int raw_mode_flag, uint32_t cmp_size_byte); /* create a compression entity and set the header fields */ -size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type, - uint32_t version_id, uint64_t start_time, - uint64_t end_time, uint16_t model_id, uint8_t model_counter, - struct cmp_info *info, struct cmp_cfg *cfg); +size_t cmp_ent_build(struct cmp_entity *ent, uint32_t version_id, + uint64_t start_time, uint64_t end_time, uint16_t model_id, + uint8_t model_counter, struct cmp_cfg *cfg, int cmp_size_bits); + +/* read in a compression entity header */ +int cmp_ent_read_header(struct cmp_entity *ent, struct cmp_cfg *cfg); -/* read in a imagette compression entity header to a info struct */ -int cmp_ent_read_imagette_header(struct cmp_entity *ent, struct cmp_info *info); +/* write the compression parameters from a compression configuration into the + * compression entity header + */ +int cmp_ent_write_cmp_pars(struct cmp_entity *ent, const struct cmp_cfg *cfg, + int cmp_size_bits); +/* write the parameters from the RDCU decompression information structure in the + * compression entity header + */ +int cmp_ent_write_rdcu_cmp_pars(struct cmp_entity *ent, const struct cmp_info *info, + const struct cmp_cfg *cfg); /* set functions for generic compression entity header */ @@ -187,12 +169,12 @@ int cmp_ent_set_coarse_end_time(struct cmp_entity *ent, uint32_t coarse_time); int cmp_ent_set_fine_end_time(struct cmp_entity *ent, uint16_t fine_time); int cmp_ent_set_data_type(struct cmp_entity *ent, - enum cmp_ent_data_type data_type); -int cmp_ent_data_type_valid(enum cmp_ent_data_type data_type); + enum cmp_data_type data_type, int raw_mode); int cmp_ent_set_cmp_mode(struct cmp_entity *ent, uint32_t cmp_mode_used); int cmp_ent_set_model_value(struct cmp_entity *ent, uint32_t model_value_used); int cmp_ent_set_model_id(struct cmp_entity *ent, uint32_t model_id); int cmp_ent_set_model_counter(struct cmp_entity *ent, uint32_t model_counter); +int cmp_ent_set_max_used_bits_version(struct cmp_entity *ent, uint8_t max_used_bits_version); int cmp_ent_set_lossy_cmp_par(struct cmp_entity *ent, uint32_t lossy_cmp_par_used); @@ -247,13 +229,14 @@ uint64_t cmp_ent_get_end_timestamp(struct cmp_entity *ent); uint32_t cmp_ent_get_coarse_end_time(struct cmp_entity *ent); uint16_t cmp_ent_get_fine_end_time(struct cmp_entity *ent); -enum cmp_ent_data_type cmp_ent_get_data_type(struct cmp_entity *ent); +enum cmp_data_type cmp_ent_get_data_type(struct cmp_entity *ent); int cmp_ent_get_data_type_raw_bit(struct cmp_entity *ent); uint8_t cmp_ent_get_cmp_mode(struct cmp_entity *ent); uint8_t cmp_ent_get_model_value_used(struct cmp_entity *ent); uint16_t cmp_ent_get_model_id(struct cmp_entity *ent); uint8_t cmp_ent_get_model_counter(struct cmp_entity *ent); +uint8_t cmp_ent_get_max_used_bits_version(struct cmp_entity *ent); uint16_t cmp_ent_get_lossy_cmp_par(struct cmp_entity *ent); @@ -301,14 +284,16 @@ ssize_t cmp_ent_get_cmp_data(struct cmp_entity *ent, uint32_t *data_buf, size_t data_buf_size); /* calculate the size of the compression entity header */ -uint32_t cmp_ent_cal_hdr_size(enum cmp_ent_data_type data_type); +uint32_t cmp_ent_cal_hdr_size(enum cmp_data_type data_type, int raw_mode); -#if __has_include(<time.h>) -#include <time.h> +#if defined __has_include +# if __has_include(<time.h>) +# include <time.h> /* create a timestamp for the compression header */ extern const struct tm EPOCH_DATE; uint64_t cmp_ent_create_timestamp(const struct timespec *ts); +# endif #endif /* print and parse functions */ diff --git a/include/cmp_guess.h b/include/cmp_guess.h index fe2ed0989a6b8ab188c92a33cb0b43a3ba2414e1..4b26e9cae965aa0aceea4e12fce0cf0549607939 100644 --- a/include/cmp_guess.h +++ b/include/cmp_guess.h @@ -20,19 +20,24 @@ #ifndef CMP_GUESS_H #define CMP_GUESS_H -#include "cmp_support.h" +#include <cmp_support.h> + #define DEFAULT_GUESS_LEVEL 2 -#define CMP_GUESS_DEF_MODE_DIFF MODE_DIFF_ZERO -#define CMP_GUESS_DEF_MODE_MODEL MODE_MODEL_MULTI +#define CMP_GUESS_DEF_MODE_DIFF CMP_MODE_DIFF_ZERO +#define CMP_GUESS_DEF_MODE_MODEL CMP_MODE_MODEL_MULTI +/* good guess for the spill parameter using the MODE_DIFF_MULTI */ +#define CMP_GOOD_SPILL_DIFF_MULTI 2U /* how often the model is updated before it is reset default value */ #define CMP_GUESS_N_MODEL_UPDATE_DEF 8 uint32_t cmp_guess(struct cmp_cfg *cfg, int level); void cmp_guess_set_model_updates(int n_model_updates); +uint32_t cmp_rdcu_get_good_spill(unsigned int golomb_par, enum cmp_mode cmp_mode); + uint16_t cmp_guess_model_value(int n_model_updates); #endif /* CMP_GUESS_H */ diff --git a/include/cmp_icu.h b/include/cmp_icu.h index cd7f193e10ba3e6b89a863c1f259d948f7c0ce8f..743e7d1014b93b162f8d216da25435047e97069a 100644 --- a/include/cmp_icu.h +++ b/include/cmp_icu.h @@ -13,7 +13,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * * @brief software compression library * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001 */ @@ -21,13 +20,37 @@ #ifndef _CMP_ICU_H_ #define _CMP_ICU_H_ -#include "../include/cmp_support.h" +#include <cmp_support.h> + +#define CMP_PAR_UNUSED 0 + +/* create and setup a compression configuration */ +struct cmp_cfg cmp_cfg_icu_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode, + uint32_t model_value, uint32_t lossy_par); + +uint32_t cmp_cfg_icu_buffers(struct cmp_cfg *cfg, void *data_to_compress, + uint32_t data_samples, void *model_of_data, + void *updated_model, uint32_t *compressed_data, + uint32_t compressed_data_len_samples); + +int cmp_cfg_icu_imagette(struct cmp_cfg *cfg, uint32_t cmp_par, + uint32_t spillover_par); + +int cmp_cfg_fx_cob(struct cmp_cfg *cfg, + uint32_t cmp_par_exp_flags, uint32_t spillover_exp_flags, + uint32_t cmp_par_fx, uint32_t spillover_fx, + uint32_t cmp_par_ncob, uint32_t spillover_ncob, + uint32_t cmp_par_efx, uint32_t spillover_efx, + uint32_t cmp_par_ecob, uint32_t spillover_ecob, + uint32_t cmp_par_fx_cob_variance, uint32_t spillover_fx_cob_variance); -int icu_compress_data(struct cmp_cfg *cfg, struct cmp_info *info); +int cmp_cfg_aux(struct cmp_cfg *cfg, + uint32_t cmp_par_mean, uint32_t spillover_mean, + uint32_t cmp_par_variance, uint32_t spillover_variance, + uint32_t cmp_par_pixels_error, uint32_t spillover_pixels_error); -int cmp_pre_process(struct cmp_cfg *cfg); -int cmp_map_to_pos(struct cmp_cfg *cfg); -uint32_t cmp_encode_data(struct cmp_cfg *cfg); +/* start the compression */ +int icu_compress_data(const struct cmp_cfg *cfg); #endif /* _CMP_ICU_H_ */ diff --git a/include/cmp_io.h b/include/cmp_io.h index 77dce35b4f571b485267a8fae2ed74b726c38f2b..873bf91652f6c03fa049d9db16b6642eca63640c 100644 --- a/include/cmp_io.h +++ b/include/cmp_io.h @@ -17,10 +17,9 @@ #include <string.h> -#include "cmp_support.h" -#include "cmp_entity.h" +#include <cmp_support.h> +#include <cmp_entity.h> -#define PROGRAM_NAME "cmp_tool" #define MAX_CONFIG_LINE 256 #define DEFAULT_OUTPUT_PREFIX "OUTPUT" @@ -32,21 +31,21 @@ void print_help(const char *program_name); int read_cmp_cfg(const char *file_name, struct cmp_cfg *cfg, int verbose_en); int read_cmp_info(const char *file_name, struct cmp_info *info, int verbose_en); -ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, +ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, int verbose_en); -ssize_t read_file16(const char *file_name, uint16_t *buf, uint32_t samples, - int verbose_en); -ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t samples, - int verbose_en); +ssize_t read_file_data(const char *file_name, enum cmp_data_type data_type, + void *buf, uint32_t buf_size, int verbose_en); ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent, - uint32_t ent_size, int verbose_en); + uint32_t ent_size, int verbose_en); +ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t buf_size, + int verbose_en); uint32_t cmp_tool_gen_version_id(const char *version); int write_cmp_data_file(const void *buf, uint32_t buf_size, const char *output_prefix, const char *name_extension, int verbose); -int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char - *output_prefix, const char *name_extension, int verbose); +int write_input_data_to_file(void *data, uint32_t data_size, enum cmp_data_type data_type, + const char *output_prefix, const char *name_extension, int verbose); int write_info(const struct cmp_info *info, const char *output_prefix, int rdcu_cfg); int write_cfg(const struct cmp_cfg *cfg, const char *output_prefix, int rdcu_cfg, @@ -55,3 +54,6 @@ void print_cfg(const struct cmp_cfg *cfg, int rdcu_cfg); int atoui32(const char *dep_str, const char *val_str, uint32_t *red_val); int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode); + +enum cmp_data_type string2data_type(const char *data_type_str); +const char *data_type2string(enum cmp_data_type data_type); diff --git a/include/cmp_rdcu.h b/include/cmp_rdcu.h index ee5cffb908fe59d8df033b4d44abbdc20815276b..93da3d06a62f51cac7eee52a4c665d4fdc964b0f 100644 --- a/include/cmp_rdcu.h +++ b/include/cmp_rdcu.h @@ -21,23 +21,47 @@ #ifndef _CMP_RDCU_H_ #define _CMP_RDCU_H_ -#include <stdint.h> -#include "../include/cmp_support.h" +#include <cmp_support.h> +/* Compression Error Register bits definition, see RDCU-FRS-FN-0952 */ +#define SMALL_BUFFER_ERR_BIT 0x00 /* The length for the compressed data buffer is too small */ +#define CMP_MODE_ERR_BIT 0x01 /* The cmp_mode parameter is not set correctly */ +#define MODEL_VALUE_ERR_BIT 0x02 /* The model_value parameter is not set correctly */ +#define CMP_PAR_ERR_BIT 0x03 /* The spill, golomb_par combination is not set correctly */ +#define AP1_CMP_PAR_ERR_BIT 0x04 /* The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression) */ +#define AP2_CMP_PAR_ERR_BIT 0x05 /* The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression) */ +#define MB_ERR_BIT 0x06 /* Multi bit error detected by the memory controller (only HW compression) */ +#define SLAVE_BUSY_ERR_BIT 0x07 /* The bus master has received the "slave busy" status (only HW compression) */ + + +struct cmp_cfg rdcu_cfg_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode, + uint32_t model_value, uint32_t lossy_par); +int rdcu_cfg_buffers(struct cmp_cfg *cfg, uint16_t *data_to_compress, + uint32_t data_samples, uint16_t *model_of_data, + uint32_t rdcu_data_adr, uint32_t rdcu_model_adr, + uint32_t rdcu_new_model_adr, uint32_t rdcu_buffer_adr, + uint32_t rdcu_buffer_lenght); +int rdcu_cfg_imagette(struct cmp_cfg *cfg, + uint32_t golomb_par, uint32_t spillover_par, + uint32_t ap1_golomb_par, uint32_t ap1_spillover_par, + uint32_t ap2_golomb_par, uint32_t ap2_spillover_par); + int rdcu_compress_data(const struct cmp_cfg *cfg); int rdcu_read_cmp_status(struct cmp_status *status); int rdcu_read_cmp_info(struct cmp_info *info); -int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf); +int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *compressed_data); -int rdcu_read_model(const struct cmp_info *info, void *model_buf); +int rdcu_read_model(const struct cmp_info *info, void *updated_model); int rdcu_interrupt_compression(void); void rdcu_enable_interrput_signal(void); void rdcu_disable_interrput_signal(void); +int rdcu_cmp_cfg_is_invalid(const struct cmp_cfg *cfg); + #endif /* _CMP_RDCU_H_ */ diff --git a/include/cmp_rdcu_extended.h b/include/cmp_rdcu_extended.h index a4f33e030549419ca1e120bcc4a2a77b2d092532..7ab229b5fd1df7519651916d55f1192cae877788 100644 --- a/include/cmp_rdcu_extended.h +++ b/include/cmp_rdcu_extended.h @@ -18,7 +18,7 @@ #ifndef _CMP_RDCU_EXTENDED_H_ #define _CMP_RDCU_EXTENDED_H_ -#include "../include/cmp_rdcu.h" +#include <cmp_rdcu.h> int rdcu_start_compression(void); diff --git a/include/cmp_support.h b/include/cmp_support.h index 0c1c90f6288c733d6c9db4c51f99b0b5e09d4c26..be598aaff62471c10e5aa595a8c3725e48432a74 100644 --- a/include/cmp_support.h +++ b/include/cmp_support.h @@ -23,97 +23,175 @@ #include <stddef.h> -#define GOLOMB_PAR_EXPOSURE_FLAGS 1 - -/* Compression Error Register bits definition, see RDCU-FRS-FN-0952 */ -#define SMALL_BUFFER_ERR_BIT 0x00 /* The length for the compressed data buffer is too small */ -#define CMP_MODE_ERR_BIT 0x01 /* The cmp_mode parameter is not set correctly */ -#define MODEL_VALUE_ERR_BIT 0x02 /* The model_value parameter is not set correctly */ -#define CMP_PAR_ERR_BIT 0x03 /* The spill, golomb_par combination is not set correctly */ -#define AP1_CMP_PAR_ERR_BIT 0x04 /* The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression) */ -#define AP2_CMP_PAR_ERR_BIT 0x05 /* The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression) */ -#define MB_ERR_BIT 0x06 /* Multi bit error detected by the memory controller (only HW compression) */ -#define SLAVE_BUSY_ERR_BIT 0x07 /* The bus master has received the "slave busy" status (only HW compression) */ - -#define MODE_RAW 0 -#define MODE_MODEL_ZERO 1 -#define MODE_DIFF_ZERO 2 -#define MODE_MODEL_MULTI 3 -#define MODE_DIFF_MULTI 4 +/* return code if the bitstream buffer is too small to store the whole bitstream */ +#define CMP_ERROR_SMALL_BUF -2 + +/* return code if the value or the model is bigger than the max_used_bits + * parameter allows + */ +#define CMP_ERROR_HIGH_VALUE -3 + +#define CMP_LOSSLESS 0 +#define CMP_PAR_UNUNSED 0 + #define MAX_MODEL_VALUE \ - 16UL /* the maximal model values used in the update equation for the new model */ + 16U /* the maximal model values used in the update equation for the new model */ -/* valid compression parameter ranges for RDCU compression according to PLATO-UVIE-PL-UM-0001 */ -#define MAX_RDCU_CMP_MODE 4UL -#define MIN_RDCU_GOLOMB_PAR 1UL -#define MAX_RDCU_GOLOMB_PAR 63UL -#define MIN_RDCU_SPILL 2UL -#define MAX_RDCU_ROUND 2UL -/* for maximum spill value look at get_max_spill function */ +/* valid compression parameter ranges for RDCU/ICU imagette compression according to PLATO-UVIE-PL-UM-0001 */ +#define MAX_RDCU_CMP_MODE 4U +#define MIN_IMA_GOLOMB_PAR 1U +#define MAX_IMA_GOLOMB_PAR 63U +#define MIN_IMA_SPILL 2U +#define MAX_RDCU_ROUND 2U +/* for maximum spill value look at cmp_rdcu_max_spill function */ /* valid compression parameter ranges for ICU compression */ -#define MIN_ICU_GOLOMB_PAR 1UL -#define MAX_ICU_GOLOMB_PAR UINT32_MAX -#define MIN_ICU_SPILL 2UL -/* for maximum spill value look at get_max_spill function */ -#define MAX_ICU_ROUND 3UL +#define MIN_ICU_GOLOMB_PAR 1U +#define MAX_ICU_GOLOMB_PAR UINT16_MAX /* the compression entity dos not allow larger values */ +#define MIN_ICU_SPILL 2U +/* for maximum spill value look at cmp_icu_max_spill function */ +#define MAX_ICU_ROUND 3U +#define MAX_STUFF_CMP_PAR 32U + + +/* default imagette RDCU compression parameters for model compression */ +#define CMP_DEF_IMA_MODEL_DATA_TYPE DATA_TYPE_IMAGETTE +#define CMP_DEF_IMA_MODEL_CMP_MODE CMP_MODE_MODEL_MULTI +#define CMP_DEF_IMA_MODEL_MODEL_VALUE 8 +#define CMP_DEF_IMA_MODEL_LOSSY_PAR 0 + +#define CMP_DEF_IMA_MODEL_GOLOMB_PAR 4 +#define CMP_DEF_IMA_MODEL_SPILL_PAR 48 +#define CMP_DEF_IMA_MODEL_AP1_GOLOMB_PAR 3 +#define CMP_DEF_IMA_MODEL_AP1_SPILL_PAR 35 +#define CMP_DEF_IMA_MODEL_AP2_GOLOMB_PAR 5 +#define CMP_DEF_IMA_MODEL_AP2_SPILL_PAR 60 + +#define CMP_DEF_IMA_MODEL_RDCU_DATA_ADR 0x000000 +#define CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR 0x200000 +#define CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR 0x400000 +#define CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR 0x600000 + +/* default imagette RDCU compression parameters for 1d-differencing compression */ +#define CMP_DEF_IMA_DIFF_DATA_TYPE DATA_TYPE_IMAGETTE +#define CMP_DEF_IMA_DIFF_CMP_MODE CMP_MODE_DIFF_ZERO +#define CMP_DEF_IMA_DIFF_MODEL_VALUE 8 /* not needed for 1d-differencing cmp_mode */ +#define CMP_DEF_IMA_DIFF_LOSSY_PAR 0 + +#define CMP_DEF_IMA_DIFF_GOLOMB_PAR 7 +#define CMP_DEF_IMA_DIFF_SPILL_PAR 60 +#define CMP_DEF_IMA_DIFF_AP1_GOLOMB_PAR 6 +#define CMP_DEF_IMA_DIFF_AP1_SPILL_PAR 48 +#define CMP_DEF_IMA_DIFF_AP2_GOLOMB_PAR 8 +#define CMP_DEF_IMA_DIFF_AP2_SPILL_PAR 72 + +#define CMP_DEF_IMA_DIFF_RDCU_DATA_ADR 0x000000 +#define CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR 0x000000 /* not needed for 1d-differencing cmp_mode */ +#define CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR 0x000000 /* not needed for 1d-differencing cmp_mode */ +#define CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR 0x600000 + +enum {ICU_CHECK, RDCU_CHECK}; /* option for the cmp_cfg_imagette_is_invalid() function */ -#define SAM2BYT \ - 2 /* sample to byte conversion factor; one samples has 16 bits (2 bytes) */ -#define CMP_GOOD_SPILL_DIFF_MULTI 2 /* good guess for the spill parameter using the MODE_DIFF_MULTI */ +/* defined compression data product types */ +enum cmp_data_type { + DATA_TYPE_UNKNOWN, + DATA_TYPE_IMAGETTE, + DATA_TYPE_IMAGETTE_ADAPTIVE, + DATA_TYPE_SAT_IMAGETTE, + DATA_TYPE_SAT_IMAGETTE_ADAPTIVE, + DATA_TYPE_OFFSET, + DATA_TYPE_BACKGROUND, + DATA_TYPE_SMEARING, + DATA_TYPE_S_FX, + DATA_TYPE_S_FX_EFX, + DATA_TYPE_S_FX_NCOB, + DATA_TYPE_S_FX_EFX_NCOB_ECOB, + DATA_TYPE_L_FX, + DATA_TYPE_L_FX_EFX, + DATA_TYPE_L_FX_NCOB, + DATA_TYPE_L_FX_EFX_NCOB_ECOB, + DATA_TYPE_F_FX, + DATA_TYPE_F_FX_EFX, + DATA_TYPE_F_FX_NCOB, + DATA_TYPE_F_FX_EFX_NCOB_ECOB, + DATA_TYPE_F_CAM_IMAGETTE, + DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE, + DATA_TYPE_F_CAM_OFFSET, + DATA_TYPE_F_CAM_BACKGROUND +}; + + +/* defined compression mode */ +enum cmp_mode { + CMP_MODE_RAW, + CMP_MODE_MODEL_ZERO, + CMP_MODE_DIFF_ZERO, + CMP_MODE_MODEL_MULTI, + CMP_MODE_DIFF_MULTI, + CMP_MODE_STUFF +}; + /** * @brief The cmp_cfg structure can contain the complete configuration of the HW as * well as the SW compressor. - * @note when using the 1d-differentiating mode or the raw mode (cmp_error = - * 0,2,4), the model parameters (model_value, model_buf, rdcu_model_adr, - * rdcu_new_model_adr) are ignored * @note the icu_output_buf will not be used for HW compression * @note the rdcu_***_adr parameters are ignored for SW compression - * @note semi adaptive compression not supported for SW compression; - * configuration parameters ap1\_golomb\_par, ap2\_golomb\_par, ap1\_spill, - * ap2\_spill will be ignored; */ struct cmp_cfg { - uint32_t cmp_mode; /* 0: raw mode + void *input_buf; /* Pointer to the data to compress buffer */ + void *model_buf; /* Pointer to the model buffer */ + void *icu_new_model_buf; /* Pointer to the updated model buffer (not used for RDCU compression )*/ + uint32_t *icu_output_buf; /* Pointer to the compressed data buffer (not used for RDCU compression) */ + uint32_t samples; /* Number of samples to compress, length of the data and model buffer + * (including the multi entity header by non-imagette data) + */ + uint32_t buffer_length; /* Length of the compressed data buffer in number of samples */ + uint32_t rdcu_data_adr; /* RDCU data to compress start address, the first data address in the RDCU SRAM; HW only */ + uint32_t rdcu_model_adr; /* RDCU model start address, the first model address in the RDCU SRAM */ + uint32_t rdcu_new_model_adr;/* RDCU updated model start address, the address in the RDCU SRAM where the updated model is stored */ + uint32_t rdcu_buffer_adr; /* RDCU compressed data start address, the first output data address in the RDCU SRAM */ + enum cmp_data_type data_type; /* Compression Data Product Types */ + enum cmp_mode cmp_mode; /* 0: raw mode * 1: model mode with zero escape symbol mechanism * 2: 1d differencing mode without input model with zero escape symbol mechanism * 3: model mode with multi escape symbol mechanism * 4: 1d differencing mode without input model multi escape symbol mechanism */ - uint32_t golomb_par; /* Golomb parameter for dictionary selection */ - uint32_t spill; /* Spillover threshold for encoding outliers */ uint32_t model_value; /* Model weighting parameter */ - uint32_t round; /* Number of noise bits to be rounded */ - uint32_t ap1_golomb_par; /* Adaptive 1 spillover threshold; HW only */ - uint32_t ap1_spill; /* Adaptive 1 Golomb parameter; HW only */ - uint32_t ap2_golomb_par; /* Adaptive 2 spillover threshold; HW only */ + uint32_t round; /* lossy compression parameter */ + uint32_t golomb_par; /* Golomb parameter for imagette data compression */ + uint32_t spill; /* Spillover threshold parameter for imagette compression */ + uint32_t ap1_golomb_par; /* Adaptive 1 spillover threshold for imagette data; HW only */ + uint32_t ap1_spill; /* Adaptive 1 Golomb parameter for imagette data; HW only */ + uint32_t ap2_golomb_par; /* Adaptive 2 spillover threshold for imagette data; HW only */ uint32_t ap2_spill; /* Adaptive 2 Golomb parameter; HW only */ - void *input_buf; /* Pointer to the data to compress buffer */ - uint32_t rdcu_data_adr; /* RDCU data to compress start address, the first data address in the RDCU SRAM; HW only */ - void *model_buf; /* Pointer to the model buffer */ - uint32_t rdcu_model_adr; /* RDCU model start address, the first model address in the RDCU SRAM */ - void *icu_new_model_buf; /* Pointer to the updated model buffer */ - uint32_t rdcu_new_model_adr;/* RDCU updated model start address, the address in the RDCU SRAM where the updated model is stored*/ - uint32_t samples; /* Number of samples (16 bit value) to compress, length of the data and model buffer */ - uint32_t *icu_output_buf; /* Pointer to the compressed data buffer (not used for RDCU compression) */ - uint32_t rdcu_buffer_adr; /* RDCU compressed data start address, the first output data address in the RDCU SRAM */ - uint32_t buffer_length; /* Length of the compressed data buffer in number of samples (16 bit values)*/ + uint32_t cmp_par_exp_flags; /* Compression parameter for exposure flags compression */ + uint32_t spill_exp_flags; /* Spillover threshold parameter for exposure flags compression */ + uint32_t cmp_par_fx; /* Compression parameter for normal flux compression */ + uint32_t spill_fx; /* Spillover threshold parameter for normal flux compression */ + uint32_t cmp_par_ncob; /* Compression parameter for normal center of brightness compression */ + uint32_t spill_ncob; /* Spillover threshold parameter for normal center of brightness compression */ + uint32_t cmp_par_efx; /* Compression parameter for extended flux compression */ + uint32_t spill_efx; /* Spillover threshold parameter for extended flux compression */ + uint32_t cmp_par_ecob; /* Compression parameter for executed center of brightness compression */ + uint32_t spill_ecob; /* Spillover threshold parameter for executed center of brightness compression */ + uint32_t cmp_par_fx_cob_variance; /* Compression parameter for flux/COB variance compression */ + uint32_t spill_fx_cob_variance; /* Spillover threshold parameter for flux/COB variance compression */ + uint32_t cmp_par_mean; /* Compression parameter for auxiliary science mean compression */ + uint32_t spill_mean; /* Spillover threshold parameter for auxiliary science mean compression */ + uint32_t cmp_par_variance; /* Compression parameter for auxiliary science variance compression */ + uint32_t spill_variance; /* Spillover threshold parameter for auxiliary science variance compression */ + uint32_t cmp_par_pixels_error; /* Compression parameter for auxiliary science outlier pixels number compression */ + uint32_t spill_pixels_error; /* Spillover threshold parameter for auxiliary science outlier pixels number compression */ }; -extern const struct cmp_cfg DEFAULT_CFG_MODEL; - -extern const struct cmp_cfg DEFAULT_CFG_DIFF; - - -/** - * @brief The cmp_status structure can contain the information of the - * compressor status register from the RDCU, see RDCU-FRS-FN-0632, - * but can also be used for the SW compression. +/* The cmp_status structure can contain the information of the compressor status + * register from the RDCU, see RDCU-FRS-FN-0632. */ struct cmp_status { @@ -125,18 +203,12 @@ struct cmp_status { }; -/** - * @brief The cmp_info structure can contain the information and metadata of an - * executed compression of the HW as well as the SW compressor. - * - * @note if SW compression is used the parameters rdcu_model_adr_used, rdcu_cmp_adr_used, - * ap1_cmp_size, ap2_cmp_size are not used and are therefore set to zero +/* The cmp_info structure can contain the information and metadata of an + * executed RDCU compression. */ struct cmp_info { uint32_t cmp_mode_used; /* Compression mode used */ - uint8_t model_value_used; /* Model weighting parameter used */ - uint8_t round_used; /* Number of noise bits to be rounded used */ uint32_t spill_used; /* Spillover threshold used */ uint32_t golomb_par_used; /* Golomb parameter used */ uint32_t samples_used; /* Number of samples (16 bit value) to be stored */ @@ -145,6 +217,8 @@ struct cmp_info { uint32_t ap2_cmp_size; /* Adaptive compressed data size 2; measured in bits */ uint32_t rdcu_new_model_adr_used; /* Updated model start address used */ uint32_t rdcu_cmp_adr_used; /* Compressed data start address */ + uint8_t model_value_used; /* Model weighting parameter used */ + uint8_t round_used; /* Number of noise bits to be rounded used */ uint16_t cmp_err; /* Compressor errors * [bit 0] small_buffer_err; The length for the compressed data buffer is too small * [bit 1] cmp_mode_err; The cmp_mode parameter is not set correctly @@ -155,32 +229,44 @@ struct cmp_info { * [bit 6] mb_err; Multi bit error detected by the memory controller (only HW compression) * [bit 7] slave_busy_err; The bus master has received the "slave busy" status (only HW compression) * [bit 8] slave_blocked_err; The bus master has received the “slave blocked” status (only HW compression) - * [bit 9] invalid address_err; The bus master has received the “invalid address” status (only HW compression) */ + * [bit 9] invalid address_err; The bus master has received the “invalid address” status (only HW compression) + */ }; + int is_a_pow_of_2(unsigned int v); int ilog_2(uint32_t x); -int model_mode_is_used(unsigned int cmp_mode); -int diff_mode_is_used(unsigned int cmp_mode); -int raw_mode_is_used(unsigned int cmp_mode); -int rdcu_supported_mode_is_used(unsigned int cmp_mode); -int cmp_mode_available(unsigned int cmp_mode); +unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit); -int zero_escape_mech_is_used(unsigned int cmp_mode); -int multi_escape_mech_is_used(unsigned int cmp_mode); +int cmp_cfg_is_invalid(const struct cmp_cfg *cfg); +int cmp_cfg_icu_gen_par_is_invalid(const struct cmp_cfg *cfg); +int cmp_cfg_icu_buffers_is_invalid(const struct cmp_cfg *cfg); +int cmp_cfg_imagette_is_invalid(const struct cmp_cfg *cfg, int rdcu_check); +int cmp_cfg_fx_cob_is_invalid(const struct cmp_cfg *cfg); +int cmp_cfg_aux_is_invalid(const struct cmp_cfg *cfg); +uint32_t cmp_ima_max_spill(unsigned int golomb_par); +uint32_t cmp_icu_max_spill(unsigned int cmp_par); -unsigned int round_fwd(unsigned int value, unsigned int round); -unsigned int round_inv(unsigned int value, unsigned int round); -unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int - model_value); +int cmp_data_type_valid(enum cmp_data_type data_type); +int rdcu_supported_data_type_is_used(enum cmp_data_type data_type); +int cmp_imagette_data_type_is_used(enum cmp_data_type data_type); +int cmp_ap_imagette_data_type_is_used(enum cmp_data_type data_type); +int cmp_fx_cob_data_type_is_used(enum cmp_data_type data_type); +int cmp_aux_data_type_is_used(enum cmp_data_type data_type); -uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode); -uint32_t cmp_get_good_spill(unsigned int golomb_par, unsigned int cmp_mode); +int cmp_mode_is_supported(enum cmp_mode cmp_mode); +int model_mode_is_used(enum cmp_mode cmp_mode); +int diff_mode_is_used(enum cmp_mode cmp_mode); +int raw_mode_is_used(enum cmp_mode cmp_mode); +int rdcu_supported_cmp_mode_is_used(enum cmp_mode cmp_mode); +int zero_escape_mech_is_used(enum cmp_mode cmp_mode); +int multi_escape_mech_is_used(enum cmp_mode cmp_mode); -size_t size_of_a_sample(unsigned int cmp_mode); -unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit); -unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode); +unsigned int round_fwd(unsigned int value, unsigned int round); +unsigned int round_inv(unsigned int value, unsigned int round); +unsigned int cmp_up_model(unsigned int data, unsigned int model, + unsigned int model_value, unsigned int round); void print_cmp_cfg(const struct cmp_cfg *cfg); diff --git a/include/decmp.h b/include/decmp.h index 139273f1f0bd27c838a0c9f1f6b2b6a93d43550a..826eb89804f8d5388e9aee8a77b05f405da6ae7c 100644 --- a/include/decmp.h +++ b/include/decmp.h @@ -19,13 +19,14 @@ #ifndef DECMP_H_ #define DECMP_H_ -#include "../include/cmp_support.h" +#include <cmp_entity.h> +#include <cmp_support.h> -void *malloc_decompressed_data(const struct cmp_info *info); +int decompress_cmp_entiy(struct cmp_entity *ent, void *model_of_data, + void *up_model_buf, void *decompressed_data); -int decompress_data(const void *compressed_data, void *de_model_buf, - const struct cmp_info *info, void *decompressed_data); - -double get_compression_ratio(const struct cmp_info *info); +int decompress_rdcu_data(uint32_t *compressed_data, const struct cmp_info *info, + uint16_t *model_of_data, uint16_t *up_model_buf, + uint16_t *decompressed_data); #endif /* DECMP_H_ */ diff --git a/include/meson.build b/include/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..491eef5ecebc527e3df0fb677d7e81907bcb9895 --- /dev/null +++ b/include/meson.build @@ -0,0 +1,13 @@ +# generate the configuration file +cdata = configuration_data() +cdata.set_quoted('PROGRAM_NAME', 'cmp_tool') +cdata.set_quoted('CMP_TOOL_VERSION', meson.project_version()) +if get_option('argument_input_mode') + cdata.set('ARGUMENT_INPUT_MODE', '') +endif + +configure_file( + output : 'cmp_tool-config.h', + configuration : cdata) + +incdir = include_directories('.') diff --git a/include/rdcu_ctrl.h b/include/rdcu_ctrl.h index ec5b9a2c919621c318fc3550a4a444c2155f63a8..ac3f03f9b0788e3f63977b017beaf946c803378c 100644 --- a/include/rdcu_ctrl.h +++ b/include/rdcu_ctrl.h @@ -245,11 +245,14 @@ uint32_t rdcu_get_golomb_param(void); uint32_t rdcu_get_compr_data_start_addr(void); -uint32_t rdcu_get_compr_data_size(void); +uint32_t rdcu_get_compr_data_size_bit(void); +uint32_t rdcu_get_compr_data_size_byte(void); -uint32_t rdcu_get_compr_data_adaptive_1_size(void); +uint32_t rdcu_get_compr_data_adaptive_1_size_bit(void); +uint32_t rdcu_get_compr_data_adaptive_1_size_byte(void); -uint32_t rdcu_get_compr_data_adaptive_2_size(void); +uint32_t rdcu_get_compr_data_adaptive_2_size_bit(void); +uint32_t rdcu_get_compr_data_adaptive_2_size_byte(void); uint16_t rdcu_get_compr_error(void); diff --git a/include/rdcu_pkt_to_file.h b/include/rdcu_pkt_to_file.h index 87c3d4b72fbf0189e2fb5ee193eca092ffcfb8b9..b0f055880bcfbe25ccdc76aa0eb5c29507553516 100644 --- a/include/rdcu_pkt_to_file.h +++ b/include/rdcu_pkt_to_file.h @@ -18,7 +18,7 @@ #ifndef _RDCU_PKT_TO_FILE_H_ #define _RDCU_PKT_TO_FILE_H_ -#include "cmp_support.h" +#include <cmp_support.h> /* directory where the tc files are stored, when --rdcu_pkt option is set */ #define TC_DIR "TC_FILES" @@ -27,6 +27,11 @@ #define MAX_TC_FOLDER_DIR_LEN 256 +/* default values when no .rdcu_pkt_mode_cfg file is available */ +#define DEF_ICU_ADDR 0xA7 +#define DEF_RDCU_ADDR 0xFE +#define DEF_MTU 4224 + int init_rmap_pkt_to_file(void); void set_tc_folder_dir(const char *dir_name); diff --git a/include/rmap.h b/include/rmap.h index 5156679c0c37bd7c805eec3fb9fa0e3eb82dbb6e..c5815750e7f5e99eb219ea0efe391ce0e92fd1a0 100644 --- a/include/rmap.h +++ b/include/rmap.h @@ -20,6 +20,7 @@ #define RMAP_H #include <stdint.h> +#include <compiler.h> /** * valid RMAP command codes, see Table 5-1 of ECSS‐E‐ST‐50‐52C @@ -149,11 +150,9 @@ struct rmap_instruction { #else #error "Unknown byte order" #endif -}__attribute__((packed)); -#if 0 -compile_time_assert((sizeof(struct rmap_instruction) == sizeof(uint8_t), - RMAP_INSTRUCTION_STRUCT_WRONG_SIZE)); -#endif +} __attribute__((packed)); + +compile_time_assert(sizeof(struct rmap_instruction) == sizeof(uint8_t), RMAP_INSTRUCTION_STRUCT_WRONG_SIZE); /** diff --git a/lib/cmp_data_types.c b/lib/cmp_data_types.c index 1df363cb274aa698815432ef3e9ed51557c88d5b..ed7d5e678f6393e9e55a35abd34d911c6453fd51 100644 --- a/lib/cmp_data_types.c +++ b/lib/cmp_data_types.c @@ -17,624 +17,527 @@ */ -#include "../include/cmp_data_types.h" -#include "../include/cmp_support.h" -#include "../include/cmp_debug.h" +#include <stdint.h> +#include <stdio.h> +#include <limits.h> + + +#include <cmp_data_types.h> +#include <cmp_debug.h> +#include <byteorder.h> + + +/* the maximum length of the different data products types in bits */ +struct cmp_max_used_bits max_used_bits = { + 0, /* default version */ + MAX_USED_S_FX_EXPOSURE_FLAGS_BITS, /* s_fx_exp_flags */ + MAX_USED_S_FX_BITS, /* s_fx */ + MAX_USED_S_EFX_BITS, /* s_efx */ + MAX_USED_S_NCOB_BITS, /* s_ncob_x and s_ncob_y */ + MAX_USED_S_ECOB_BITS, /* s_ecob_x and s_ncob_y */ + MAX_USED_F_FX_BITS, /* f_fx */ + MAX_USED_F_EFX_BITS, /* f_efx */ + MAX_USED_F_NCOB_BITS, /* f_ncob_x and f_ncob_y */ + MAX_USED_F_ECOB_BITS, /* f_ecob_x and f_ncob_y */ + MAX_USED_L_FX_EXPOSURE_FLAGS_BITS, /* l_fx_exp_flags */ + MAX_USED_L_FX_BITS, /* l_fx */ + MAX_USED_L_FX_VARIANCE_BITS, /* l_fx_variance */ + MAX_USED_L_EFX_BITS, /* l_efx */ + MAX_USED_L_NCOB_BITS, /* l_ncob_x and l_ncob_y */ + MAX_USED_L_ECOB_BITS, /* l_ecob_x and l_ncob_y */ + MAX_USED_L_COB_VARIANCE_BITS, /* l_cob_x_variance and l_cob_y_variance */ + MAX_USED_NC_IMAGETTE_BITS, /* nc_imagette */ + MAX_USED_SATURATED_IMAGETTE_BITS, /* saturated_imagette */ + MAX_USED_NC_OFFSET_MEAN_BITS, /* nc_offset_mean */ + MAX_USED_NC_OFFSET_VARIANCE_BITS, /* nc_offset_variance */ + MAX_USED_NC_BACKGROUND_MEAN_BITS, /* nc_background_mean */ + MAX_USED_NC_BACKGROUND_VARIANCE_BITS, /* nc_background_variance */ + MAX_USED_NC_BACKGROUND_OUTLIER_PIXELS_BITS, /* nc_background_outlier_pixels */ + MAX_USED_SMEARING_MEAN_BITS, /* smearing_mean */ + MAX_USED_SMEARING_VARIANCE_MEAN_BITS, /* smearing_variance_mean */ + MAX_USED_SMEARING_OUTLIER_PIXELS_BITS, /* smearing_outlier_pixels */ + MAX_USED_FC_IMAGETTE_BITS, /* fc_imagette */ + MAX_USED_FC_OFFSET_MEAN_BITS, /* fc_offset_mean */ + MAX_USED_FC_OFFSET_VARIANCE_BITS, /* fc_offset_variance */ + MAX_USED_FC_OFFSET_PIXEL_IN_ERROR_BITS, /* fc_offset_pixel_in_error */ + MAX_USED_FC_BACKGROUND_MEAN_BITS, /* fc_background_mean */ + MAX_USED_FC_BACKGROUND_VARIANCE_BITS, /* fc_background_variance */ + MAX_USED_FC_BACKGROUND_OUTLIER_PIXELS_BITS /* fc_background_outlier_pixels */ +}; /** - * @brief rounding down the least significant digits of a uint16_t data buffer + * @brief sets the maximum length of the different data products types * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place - * - * @param data_buf uint16_t formatted data buffer - * @param samples the size of the data buffer measured in uint16_t samples - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise + * @param set_max_used_bits pointer to a structure with the maximum length + * of the different data products types in bits */ -int lossy_rounding_16(uint16_t *data_buf, unsigned int samples, unsigned int - round) +void cmp_set_max_used_bits(const struct cmp_max_used_bits *set_max_used_bits) { - size_t i; - - if (!samples) - return 0; - - if (!data_buf) - return -1; + if (set_max_used_bits) + max_used_bits = *set_max_used_bits; +} - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; - for (i = 0; i < samples; i++) - data_buf[i] = round_fwd(data_buf[i], round); /* this is the lossy step */ +/** + * @brief get the maximum length of the different data products types + * + * @returns a structure with the used maximum length of the different data + * products types in bits + */ - return 0; +struct cmp_max_used_bits cmp_get_max_used_bits(void) +{ + return max_used_bits; } /** - * @brief rounding back the least significant digits of the data buffer - * - * @param data_buf pointer to the data to process - * @param samples_used the size of the data and model buffer in 16 bit units - * @param round_used used number of bits to round; if zero no rounding takes place + * @brief get the version record form the max used bits registry * - * @returns 0 on success, error otherwise + * @returns version of the max used bits registry */ -int de_lossy_rounding_16(uint16_t *data_buf, uint32_t samples_used, uint32_t - round_used) +uint8_t cmp_get_max_used_bits_version(void) { - size_t i; - - if (!samples_used) - return 0; + return max_used_bits.version; +} - if (!data_buf) - return -1; - /* round 0 means loss less compression, no further processing is necessary */ - if (round_used == 0) - return 0; +/** + * @brief calculate the size of a sample for the different compression data type + * + * @param data_type compression data_type + * + * @returns the size of a data sample in bytes for the selected compression + * data type; zero on unknown data type + */ - for (i = 0; i < samples_used; i++) { - /* check if data are not to big for a overflow */ - uint16_t mask = (uint16_t)(~0U << (16-round_used)); - if (data_buf[i] & mask) { - debug_print("de_lossy_rounding_16 failed!\n"); - return -1; - } - data_buf[i] = round_inv(data_buf[i], round_used); +size_t size_of_a_sample(enum cmp_data_type data_type) +{ + size_t sample_size = 0; + + switch (data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + sample_size = sizeof(uint16_t); + break; + case DATA_TYPE_OFFSET: + sample_size = sizeof(struct nc_offset); + break; + case DATA_TYPE_BACKGROUND: + sample_size = sizeof(struct nc_background); + break; + case DATA_TYPE_SMEARING: + sample_size = sizeof(struct smearing); + break; + case DATA_TYPE_S_FX: + sample_size = sizeof(struct s_fx); + break; + case DATA_TYPE_S_FX_EFX: + sample_size = sizeof(struct s_fx_efx); + break; + case DATA_TYPE_S_FX_NCOB: + sample_size = sizeof(struct s_fx_ncob); + break; + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + sample_size = sizeof(struct s_fx_efx_ncob_ecob); + break; + case DATA_TYPE_L_FX: + sample_size = sizeof(struct l_fx); + break; + case DATA_TYPE_L_FX_EFX: + sample_size = sizeof(struct l_fx_efx); + break; + case DATA_TYPE_L_FX_NCOB: + sample_size = sizeof(struct l_fx_ncob); + break; + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + sample_size = sizeof(struct l_fx_efx_ncob_ecob); + break; + case DATA_TYPE_F_FX: + sample_size = sizeof(struct f_fx); + break; + case DATA_TYPE_F_FX_EFX: + sample_size = sizeof(struct f_fx_efx); + break; + case DATA_TYPE_F_FX_NCOB: + sample_size = sizeof(struct f_fx_ncob); + break; + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + sample_size = sizeof(struct f_fx_efx_ncob_ecob); + break; + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + case DATA_TYPE_UNKNOWN: + default: + debug_print("Error: Compression data type is not supported.\n"); + break; } - return 0; + return sample_size; } /** - * @brief rounding down the least significant digits of a uint32_t data buffer + * @brief calculate the need bytes for the data * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place + * @param samples number of data samples + * @param data_type compression data_type * - * @param data_buf a uint32_t formatted data buffer - * @param samples the size of the data buffer measured in uint16_t samples - * @param round number of bits to round; if zero no rounding takes place + * @note for non-imagette data program types the multi entry header size is added * - * @returns 0 on success, error otherwise + * @returns the size in bytes to store the data sample; zero on failure */ -int lossy_rounding_32(uint32_t *data_buf, unsigned int samples, unsigned int - round) +unsigned int cmp_cal_size_of_data(unsigned int samples, enum cmp_data_type data_type) { - size_t i; + size_t s = size_of_a_sample(data_type); + uint64_t x; /* use 64 bit to catch overflow */ - if (!samples) + if (!s) return 0; - if (!data_buf) - return -1; + x = (uint64_t)s*samples; - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; - - for (i = 0; i < samples; i++) - data_buf[i] = round_fwd(data_buf[i], round); /* this is the lossy step */ - - return 0; -} + if (!rdcu_supported_data_type_is_used(data_type)) + x += MULTI_ENTRY_HDR_SIZE; - -int de_lossy_rounding_32(uint32_t *data_buf, uint32_t samples_used, uint32_t - round_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - /* round 0 means loss less compression, no further processing is necessary */ - if (round_used == 0) + if (x > UINT_MAX) /* catch overflow */ return 0; - for (i = 0; i < samples_used; i++) { - /* check if data are not to big for a overflow */ - uint32_t mask = (uint32_t)(~0U << (32-round_used)); - if (data_buf[i] & mask) { - debug_print("de_lossy_rounding_32 failed!\n"); - return -1; - } - data_buf[i] = round_inv(data_buf[i], round_used); - } - return 0; -} - - -struct S_FX sub_S_FX(struct S_FX a, struct S_FX b) -{ - struct S_FX result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - - return result; -} - - -struct S_FX add_S_FX(struct S_FX a, struct S_FX b) -{ - struct S_FX result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS; - result.FX = a.FX + b.FX; - - return result; + return (unsigned int)x; } /** - * @brief rounding down the least significant digits of a S_FX data buffer - * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place - * @note the exposure_flags are not rounded + * @brief calculates the number of samples for a given data size for the + * different compression modes * - * @param data_buf a S_FX formatted data buffer - * @param samples the size of the data buffer measured in S_FX samples - * @param round number of bits to round; if zero no rounding takes place + * @param size size of the data in bytes + * @param data_type compression data type * - * @returns 0 on success, error otherwise + * @returns the number samples for the given compression mode; negative on error */ -int lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples, unsigned - int round) +int cmp_input_size_to_samples(unsigned int size, enum cmp_data_type data_type) { - size_t i; + uint32_t samples_size = size_of_a_sample(data_type); - if (!samples) - return 0; - - if (!data_buf) + if (!samples_size) return -1; - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; + if (!rdcu_supported_data_type_is_used(data_type)) { + if (size < MULTI_ENTRY_HDR_SIZE) + return -1; + size -= MULTI_ENTRY_HDR_SIZE; + } - for (i = 0; i < samples; i++) - data_buf[i].FX = round_fwd(data_buf[i].FX, round); + if (size % samples_size) + return -1; - return 0; + return (int)(size/samples_size); } -int de_lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples_used, - unsigned int round_used) +static uint32_t be24_to_cpu(uint32_t a) { - size_t i; + return be32_to_cpu(a) >> 8; +} - if (!samples_used) - return 0; - if (!data_buf) - return -1; +static void be_to_cpus_16(uint16_t *a, int samples) +{ + int i; - if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; + for (i = 0; i < samples; ++i) + be16_to_cpus(&a[i]); +} - for (i = 0; i < samples_used; i++) { - uint32_t mask = (~0U << (32-round_used)); - if (data_buf[i].FX & mask) { - debug_print("Errolr: de_lossy_rounding_S_FX failed\n"); - return -1; - } +static void be_to_cpus_nc_offset(struct nc_offset *a, int samples) +{ + int i; - data_buf[i].FX = round_inv(data_buf[i].FX, round_used); + for (i = 0; i < samples; ++i) { + a[i].mean = be32_to_cpu(a[i].mean); + a[i].variance = be32_to_cpu(a[i].variance); } - return 0; } -struct S_FX cal_up_model_S_FX(struct S_FX data_buf, struct S_FX model_buf, - unsigned int model_value) +static void be_to_cpus_nc_background(struct nc_background *a, int samples) { - struct S_FX result; - - result.EXPOSURE_FLAGS = (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS, - model_buf.EXPOSURE_FLAGS, - model_value); - result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value); + int i; - return result; + for (i = 0; i < samples; ++i) { + a[i].mean = be32_to_cpu(a[i].mean); + a[i].variance = be32_to_cpu(a[i].variance); + a[i].outlier_pixels = be16_to_cpu(a[i].outlier_pixels); + } } -struct S_FX_EFX sub_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b) +static void be_to_cpus_smearing(struct smearing *a, int samples) { - struct S_FX_EFX result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - result.EFX = a.EFX - b.EFX; + int i; - return result; + for (i = 0; i < samples; ++i) { + a[i].mean = be32_to_cpu(a[i].mean); + a[i].variance_mean = be16_to_cpu(a[i].variance_mean); + a[i].outlier_pixels = be16_to_cpu(a[i].outlier_pixels); + } } -struct S_FX_EFX add_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b) +static void be_to_cpus_s_fx(struct s_fx *a, int samples) { - struct S_FX_EFX result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS; - result.FX = a.FX + b.FX; - result.EFX = a.EFX + b.EFX; + int i; - return result; + for (i = 0; i < samples; ++i) + a[i].fx = be32_to_cpu(a[i].fx); } -/** - * @brief rounding down the least significant digits of a S_FX_EFX data buffer - * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place - * @note the exposure_flags are not rounded - * - * @param data S_FX_EFX formatted data buffer - * @param samples the size of the data buffer measured in S_FX_EFX samples - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise - */ - -int lossy_rounding_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples, - unsigned int round) +static void be_to_cpus_s_fx_efx(struct s_fx_efx *a, int samples) { - size_t i; - - if (!samples) - return 0; + int i; - if (!data) - return -1; - - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; - - for (i = 0; i < samples; i++) { - data[i].FX = round_fwd(data[i].FX, round); - data[i].EFX = round_fwd(data[i].EFX, round); + for (i = 0; i < samples; ++i) { + a[i].fx = be32_to_cpu(a[i].fx); + a[i].efx = be32_to_cpu(a[i].efx); } - return 0; } -int de_lossy_rounding_S_FX_EFX(struct S_FX_EFX *data_buf, unsigned int - samples_used, unsigned int round_used) +static void be_to_cpus_s_fx_ncob(struct s_fx_ncob *a, int samples) { - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; + int i; - for (i = 0; i < samples_used; i++) { - uint32_t mask = (~0U << (32-round_used)); - - if (data_buf[i].FX & mask) { - debug_print("de_lossy_rounding_S_FX failed!\n"); - return -1; - } - if (data_buf[i].EFX & mask) { - debug_print("de_lossy_rounding_S_FX failed!\n"); - return -1; - } - - data_buf[i].FX = round_inv(data_buf[i].FX, round_used); - data_buf[i].EFX = round_inv(data_buf[i].EFX, round_used); + for (i = 0; i < samples; ++i) { + a[i].fx = be32_to_cpu(a[i].fx); + a[i].ncob_x = be32_to_cpu(a[i].ncob_x); + a[i].ncob_y = be32_to_cpu(a[i].ncob_y); } - return 0; } -struct S_FX_EFX cal_up_model_S_FX_EFX(struct S_FX_EFX data_buf, struct S_FX_EFX - model_buf, unsigned int model_value) +static void be_to_cpus_s_fx_efx_ncob_ecob(struct s_fx_efx_ncob_ecob *a, int samples) { - struct S_FX_EFX result; - - result.EXPOSURE_FLAGS = - (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS, - model_buf.EXPOSURE_FLAGS, model_value); - result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value); - result.EFX = cal_up_model(data_buf.EFX, model_buf.FX, model_value); - - return result; + int i; + + for (i = 0; i < samples; ++i) { + a[i].fx = be32_to_cpu(a[i].fx); + a[i].ncob_x = be32_to_cpu(a[i].ncob_x); + a[i].ncob_y = be32_to_cpu(a[i].ncob_y); + a[i].efx = be32_to_cpu(a[i].efx); + a[i].ecob_x = be32_to_cpu(a[i].ecob_x); + a[i].ecob_y = be32_to_cpu(a[i].ecob_y); + } } -struct S_FX_NCOB sub_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b) +static void be_to_cpus_l_fx(struct l_fx *a, int samples) { - struct S_FX_NCOB result; + int i; - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - result.NCOB_X = a.NCOB_X - b.NCOB_X; - result.NCOB_Y = a.NCOB_Y - b.NCOB_Y; - - return result; + for (i = 0; i < samples; ++i) { + a[i].exp_flags = be24_to_cpu(a[i].exp_flags); + a[i].fx = be32_to_cpu(a[i].fx); + a[i].fx_variance = be32_to_cpu(a[i].fx_variance); + } } -struct S_FX_NCOB add_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b) +static void be_to_cpus_l_fx_efx(struct l_fx_efx *a, int samples) { - struct S_FX_NCOB result; + int i; - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS; - result.FX = a.FX + b.FX; - result.NCOB_X = a.NCOB_X + b.NCOB_X; - result.NCOB_Y = a.NCOB_Y + b.NCOB_Y; - - return result; + for (i = 0; i < samples; ++i) { + a[i].exp_flags = be24_to_cpu(a[i].exp_flags); + a[i].fx = be32_to_cpu(a[i].fx); + a[i].efx = be32_to_cpu(a[i].efx); + a[i].fx_variance = be32_to_cpu(a[i].fx_variance); + } } -/** - * @brief rounding down the least significant digits of a S_FX_NCOB data buffer - * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place - * @note the exposure_flags are not rounded - * - * @param data_buf a S_FX_NCOB formatted data buffer - * @param samples the size of the data buffer measured in S_FX_NCOB samples - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise - */ - -int lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int samples, - unsigned int round) +static void be_to_cpus_l_fx_ncob(struct l_fx_ncob *a, int samples) { - size_t i; - - if (!samples) - return 0; - - if (!data_buf) - return -1; - - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; - - for (i = 0; i < samples; i++) { - data_buf[i].FX = round_fwd(data_buf[i].FX, round); - data_buf[i].NCOB_X = round_fwd(data_buf[i].NCOB_X, round); - data_buf[i].NCOB_Y = round_fwd(data_buf[i].NCOB_Y, round); + int i; + + for (i = 0; i < samples; ++i) { + a[i].exp_flags = be24_to_cpu(a[i].exp_flags); + a[i].fx = be32_to_cpu(a[i].fx); + a[i].ncob_x = be32_to_cpu(a[i].ncob_x); + a[i].ncob_y = be32_to_cpu(a[i].ncob_y); + a[i].fx_variance = be32_to_cpu(a[i].fx_variance); + a[i].cob_x_variance = be32_to_cpu(a[i].cob_x_variance); + a[i].cob_y_variance = be32_to_cpu(a[i].cob_y_variance); } - return 0; } -int de_lossy_rounding_S_FX_NCOB(struct S_FX_NCOB *data_buf, unsigned int - samples_used, unsigned int round_used) +static void be_to_cpus_l_fx_efx_ncob_ecob(struct l_fx_efx_ncob_ecob *a, int samples) { - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; - - for (i = 0; i < samples_used; i++) { - uint32_t mask = (~0U << (32-round_used)); - - if (data_buf[i].FX & mask) { - debug_print("de_lossy_rounding_S_FX_NCOB failed!\n"); - return -1; - } - if (data_buf[i].NCOB_X & mask) { - debug_print("de_lossy_rounding_S_FX_NCOB failed!\n"); - return -1; - } - if (data_buf[i].NCOB_Y & mask) { - debug_print("de_lossy_rounding_S_FX_NCOB failed!\n"); - return -1; - } - - data_buf[i].FX = round_inv(data_buf[i].FX, round_used); - data_buf[i].NCOB_X = round_inv(data_buf[i].NCOB_X, round_used); - data_buf[i].NCOB_Y = round_inv(data_buf[i].NCOB_Y, round_used); + int i; + + for (i = 0; i < samples; ++i) { + a[i].exp_flags = be24_to_cpu(a[i].exp_flags); + a[i].fx = be32_to_cpu(a[i].fx); + a[i].ncob_x = be32_to_cpu(a[i].ncob_x); + a[i].ncob_y = be32_to_cpu(a[i].ncob_y); + a[i].efx = be32_to_cpu(a[i].efx); + a[i].ecob_x = be32_to_cpu(a[i].ecob_x); + a[i].ecob_y = be32_to_cpu(a[i].ecob_y); + a[i].fx_variance = be32_to_cpu(a[i].fx_variance); + a[i].cob_x_variance = be32_to_cpu(a[i].cob_x_variance); + a[i].cob_y_variance = be32_to_cpu(a[i].cob_y_variance); } - return 0; } -struct S_FX_NCOB cal_up_model_S_FX_NCOB(struct S_FX_NCOB data_buf, struct S_FX_NCOB - model_buf, unsigned int model_value) +static void be_to_cpus_f_fx(struct f_fx *a, int samples) { - struct S_FX_NCOB result; - - result.EXPOSURE_FLAGS = - (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS, - model_buf.EXPOSURE_FLAGS, model_value); - result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value); - result.NCOB_X = cal_up_model(data_buf.NCOB_X, model_buf.NCOB_X, model_value); - result.NCOB_Y = cal_up_model(data_buf.NCOB_Y, model_buf.NCOB_Y, model_value); + int i; - return result; + for (i = 0; i < samples; ++i) + a[i].fx = be32_to_cpu(a[i].fx); } -struct S_FX_EFX_NCOB_ECOB sub_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a, - struct S_FX_EFX_NCOB_ECOB b) +static void be_to_cpus_f_fx_efx(struct f_fx_efx *a, int samples) { - struct S_FX_EFX_NCOB_ECOB result; + int i; - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - result.NCOB_X = a.NCOB_X - b.NCOB_X; - result.NCOB_Y = a.NCOB_Y - b.NCOB_Y; - result.EFX = a.EFX - b.EFX; - result.ECOB_X = a.ECOB_X - b.ECOB_X; - result.ECOB_Y = a.ECOB_Y - b.ECOB_Y; - - return result; + for (i = 0; i < samples; ++i) { + a[i].fx = be32_to_cpu(a[i].fx); + a[i].efx = be32_to_cpu(a[i].efx); + } } -struct S_FX_EFX_NCOB_ECOB add_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB a, - struct S_FX_EFX_NCOB_ECOB b) +static void be_to_cpus_f_fx_ncob(struct f_fx_ncob *a, int samples) { - struct S_FX_EFX_NCOB_ECOB result; + int i; + + for (i = 0; i < samples; ++i) { + a[i].fx = be32_to_cpu(a[i].fx); + a[i].ncob_x = be32_to_cpu(a[i].ncob_x); + a[i].ncob_y = be32_to_cpu(a[i].ncob_y); + } +} - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS; - result.FX = a.FX + b.FX; - result.NCOB_X = a.NCOB_X + b.NCOB_X; - result.NCOB_Y = a.NCOB_Y + b.NCOB_Y; - result.EFX = a.EFX + b.EFX; - result.ECOB_X = a.ECOB_X + b.ECOB_X; - result.ECOB_Y = a.ECOB_Y + b.ECOB_Y; - return result; +static void be_to_cpus_f_fx_efx_ncob_ecob(struct f_fx_efx_ncob_ecob *a, int samples) +{ + int i; + + for (i = 0; i < samples; ++i) { + a[i].fx = be32_to_cpu(a[i].fx); + a[i].ncob_x = be32_to_cpu(a[i].ncob_x); + a[i].ncob_y = be32_to_cpu(a[i].ncob_y); + a[i].efx = be32_to_cpu(a[i].efx); + a[i].ecob_x = be32_to_cpu(a[i].ecob_x); + a[i].ecob_y = be32_to_cpu(a[i].ecob_y); + } } /** - * @brief rounding down the least significant digits of a S_FX_EFX_NCOB_ECOB data - * buffer + * @brief swap the endianness of uncompressed data form big endian to the cpu + * endianness (or the other way around) in place * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place - * @note the exposure_flags are not rounded + * @param data pointer to a data sample + * @param data_size_byte size of the data in bytes + * @param data_type compression data type * - * @param data_buf a S_FX_EFX_NCOB_ECOB formatted data buffer - * @param samples the size of the data buffer measured in - * S_FX_EFX_NCOB_ECOB samples - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise + * @returns 0 on success; non-zero on failure */ -int lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - unsigned int samples, unsigned int round) +int cmp_input_big_to_cpu_endianness(void *data, uint32_t data_size_byte, + enum cmp_data_type data_type) { - size_t i; + int samples = cmp_input_size_to_samples(data_size_byte, data_type); - if (!samples) + if (!data) /* nothing to do */ return 0; - if (!data_buf) + if (samples < 0) { + debug_print("Error: Can not convert data size in samples.\n"); return -1; - - if (round == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; - - for (i = 0; i < samples; i++) { - data_buf[i].FX = round_fwd(data_buf[i].FX, round); - data_buf[i].NCOB_X = round_fwd(data_buf[i].NCOB_X, round); - data_buf[i].NCOB_Y = round_fwd(data_buf[i].NCOB_Y, round); - data_buf[i].EFX = round_fwd(data_buf[i].EFX, round); - data_buf[i].ECOB_X = round_fwd(data_buf[i].ECOB_X, round); - data_buf[i].ECOB_Y = round_fwd(data_buf[i].ECOB_Y, round); } - return 0; -} - - -int de_lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - unsigned int samples_used, - unsigned int round_used) -{ - size_t i; - - if (!samples_used) - return 0; - if (!data_buf) + /* we do not convert the endianness of the multi entry header */ + if (!rdcu_supported_data_type_is_used(data_type)) + data = (uint8_t *)data + MULTI_ENTRY_HDR_SIZE; + + switch (data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + be_to_cpus_16(data, samples); + break; + case DATA_TYPE_OFFSET: + be_to_cpus_nc_offset(data, samples); + break; + case DATA_TYPE_BACKGROUND: + be_to_cpus_nc_background(data, samples); + break; + case DATA_TYPE_SMEARING: + be_to_cpus_smearing(data, samples); + break; + case DATA_TYPE_S_FX: + be_to_cpus_s_fx(data, samples); + break; + case DATA_TYPE_S_FX_EFX: + be_to_cpus_s_fx_efx(data, samples); + break; + case DATA_TYPE_S_FX_NCOB: + be_to_cpus_s_fx_ncob(data, samples); + break; + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + be_to_cpus_s_fx_efx_ncob_ecob(data, samples); + break; + case DATA_TYPE_L_FX: + be_to_cpus_l_fx(data, samples); + break; + case DATA_TYPE_L_FX_EFX: + be_to_cpus_l_fx_efx(data, samples); + break; + case DATA_TYPE_L_FX_NCOB: + be_to_cpus_l_fx_ncob(data, samples); + break; + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + be_to_cpus_l_fx_efx_ncob_ecob(data, samples); + break; + case DATA_TYPE_F_FX: + be_to_cpus_f_fx(data, samples); + break; + case DATA_TYPE_F_FX_EFX: + be_to_cpus_f_fx_efx(data, samples); + break; + case DATA_TYPE_F_FX_NCOB: + be_to_cpus_f_fx_ncob(data, samples); + break; + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + be_to_cpus_f_fx_efx_ncob_ecob(data, samples); + break; + /* TODO: implement F_CAM conversion */ + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + case DATA_TYPE_UNKNOWN: + default: + debug_print("Error: Can not swap endianness for this compression data type.\n"); return -1; - - if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; - - for (i = 0; i < samples_used; i++) { - uint32_t mask = (~0U << (32-round_used)); - - if (data_buf[i].FX & mask) { - debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n"); - return -1; - } - if (data_buf[i].NCOB_X & mask) { - debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n"); - return -1; - } - if (data_buf[i].NCOB_Y & mask) { - debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n"); - return -1; - } - if (data_buf[i].EFX & mask) { - debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n"); - return -1; - } - if (data_buf[i].ECOB_X & mask) { - debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n"); - return -1; - } - if (data_buf[i].ECOB_Y & mask) { - debug_print("de_lossy_rounding_S_FX_EFX_NCOB_ECOB failed!\n"); - return -1; - } - - data_buf[i].FX = round_inv(data_buf[i].FX, round_used); - data_buf[i].NCOB_X = round_inv(data_buf[i].NCOB_X, round_used); - data_buf[i].NCOB_Y = round_inv(data_buf[i].NCOB_Y, round_used); - data_buf[i].EFX = round_inv(data_buf[i].EFX, round_used); - data_buf[i].ECOB_X = round_inv(data_buf[i].ECOB_X, round_used); - data_buf[i].ECOB_Y = round_inv(data_buf[i].ECOB_Y, round_used); } - return 0; -} - -struct S_FX_EFX_NCOB_ECOB cal_up_model_S_FX_EFX_NCOB_ECOB - (struct S_FX_EFX_NCOB_ECOB data_buf, struct S_FX_EFX_NCOB_ECOB - model_buf, unsigned int model_value) -{ - struct S_FX_EFX_NCOB_ECOB result; - - result.EXPOSURE_FLAGS = - (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS, - model_buf.EXPOSURE_FLAGS, model_value); - result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value); - result.NCOB_X = cal_up_model(data_buf.NCOB_X, model_buf.NCOB_X, model_value); - result.NCOB_Y = cal_up_model(data_buf.NCOB_Y, model_buf.NCOB_Y, model_value); - result.EFX = cal_up_model(data_buf.EFX, model_buf.EFX, model_value); - result.ECOB_X = cal_up_model(data_buf.ECOB_X, model_buf.ECOB_X, model_value); - result.ECOB_Y = cal_up_model(data_buf.ECOB_Y, model_buf.ECOB_Y, model_value); - - return result; + return 0; } diff --git a/lib/cmp_entity.c b/lib/cmp_entity.c index 84f784d0993f62f12336966ce398ec7ff33f3e1d..daa1e11917a0565378ec00738c7787b7ae3c152e 100644 --- a/lib/cmp_entity.c +++ b/lib/cmp_entity.c @@ -17,24 +17,30 @@ * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001 */ + #include <stdint.h> #include <stdio.h> #include <string.h> #include <limits.h> -#if __has_include(<time.h>) - #include <time.h> - #include <stdlib.h> +#if defined __has_include +# if __has_include(<time.h>) +# include <time.h> +# include <stdlib.h> +# define HAS_TIME_H 1 +# endif #endif -#include "../include/cmp_entity.h" -#include "../include/cmp_support.h" -#include "../include/byteorder.h" +#include <byteorder.h> +#include <cmp_debug.h> +#include <cmp_support.h> +#include <cmp_data_types.h> +#include <cmp_entity.h> -#if __has_include(<time.h>) +#ifdef HAS_TIME_H /* Used as epoch Wed Jan 1 00:00:00 2020 */ # if defined(_WIN32) || defined(_WIN64) -const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0, }; +const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0 }; # else const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0, 0, NULL }; # endif /* _WIN */ @@ -42,69 +48,61 @@ const struct tm EPOCH_DATE = { 0, 0, 0, 1, 0, 120, 0, 0, 0, 0, NULL }; /** - * @brief calculate the size of the compression entity header based of the data + * @brief calculate the size of the compression entity header based on the data * product type * * @param data_type compression entity data product type + * @param raw_mode_flag set this flag if the raw compression mode (CMP_MODE_RAW) is used * * @returns size of the compression entity header in bytes, 0 on unknown data * type */ -uint32_t cmp_ent_cal_hdr_size(enum cmp_ent_data_type data_type) -{ - switch (data_type) { - case DATA_TYPE_IMAGETTE: - case DATA_TYPE_F_CAM_IMAGETTE: - return IMAGETTE_HEADER_SIZE; - case DATA_TYPE_IMAGETTE_ADAPTIVE: - case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: - return IMAGETTE_ADAPTIVE_HEADER_SIZE; - case DATA_TYPE_SAT_IMAGETTE: - case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: - case DATA_TYPE_OFFSET: - case DATA_TYPE_BACKGROUND: - case DATA_TYPE_SMEARING: - case DATA_TYPE_S_FX: - case DATA_TYPE_S_FX_DFX: - case DATA_TYPE_S_FX_NCOB: - case DATA_TYPE_S_FX_DFX_NCOB_ECOB: - case DATA_TYPE_L_FX: - case DATA_TYPE_L_FX_DFX: - case DATA_TYPE_L_FX_NCOB: - case DATA_TYPE_L_FX_DFX_NCOB_ECOB: - case DATA_TYPE_F_FX: - case DATA_TYPE_F_FX_DFX: - case DATA_TYPE_F_FX_NCOB: - case DATA_TYPE_F_FX_DFX_NCOB_ECOB: - case DATA_TYPE_F_CAM_OFFSET: - case DATA_TYPE_F_CAM_BACKGROUND: - return NON_IMAGETTE_HEADER_SIZE; - case DATA_TYPE_UNKOWN: - return 0; +uint32_t cmp_ent_cal_hdr_size(enum cmp_data_type data_type, int raw_mode_flag) +{ + uint32_t size = 0; + + if (raw_mode_flag) { + if (cmp_data_type_valid(data_type)) + /* for raw data we do not need a specific header */ + size = GENERIC_HEADER_SIZE; + } else { + switch (data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE: + size = IMAGETTE_HEADER_SIZE; + break; + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + size = IMAGETTE_ADAPTIVE_HEADER_SIZE; + break; + case DATA_TYPE_OFFSET: + case DATA_TYPE_BACKGROUND: + case DATA_TYPE_SMEARING: + case DATA_TYPE_S_FX: + case DATA_TYPE_S_FX_EFX: + case DATA_TYPE_S_FX_NCOB: + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + case DATA_TYPE_L_FX: + case DATA_TYPE_L_FX_EFX: + case DATA_TYPE_L_FX_NCOB: + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + case DATA_TYPE_F_FX: + case DATA_TYPE_F_FX_EFX: + case DATA_TYPE_F_FX_NCOB: + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + size = NON_IMAGETTE_HEADER_SIZE; + break; + case DATA_TYPE_UNKNOWN: + size = 0; + break; + } } - - if ((data_type >> RAW_BIT_DATA_TYPE_POS) & 1U) - return GENERIC_HEADER_SIZE; - - return 0; -} - - -/** - * @brief check if the compression entity data product type is supported - * - * @param data_type compression entity data product type to check - * - * @returns zero if data_type is invalid; non-zero if data_type is valid - */ - -int cmp_ent_data_type_valid(enum cmp_ent_data_type data_type) -{ - if (cmp_ent_cal_hdr_size(data_type)) - return 1; - else - return 0; + return size; } @@ -326,19 +324,23 @@ int cmp_ent_set_fine_end_time(struct cmp_entity *ent, uint16_t fine_time) /** * @brief set the data product type in the compression entity header * - * @param ent pointer to a compression entity (including the - * uncompressed data bit) + * @param ent pointer to a compression entity * @param data_type compression entity data product type + * @param raw_mode_flag set this flag if the raw compression mode (CMP_MODE_RAW) is used * * @returns 0 on success, otherwise error */ int cmp_ent_set_data_type(struct cmp_entity *ent, - enum cmp_ent_data_type data_type) + enum cmp_data_type data_type, + int raw_mode_flag) { if (!ent) return -1; + if (raw_mode_flag) + data_type |= 1U << RAW_BIT_DATA_TYPE_POS; + if (data_type > UINT16_MAX) return -1; @@ -440,6 +442,27 @@ int cmp_ent_set_model_counter(struct cmp_entity *ent, uint32_t model_counter) } +/** + * @brief set version identifier for the max. used bits registry in the + * compression entity header + * + * @param ent pointer to a compression entity + * @param max_used_bits_version the identifier for the max. used bits registry + * + * @returns 0 on success, otherwise error + */ + +int cmp_ent_set_max_used_bits_version(struct cmp_entity *ent, uint8_t max_used_bits_version) +{ + if (!ent) + return -1; + + ent->max_used_bits_version = max_used_bits_version; + + return 0; +} + + /** * @brief set the used lossy compression parameter in the compression entity * header @@ -932,7 +955,7 @@ int cmp_ent_set_non_ima_cmp_par6(struct cmp_entity *ent, uint32_t cmp_par_6_used /** - * @brief get the ASW version identifier form the compression entity header + * @brief get the ASW version identifier from the compression entity header * * @param ent pointer to a compression entity * @@ -949,7 +972,7 @@ uint32_t cmp_ent_get_version_id(struct cmp_entity *ent) /** - * @brief get the size of the compression entity form the compression entity header + * @brief get the size of the compression entity from the compression entity header * * @param ent pointer to a compression entity * @@ -970,7 +993,7 @@ uint32_t cmp_ent_get_size(struct cmp_entity *ent) /** - * @brief get the original data size form the compression entity header + * @brief get the original data size from the compression entity header * * @param ent pointer to a compression entity * @@ -991,7 +1014,7 @@ uint32_t cmp_ent_get_original_size(struct cmp_entity *ent) /** - * @brief get the compression start timestamp form the compression entity header + * @brief get the compression start timestamp from the compression entity header * * @param ent pointer to a compression entity * @@ -1012,7 +1035,7 @@ uint64_t cmp_ent_get_start_timestamp(struct cmp_entity *ent) /** - * @brief get the coarse time form the compression start timestamp in the + * @brief get the coarse time from the compression start timestamp in the * compression entity header * * @returns the coarse part of the compression start timestamp on success, 0 on @@ -1029,7 +1052,7 @@ uint32_t cmp_ent_get_coarse_start_time(struct cmp_entity *ent) /** - * @brief get the fine time form the compression start timestamp in the + * @brief get the fine time from the compression start timestamp in the * compression entity header * * @returns the fine part of the compression start timestamp on success, 0 on @@ -1046,7 +1069,7 @@ uint16_t cmp_ent_get_fine_start_time(struct cmp_entity *ent) /** - * @brief get the compression end timestamp form the compression entity header + * @brief get the compression end timestamp from the compression entity header * * @param ent pointer to a compression entity * @@ -1067,7 +1090,7 @@ uint64_t cmp_ent_get_end_timestamp(struct cmp_entity *ent) /** - * @brief get the coarse time form the compression end timestamp in the + * @brief get the coarse time from the compression end timestamp in the * compression entity header * * @returns the coarse part of the compression end timestamp on success, 0 on @@ -1084,7 +1107,7 @@ uint32_t cmp_ent_get_coarse_end_time(struct cmp_entity *ent) /** - * @brief get the fine time form the compression end timestamp in the + * @brief get the fine time from the compression end timestamp in the * compression entity header * * @returns the fine part of the compression end timestamp on success, 0 on @@ -1101,30 +1124,33 @@ uint16_t cmp_ent_get_fine_end_time(struct cmp_entity *ent) /** - * @brief get data_type form the compression entity header + * @brief get data_type from the compression entity header * * @param ent pointer to a compression entity * - * @returns the data_type (including the uncompressed data bit) on success, - * DATA_TYPE_UNKOWN on error + * @returns the data_type NOT including the uncompressed data bit on success, + * DATA_TYPE_UNKNOWN on error */ -enum cmp_ent_data_type cmp_ent_get_data_type(struct cmp_entity *ent) +enum cmp_data_type cmp_ent_get_data_type(struct cmp_entity *ent) { + enum cmp_data_type data_type; + if (!ent) - return DATA_TYPE_UNKOWN; + return DATA_TYPE_UNKNOWN; - enum cmp_ent_data_type data_type = be16_to_cpu(ent->data_type); + data_type = be16_to_cpu(ent->data_type); + data_type &= (1U << RAW_BIT_DATA_TYPE_POS)-1; /* remove uncompressed data flag */ - if (cmp_ent_data_type_valid(data_type)) - return data_type; - else - return DATA_TYPE_UNKOWN; + if (!cmp_data_type_valid(data_type)) + data_type = DATA_TYPE_UNKNOWN; + + return data_type; } /** - * @brief get raw bit form the data_type field of the compression entity header + * @brief get the raw bit from the data_type field of the compression entity header * * @param ent pointer to a compression entity * @@ -1176,7 +1202,7 @@ uint8_t cmp_ent_get_model_value_used(struct cmp_entity *ent) /** - * @brief get model id form the compression entity header + * @brief get model id from the compression entity header * * @param ent pointer to a compression entity * @@ -1210,7 +1236,26 @@ uint8_t cmp_ent_get_model_counter(struct cmp_entity *ent) /** - * @brief get the used lossy compression parameter form the compression entity header + * @brief get the version identifier for the max. used bits registry from the + * compression entity header + * + * @param ent pointer to a compression entity + * + * @returns the version identifier for the max. used bits registry on success, + * 0 on error + */ + +uint8_t cmp_ent_get_max_use_bits_version(struct cmp_entity *ent) +{ + if (!ent) + return 0; + + return ent->max_used_bits_version; +} + + +/** + * @brief get the used lossy compression parameter from the compression entity header * * @param ent pointer to a compression entity * @@ -1227,7 +1272,7 @@ uint16_t cmp_ent_get_lossy_cmp_par(struct cmp_entity *ent) /** - * @brief get the used spillover threshold parameter form the (adaptive) + * @brief get the used spillover threshold parameter from the (adaptive) * imagette specific compression entity header * * @param ent pointer to a compression entity @@ -1245,7 +1290,7 @@ uint16_t cmp_ent_get_ima_spill(struct cmp_entity *ent) /** - * @brief get the used Golomb parameter form the (adaptive) imagette specific + * @brief get the used Golomb parameter from the (adaptive) imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1263,7 +1308,7 @@ uint8_t cmp_ent_get_ima_golomb_par(struct cmp_entity *ent) /** - * @brief get the used adaptive 1 spillover threshold parameter form the + * @brief get the used adaptive 1 spillover threshold parameter from the * adaptive imagette specific compression entity header * * @param ent pointer to a compression entity @@ -1281,7 +1326,7 @@ uint16_t cmp_ent_get_ima_ap1_spill(struct cmp_entity *ent) /** - * @brief get the used adaptive 1 Golomb parameter form adaptive imagette + * @brief get the used adaptive 1 Golomb parameter from adaptive imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1299,7 +1344,7 @@ uint8_t cmp_ent_get_ima_ap1_golomb_par(struct cmp_entity *ent) /** - * @brief get the used adaptive 2 spillover threshold parameter form the + * @brief get the used adaptive 2 spillover threshold parameter from the * adaptive imagette specific compression entity header * * @param ent pointer to a compression entity @@ -1317,7 +1362,7 @@ uint16_t cmp_ent_get_ima_ap2_spill(struct cmp_entity *ent) /** - * @brief get the used adaptive 2 spillover threshold parameter form the + * @brief get the used adaptive 2 spillover threshold parameter from the * adaptive imagette specific compression entity header * * @param ent pointer to a compression entity @@ -1335,7 +1380,7 @@ uint8_t cmp_ent_get_ima_ap2_golomb_par(struct cmp_entity *ent) /** - * @brief get the used spillover threshold 1 parameter form the non-imagette + * @brief get the used spillover threshold 1 parameter from the non-imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1357,7 +1402,7 @@ uint32_t cmp_ent_get_non_ima_spill1(struct cmp_entity *ent) /** - * @brief get the used compression parameter 1 form the non-imagette specific + * @brief get the used compression parameter 1 from the non-imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1375,7 +1420,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par1(struct cmp_entity *ent) /** - * @brief get the used spillover threshold 2 parameter form the non-imagette + * @brief get the used spillover threshold 2 parameter from the non-imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1397,7 +1442,7 @@ uint32_t cmp_ent_get_non_ima_spill2(struct cmp_entity *ent) /** - * @brief get the used compression parameter 2 form the non-imagette specific + * @brief get the used compression parameter 2 from the non-imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1415,7 +1460,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par2(struct cmp_entity *ent) /** - * @brief get the used spillover threshold 3 parameter form the non-imagette + * @brief get the used spillover threshold 3 parameter from the non-imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1437,7 +1482,7 @@ uint32_t cmp_ent_get_non_ima_spill3(struct cmp_entity *ent) /** - * @brief get the used compression parameter 3 form the non-imagette specific + * @brief get the used compression parameter 3 from the non-imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1455,7 +1500,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par3(struct cmp_entity *ent) /** - * @brief get the used spillover threshold 4 parameter form the non-imagette + * @brief get the used spillover threshold 4 parameter from the non-imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1477,7 +1522,7 @@ uint32_t cmp_ent_get_non_ima_spill4(struct cmp_entity *ent) /** - * @brief get the used compression parameter 4 form the non-imagette specific + * @brief get the used compression parameter 4 from the non-imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1495,7 +1540,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par4(struct cmp_entity *ent) /** - * @brief get the used spillover threshold 5 parameter form the non-imagette + * @brief get the used spillover threshold 5 parameter from the non-imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1517,7 +1562,7 @@ uint32_t cmp_ent_get_non_ima_spill5(struct cmp_entity *ent) /** - * @brief get the used compression parameter 5 form the non-imagette specific + * @brief get the used compression parameter 5 from the non-imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1535,7 +1580,7 @@ uint16_t cmp_ent_get_non_ima_cmp_par5(struct cmp_entity *ent) /** - * @brief get the used spillover threshold 6 parameter form the non-imagette + * @brief get the used spillover threshold 6 parameter from the non-imagette * specific compression entity header * * @param ent pointer to a compression entity @@ -1557,7 +1602,7 @@ uint32_t cmp_ent_get_non_ima_spill6(struct cmp_entity *ent) /** - * @brief get the used compression parameter 6 form the non-imagette specific + * @brief get the used compression parameter 6 from the non-imagette specific * compression entity header * * @param ent pointer to a compression entity @@ -1588,44 +1633,50 @@ uint16_t cmp_ent_get_non_ima_cmp_par6(struct cmp_entity *ent) void *cmp_ent_get_data_buf(struct cmp_entity *ent) { - enum cmp_ent_data_type data_type; + enum cmp_data_type data_type; if (!ent) return NULL; + data_type = cmp_ent_get_data_type(ent); + if (!cmp_data_type_valid(data_type)) { + debug_print("Error: Compression data type not supported.\n"); + return NULL; + } + if (cmp_ent_get_data_type_raw_bit(ent)) return (uint8_t *)ent + GENERIC_HEADER_SIZE; - data_type = cmp_ent_get_data_type(ent); switch (data_type) { case DATA_TYPE_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE: case DATA_TYPE_F_CAM_IMAGETTE: return ent->ima.ima_cmp_dat; case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: return ent->ima.ap_ima_cmp_data; - case DATA_TYPE_SAT_IMAGETTE: - case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: case DATA_TYPE_OFFSET: case DATA_TYPE_BACKGROUND: case DATA_TYPE_SMEARING: case DATA_TYPE_S_FX: - case DATA_TYPE_S_FX_DFX: + case DATA_TYPE_S_FX_EFX: case DATA_TYPE_S_FX_NCOB: - case DATA_TYPE_S_FX_DFX_NCOB_ECOB: + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: case DATA_TYPE_L_FX: - case DATA_TYPE_L_FX_DFX: + case DATA_TYPE_L_FX_EFX: case DATA_TYPE_L_FX_NCOB: - case DATA_TYPE_L_FX_DFX_NCOB_ECOB: + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: case DATA_TYPE_F_FX: - case DATA_TYPE_F_FX_DFX: + case DATA_TYPE_F_FX_EFX: case DATA_TYPE_F_FX_NCOB: - case DATA_TYPE_F_FX_DFX_NCOB_ECOB: + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: case DATA_TYPE_F_CAM_OFFSET: case DATA_TYPE_F_CAM_BACKGROUND: return ent->non_ima.cmp_data; - case DATA_TYPE_UNKOWN: + case DATA_TYPE_UNKNOWN: + default: return NULL; } @@ -1634,15 +1685,14 @@ void *cmp_ent_get_data_buf(struct cmp_entity *ent) /** - * @brief copy the data form a compression entity to a buffer + * @brief copy the data from a compression entity to a buffer * * @param ent pointer to the compression entity containing the compressed data * @param data_buf pointer where the destination data buffer where the * compressed data is copied to (can be NULL) * @param data_buf_size size of the destination data buffer - * @param verbose_en print verbose output if not zero * - * @returns the size in bytes to store the compressed data; negative on error + * @returns the size in bytes to store the compressed data; -1 on error * * @note the destination and source buffer can overlap * @note converts the data to the correct endianness @@ -1700,7 +1750,8 @@ ssize_t cmp_ent_get_cmp_data(struct cmp_entity *ent, uint32_t *data_buf, static uint32_t cmp_ent_get_hdr_size(struct cmp_entity *ent) { - return cmp_ent_cal_hdr_size(cmp_ent_get_data_type(ent)); + return cmp_ent_cal_hdr_size(cmp_ent_get_data_type(ent), + cmp_ent_get_data_type_raw_bit(ent)); } @@ -1728,77 +1779,195 @@ uint32_t cmp_ent_get_cmp_data_size(struct cmp_entity *ent) /** - * @brief set the parameters in the non-imagette specific compression - * entity header - * - * @param ent pointer to a compression entity - * @param info decompression information structure + * @brief write the compression parameters from a compression configuration + * into the compression entity header + * @note no compressed data are put into the entity and no change of the entity + * size * - * @returns 0 on success, otherwise error + * @param ent pointer to a compression entity + * @param cfg pointer to a compression configuration + * @param cmp_size_bits size of the compressed data in bits * - * @warning this functions is not implemented jet + * @returns 0 on success, negative on error */ -static int cmp_ent_write_non_ima_parameters(struct cmp_entity *ent, struct cmp_info *info) +int cmp_ent_write_cmp_pars(struct cmp_entity *ent, const struct cmp_cfg *cfg, + int cmp_size_bits) { - if (!info) - return -1; - (void)ent; + uint32_t ent_cmp_data_size; - printf("not implemented jet!\n"); - return -1; -#if 0 - if (cmp_ent_set_non_ima_spill1(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par1(ent, info->)) + if (!cfg) return -1; - if (cmp_ent_set_non_ima_spill2(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par2(ent, info->)) + if (cmp_size_bits < 0) return -1; - if (cmp_ent_set_non_ima_spill3(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par3(ent, info->)) + if (cfg->data_type != cmp_ent_get_data_type(ent)) { + debug_print("Error: The entity data product type dos not match the configuration data product type.\n"); return -1; + } + + ent_cmp_data_size = cmp_ent_get_cmp_data_size(ent); + + /* check if the entity can hold the compressed data */ + if (ent_cmp_data_size < cmp_bit_to_4byte((unsigned int)cmp_size_bits)) { + debug_print("Error: The entity size is to small to hold the compressed data.\n"); + return -2; + } - if (cmp_ent_set_non_ima_spill4(ent, info->)) + /* set compression parameter fields in the generic entity header */ + if (cmp_ent_set_original_size(ent, cmp_cal_size_of_data(cfg->samples, + cfg->data_type))) return -1; - if (cmp_ent_set_non_ima_cmp_par4(ent, info->)) + if (cmp_ent_set_cmp_mode(ent, cfg->cmp_mode)) return -1; - - if (cmp_ent_set_non_ima_spill5(ent, info->)) + if (cmp_ent_set_model_value(ent, cfg->model_value)) return -1; - if (cmp_ent_set_non_ima_cmp_par5(ent, info->)) + if (cmp_ent_set_max_used_bits_version(ent, cmp_get_max_used_bits_version())) return -1; - - if (cmp_ent_set_non_ima_spill6(ent, info->)) + if (cmp_ent_set_lossy_cmp_par(ent, cfg->round)) return -1; - if (cmp_ent_set_non_ima_cmp_par6(ent, info->)) + + if (cfg->cmp_mode == CMP_MODE_RAW) { + /* check the raw data bit */ + if (!cmp_ent_get_data_type_raw_bit(ent)) { + debug_print("Error: The entity's raw data bit is not set, but the configuration contains raw data.\n"); + return -1; + } + /* no specific header is used for raw data we are done */ + return 0; + } + + switch (cmp_ent_get_data_type(ent)) { + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + if (cmp_ent_set_ima_ap1_spill(ent, cfg->ap1_spill)) + return -1; + if (cmp_ent_set_ima_ap1_golomb_par(ent, cfg->ap1_golomb_par)) + return -1; + if (cmp_ent_set_ima_ap2_spill(ent, cfg->ap2_spill)) + return -1; + if (cmp_ent_set_ima_ap2_golomb_par(ent, cfg->ap2_golomb_par)) + return -1; + /* fall through */ + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE: + if (cmp_ent_set_ima_spill(ent, cfg->spill)) + return -1; + if (cmp_ent_set_ima_golomb_par(ent, cfg->golomb_par)) + return -1; + break; + case DATA_TYPE_OFFSET: + case DATA_TYPE_BACKGROUND: + case DATA_TYPE_SMEARING: + if (cmp_ent_set_non_ima_cmp_par1(ent, cfg->cmp_par_mean)) + return -1; + if (cmp_ent_set_non_ima_spill1(ent, cfg->spill_mean)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par2(ent, cfg->cmp_par_variance)) + return -1; + if (cmp_ent_set_non_ima_spill2(ent, cfg->spill_variance)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par3(ent, cfg->cmp_par_pixels_error)) + return -1; + if (cmp_ent_set_non_ima_spill3(ent, cfg->spill_pixels_error)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par4(ent, 0)) + return -1; + if (cmp_ent_set_non_ima_spill4(ent, 0)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par5(ent, 0)) + return -1; + if (cmp_ent_set_non_ima_spill5(ent, 0)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par6(ent, 0)) + return -1; + if (cmp_ent_set_non_ima_spill6(ent, 0)) + return -1; + break; + case DATA_TYPE_S_FX: + case DATA_TYPE_S_FX_EFX: + case DATA_TYPE_S_FX_NCOB: + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + case DATA_TYPE_L_FX: + case DATA_TYPE_L_FX_EFX: + case DATA_TYPE_L_FX_NCOB: + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + case DATA_TYPE_F_FX: + case DATA_TYPE_F_FX_EFX: + case DATA_TYPE_F_FX_NCOB: + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + if (cmp_ent_set_non_ima_cmp_par1(ent, cfg->cmp_par_exp_flags)) + return -1; + if (cmp_ent_set_non_ima_spill1(ent, cfg->spill_exp_flags)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par2(ent, cfg->cmp_par_fx)) + return -1; + if (cmp_ent_set_non_ima_spill2(ent, cfg->spill_fx)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par3(ent, cfg->cmp_par_ncob)) + return -1; + if (cmp_ent_set_non_ima_spill3(ent, cfg->spill_ncob)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par4(ent, cfg->cmp_par_efx)) + return -1; + if (cmp_ent_set_non_ima_spill4(ent, cfg->spill_efx)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par5(ent, cfg->cmp_par_ecob)) + return -1; + if (cmp_ent_set_non_ima_spill5(ent, cfg->spill_ecob)) + return -1; + + if (cmp_ent_set_non_ima_cmp_par6(ent, cfg->cmp_par_fx_cob_variance)) + return -1; + if (cmp_ent_set_non_ima_spill6(ent, cfg->spill_fx_cob_variance)) + return -1; + + break; + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + /* TODO: fix this*/ + return -1; + break; + case DATA_TYPE_UNKNOWN: + default: return -1; + } + return 0; -#endif } /** - * @brief write the compression parameters in the entity header based on the data - * product type set in the entity and the provided decompression information - * struct + * @brief write the parameters from the RDCU decompression information structure + * in the compression entity header + * @note no compressed data are put into the entity and no change of the entity + * size * * @param ent pointer to a compression entity - * @param info decompression information structure - * @param cfg compression configuration structure for adaptive compression - * parameters (can be NULL) + * @param info pointer to a decompression information structure + * @param cfg pointer to a compression configuration structure for adaptive + * compression parameters (can be NULL if non adaptive data_type is used) * * @returns 0 on success, negative on error */ -static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, - struct cmp_cfg *cfg) +int cmp_ent_write_rdcu_cmp_pars(struct cmp_entity *ent, const struct cmp_info *info, + const struct cmp_cfg *cfg) { uint32_t ent_cmp_data_size; + enum cmp_data_type data_type = cmp_ent_get_data_type(ent); if (!info) return -1; @@ -1806,12 +1975,18 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, ent_cmp_data_size = cmp_ent_get_cmp_data_size(ent); /* check if the entity can hold the compressed data */ - if (ent_cmp_data_size < cmp_bit_to_4byte(info->cmp_size)) + if (ent_cmp_data_size < cmp_bit_to_4byte(info->cmp_size)) { + debug_print("Error: The entity size is to small to hold the compressed data.\n"); return -2; + } + + if (!rdcu_supported_data_type_is_used(data_type)) { + debug_print("Error: The compression data type is not one of the types supported by the RDCU.\n"); + return -1; + } /* set compression parameter fields in the generic entity header */ - if (cmp_ent_set_original_size(ent, cmp_cal_size_of_data(info->samples_used, - info->cmp_mode_used))) + if (cmp_ent_set_original_size(ent, cmp_cal_size_of_data(info->samples_used, DATA_TYPE_IMAGETTE))) return -1; if (cmp_ent_set_cmp_mode(ent, info->cmp_mode_used)) return -1; @@ -1820,16 +1995,27 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, if (cmp_ent_set_lossy_cmp_par(ent, info->round_used)) return -1; - if (cmp_ent_get_data_type_raw_bit(ent)) + if (cmp_ent_get_data_type_raw_bit(ent) != raw_mode_is_used(info->cmp_mode_used)) { + debug_print("Error: The raw bit is set in data product type filed, but no raw compression mode is used.\n"); + return -1; + } + if (raw_mode_is_used(info->cmp_mode_used)) /* no specific header is used for raw data we are done */ return 0; - switch (cmp_ent_get_data_type(ent)) { - case DATA_TYPE_IMAGETTE_ADAPTIVE: - case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: - case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: - if (!cfg) + if (cmp_ent_set_ima_spill(ent, info->spill_used)) + return -1; + if (cmp_ent_set_ima_golomb_par(ent, info->golomb_par_used)) + return -1; + + /* use the adaptive imagette parameter from the compression configuration + * if an adaptive imagette compression data type is ent in the entity + */ + if (cmp_ap_imagette_data_type_is_used(data_type)) { + if (!cfg) { + debug_print("Error: Need the compression configuration to get the adaptive parameters.\n"); return -1; + } if (cmp_ent_set_ima_ap1_spill(ent, cfg->ap1_spill)) return -1; if (cmp_ent_set_ima_ap1_golomb_par(ent, cfg->ap1_golomb_par)) @@ -1838,38 +2024,6 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, return -1; if (cmp_ent_set_ima_ap2_golomb_par(ent, cfg->ap2_golomb_par)) return -1; - /* fall through */ - case DATA_TYPE_IMAGETTE: - case DATA_TYPE_SAT_IMAGETTE: - case DATA_TYPE_F_CAM_IMAGETTE: - if (cmp_ent_set_ima_spill(ent, info->spill_used)) - return -1; - if (cmp_ent_set_ima_golomb_par(ent, info->golomb_par_used)) - return -1; - break; - case DATA_TYPE_OFFSET: - case DATA_TYPE_BACKGROUND: - case DATA_TYPE_SMEARING: - case DATA_TYPE_S_FX: - case DATA_TYPE_S_FX_DFX: - case DATA_TYPE_S_FX_NCOB: - case DATA_TYPE_S_FX_DFX_NCOB_ECOB: - case DATA_TYPE_L_FX: - case DATA_TYPE_L_FX_DFX: - case DATA_TYPE_L_FX_NCOB: - case DATA_TYPE_L_FX_DFX_NCOB_ECOB: - case DATA_TYPE_F_FX: - case DATA_TYPE_F_FX_DFX: - case DATA_TYPE_F_FX_NCOB: - case DATA_TYPE_F_FX_DFX_NCOB_ECOB: - case DATA_TYPE_F_CAM_OFFSET: - case DATA_TYPE_F_CAM_BACKGROUND: - if (cmp_ent_write_non_ima_parameters(ent, info)) - return -1; - break; - case DATA_TYPE_UNKOWN: /* fall through */ - default: - return -1; } return 0; @@ -1877,13 +2031,14 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, /** - * @brief create a compression entity by setting the size of the - * compression entity and the data product type in the entity header + * @brief create a compression entity by setting the size of the compression + * entity and the data product type in the entity header * * @param ent pointer to a compression entity; if NULL, the function - * returns the needed size + * returns the needed size * @param data_type compression entity data product type - * @param cmp_size_byte size of the compressed data in bytes + * @param raw_mode_flag set this flag if the raw compression mode (CMP_MODE_RAW) is used + * @param cmp_size_byte size of the compressed data in bytes (should be a multiple of 4) * * @note if the entity size is smaller than the largest header, the function * rounds up the entity size to the largest header @@ -1891,12 +2046,12 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, * @returns the size of the compression entity or 0 on error */ -size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type, - uint32_t cmp_size_byte) +uint32_t cmp_ent_create(struct cmp_entity *ent, enum cmp_data_type data_type, + int raw_mode_flag, uint32_t cmp_size_byte) { int err; - uint32_t hdr_size = cmp_ent_cal_hdr_size(data_type); - size_t ent_size = hdr_size + cmp_size_byte; + uint32_t hdr_size = cmp_ent_cal_hdr_size(data_type, raw_mode_flag); + uint32_t ent_size = hdr_size + cmp_size_byte; uint32_t ent_size_cpy = ent_size; if (!hdr_size) @@ -1905,6 +2060,11 @@ size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type, if (cmp_size_byte > CMP_ENTITY_MAX_SIZE) return 0; + if (ent_size > CMP_ENTITY_MAX_SIZE) + return 0; + + /* to be safe a compression entity should be at least the size of the + * largest entity header */ if (ent_size < sizeof(struct cmp_entity)) ent_size = sizeof(struct cmp_entity); @@ -1917,7 +2077,7 @@ size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type, if (err) return 0; - err = cmp_ent_set_data_type(ent, data_type); + err = cmp_ent_set_data_type(ent, data_type, raw_mode_flag); if (err) return 0; @@ -1928,35 +2088,37 @@ size_t cmp_ent_create(struct cmp_entity *ent, enum cmp_ent_data_type data_type, /** * @brief create a compression entity and set the header fields * - * @note this function simplifies the entity setup by creating a entity and + * @note this function simplifies the entity set up by creating an entity and * setting the header fields in one function call + * @note no compressed data are put into the entity * * @param ent pointer to a compression entity; if NULL, the * function returns the needed size - * @param data_type compression entity data product type - * @param version_id applications software version identifier + * @param version_id applications software version identifier * @param start_time compression start timestamp (coarse and fine) * @param end_time compression end timestamp (coarse and fine) * @param model_id model identifier * @param model_counter model counter - * @param info decompression information structure - * @param cfg compression configuration structure for adaptive - * compression parameters (can be NULL) + * @param cfg pointer to compression configuration (can be NULL) + * @param cmp_size_bits length of the compressed data in bits * * @returns the size of the compression entity or 0 on error */ -size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type, - uint32_t version_id, uint64_t start_time, - uint64_t end_time, uint16_t model_id, uint8_t model_counter, - struct cmp_info *info, struct cmp_cfg *cfg) +size_t cmp_ent_build(struct cmp_entity *ent, uint32_t version_id, + uint64_t start_time, uint64_t end_time, uint16_t model_id, + uint8_t model_counter, struct cmp_cfg *cfg, int cmp_size_bits) { uint32_t ent_size; - if (!info) + if (!cfg) + return 0; + + if (cmp_size_bits < 0) return 0; - ent_size = cmp_ent_create(ent, data_type, cmp_bit_to_4byte(info->cmp_size)); + ent_size = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, + cmp_bit_to_4byte((unsigned int)cmp_size_bits)); if (!ent_size) return 0; @@ -1971,7 +2133,7 @@ size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type, return 0; if (cmp_ent_set_model_counter(ent, model_counter)) return 0; - if (cmp_ent_write_cmp_pars(ent, info, cfg)) + if (cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits)) return 0; } @@ -1980,82 +2142,116 @@ size_t cmp_ent_build(struct cmp_entity *ent, enum cmp_ent_data_type data_type, /** - * @brief read in read in a imagette compression entity header to a info struct + * @brief read in an imagette compression entity header to a + * compression configuration * - * @param ent pointer to a compression entity - * @param info pointer to decompression information structure - * to store the read values + * @param ent pointer to a compression entity + * @param cfg pointer to a compression configuration * * @returns 0 on success; otherwise error */ -int cmp_ent_read_imagette_header(struct cmp_entity *ent, struct cmp_info *info) +int cmp_ent_read_header(struct cmp_entity *ent, struct cmp_cfg *cfg) { - uint32_t original_size; - uint32_t sample_size; - - if (!ent) - return -1; - - if (!info) - return -1; + int samples; - info->cmp_mode_used = cmp_ent_get_cmp_mode(ent); - info->model_value_used = cmp_ent_get_model_value_used(ent); - info->round_used = cmp_ent_get_lossy_cmp_par(ent); - info->spill_used = cmp_ent_get_ima_spill(ent); - info->golomb_par_used = cmp_ent_get_ima_golomb_par(ent); - info->cmp_size = cmp_ent_get_cmp_data_size(ent)*CHAR_BIT; - - sample_size = size_of_a_sample(info->cmp_mode_used); - if (!sample_size) { - info->samples_used = 0; - return -1; - } - - original_size = cmp_ent_get_original_size(ent); - if (original_size % sample_size != 0) { - fprintf(stderr, "Error: original_size and cmp_mode compression header field are not compatible.\n"); - info->samples_used = 0; + cfg->data_type = cmp_ent_get_data_type(ent); + if (!cmp_data_type_valid(cfg->data_type)) { + debug_print("Error: Compression data type not supported.\n"); return -1; } - info->samples_used = original_size / sample_size; + cfg->cmp_mode = cmp_ent_get_cmp_mode(ent); + cfg->model_value = cmp_ent_get_model_value_used(ent); + cfg->round = cmp_ent_get_lossy_cmp_par(ent); + cfg->buffer_length = cmp_ent_get_cmp_data_size(ent); - if (cmp_ent_get_data_type_raw_bit(ent) != raw_mode_is_used(info->cmp_mode_used)) { - fprintf(stderr, "Error: The raw bit is set in Data Product Type Filed, but no raw compression mode is used.\n"); + samples = cmp_input_size_to_samples(cmp_ent_get_original_size(ent), cfg->data_type); + if (samples < 0) { + debug_print("Error: original_size and data product type in the compression header field are not compatible.\n"); + cfg->samples = 0; return -1; } - return 0; -} + cfg->samples = samples; -#if 0 -int cmp_ent_read_adaptive_imagette_header(struct cmp_entity *ent, struct cmp_info *info) -{ - if (!ent) + if (cmp_ent_get_data_type_raw_bit(ent) != raw_mode_is_used(cfg->cmp_mode)) { + debug_print("Error: The raw bit is set in data product type filed, but no raw compression mode is used.\n"); return -1; + } - if (!info) - return -1; + cfg->icu_output_buf = cmp_ent_get_data_buf(ent); - if (cmp_ent_get_imagette_header(ent, info)) + switch (cfg->data_type) { + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + cfg->ap1_golomb_par = cmp_ent_get_ima_ap1_golomb_par(ent); + cfg->ap1_spill = cmp_ent_get_ima_ap1_spill(ent); + cfg->ap2_golomb_par = cmp_ent_get_ima_ap2_golomb_par(ent); + cfg->ap2_spill = cmp_ent_get_ima_ap2_spill(ent); + /* fall through */ + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE: + cfg->spill = cmp_ent_get_ima_spill(ent); + cfg->golomb_par = cmp_ent_get_ima_golomb_par(ent); + break; + case DATA_TYPE_OFFSET: + case DATA_TYPE_BACKGROUND: + case DATA_TYPE_SMEARING: + cfg->cmp_par_mean = cmp_ent_get_non_ima_cmp_par1(ent); + cfg->spill_mean = cmp_ent_get_non_ima_spill1(ent); + cfg->cmp_par_variance = cmp_ent_get_non_ima_cmp_par2(ent); + cfg->spill_variance = cmp_ent_get_non_ima_spill2(ent); + cfg->cmp_par_pixels_error = cmp_ent_get_non_ima_cmp_par3(ent); + cfg->spill_pixels_error = cmp_ent_get_non_ima_spill3(ent); + break; + case DATA_TYPE_S_FX: + case DATA_TYPE_S_FX_EFX: + case DATA_TYPE_S_FX_NCOB: + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + case DATA_TYPE_L_FX: + case DATA_TYPE_L_FX_EFX: + case DATA_TYPE_L_FX_NCOB: + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + case DATA_TYPE_F_FX: + case DATA_TYPE_F_FX_EFX: + case DATA_TYPE_F_FX_NCOB: + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + cfg->cmp_par_exp_flags = cmp_ent_get_non_ima_cmp_par1(ent); + cfg->spill_exp_flags = cmp_ent_get_non_ima_spill1(ent); + cfg->cmp_par_fx = cmp_ent_get_non_ima_cmp_par2(ent); + cfg->spill_fx = cmp_ent_get_non_ima_spill2(ent); + cfg->cmp_par_ncob = cmp_ent_get_non_ima_cmp_par3(ent); + cfg->spill_ncob = cmp_ent_get_non_ima_spill3(ent); + cfg->cmp_par_efx = cmp_ent_get_non_ima_cmp_par4(ent); + cfg->spill_efx = cmp_ent_get_non_ima_spill4(ent); + cfg->cmp_par_ecob = cmp_ent_get_non_ima_cmp_par5(ent); + cfg->spill_ecob = cmp_ent_get_non_ima_spill5(ent); + cfg->cmp_par_fx_cob_variance = cmp_ent_get_non_ima_cmp_par6(ent); + cfg->spill_fx_cob_variance = cmp_ent_get_non_ima_spill6(ent); + break; + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + /* TODO: fix this*/ + return -1; + break; + case DATA_TYPE_UNKNOWN: /* fall through */ + default: return -1; - /* info->ap1_cmp_size_byte = cmp_ent_get_ap1_cmp_size_byte(ent); */ - /* info->ap2_cmp_size_byte = cmp_ent_get_ap2_cmp_size_byte(ent); */ - /* get ap1_spill and ap1/2 gpar*/ + } return 0; } -#endif -#if __has_include(<time.h>) +#ifdef HAS_TIME_H /* * @brief Covert a calendar time expressed as a struct tm object to time since * epoch as a time_t object. The function interprets the input structure * as representing Universal Coordinated Time (UTC). - * @note timegm is a GNU C Library extensions, not standardized. This function + * @note timegm is a GNU C Library extension, not standardized. This function * is used as a portable alternative * @note The function is thread-unsafe * @@ -2068,9 +2264,9 @@ int cmp_ent_read_adaptive_imagette_header(struct cmp_entity *ent, struct cmp_inf static time_t my_timegm(struct tm *tm) { -#if defined(_WIN32) || defined(_WIN64) +# if defined(_WIN32) || defined(_WIN64) return _mkgmtime(tm); -#else +# else time_t ret; char *tz; @@ -2087,14 +2283,14 @@ static time_t my_timegm(struct tm *tm) unsetenv("TZ"); tzset(); return ret; -#endif +# endif } /* * @brief Generate a timestamp for the compression header * - * @param ts pointer to object of type struct timespec of the timestamp time, null for now + * @param ts pointer to an object of type struct timespec of the timestamp time, null for now * * @returns returns compression header timestamp or 0 on error */ @@ -2187,7 +2383,7 @@ void cmp_ent_print(struct cmp_entity *ent) /** - * @brief parse the generic compressed entity header + * @brief parses the generic compressed entity header * * @param ent pointer to a compression entity */ @@ -2195,16 +2391,17 @@ void cmp_ent_print(struct cmp_entity *ent) static void cmp_ent_parse_generic_header(struct cmp_entity *ent) { uint32_t version_id, cmp_ent_size, original_size, cmp_mode_used, - model_value_used, model_id, model_counter, lossy_cmp_par_used, - start_coarse_time, end_coarse_time; + model_value_used, model_id, model_counter, max_used_bits_version, + lossy_cmp_par_used, start_coarse_time, end_coarse_time; uint16_t start_fine_time, end_fine_time; - enum cmp_ent_data_type data_type; + enum cmp_data_type data_type; int raw_bit; version_id = cmp_ent_get_version_id(ent); if (version_id & CMP_TOOL_VERSION_ID_BIT) { uint16_t major = (version_id & 0x7FFF0000U) >> 16U; uint16_t minor = version_id & 0xFFFFU; + printf("Compressed with cmp_tool version: %u.%02u\n", major, minor); } else printf("ICU ASW Version ID: %u\n", version_id); @@ -2227,10 +2424,11 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent) end_fine_time = cmp_ent_get_fine_end_time(ent); printf("Compression Fine End Time: %d\n", end_fine_time); -#if __has_include(<time.h>) +#ifdef HAS_TIME_H { struct tm epoch_date = EPOCH_DATE; time_t time = my_timegm(&epoch_date) + start_coarse_time; + printf("Data were compressed on (local time): %s", ctime(&time)); } #endif @@ -2238,7 +2436,7 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent) + ((end_fine_time - start_fine_time)/256./256.)); data_type = cmp_ent_get_data_type(ent); - if (data_type != DATA_TYPE_UNKOWN) + if (data_type != DATA_TYPE_UNKNOWN) printf("Data Product Type: %d\n", data_type); else printf("Data Product Type: unknown!"); @@ -2258,6 +2456,9 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent) model_counter = cmp_ent_get_model_counter(ent); printf("Model Counter: %u\n", model_counter); + max_used_bits_version = cmp_ent_get_max_use_bits_version(ent); + printf("Maximum Used Bits Registry Version: %u\n", max_used_bits_version); + lossy_cmp_par_used = cmp_ent_get_lossy_cmp_par(ent); printf("Used Lossy Compression Parameters: %u\n", lossy_cmp_par_used); } @@ -2320,17 +2521,26 @@ static void cmp_ent_parese_adaptive_imagette_header(struct cmp_entity *ent) static void cmp_ent_parese_specific_header(struct cmp_entity *ent) { - enum cmp_ent_data_type data_type = cmp_ent_get_data_type(ent); + enum cmp_data_type data_type = cmp_ent_get_data_type(ent); + + if (cmp_ent_get_data_type_raw_bit(ent)) { + printf("Uncompressed data bit is set no specific header is used.\n"); + return; + } switch (data_type) { case DATA_TYPE_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE: cmp_ent_parese_imagette_header(ent); break; case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: cmp_ent_parese_adaptive_imagette_header(ent); break; default: - printf("Data Product Type not supported!\n"); + printf("For this data product type no parse functions is implemented!\n"); break; } } @@ -2348,3 +2558,4 @@ void cmp_ent_parse(struct cmp_entity *ent) cmp_ent_parese_specific_header(ent); } + diff --git a/lib/cmp_guess.c b/lib/cmp_guess.c index 265b9c58ad6fe6eca4111f2feffaa177e49b03fe..87aec6cd5824f7baa9cde955b9cb44f91fd6042f 100644 --- a/lib/cmp_guess.c +++ b/lib/cmp_guess.c @@ -15,14 +15,17 @@ * * @brief helps the user to find a good compression parameters for a given * dataset + * @warning this part of the software is not intended to run on-board on the ICU. */ +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "../include/cmp_icu.h" -#include "../include/cmp_guess.h" +#include "cmp_data_types.h" +#include "cmp_icu.h" +#include "cmp_guess.h" /* how often the model is updated before it is rested */ @@ -67,6 +70,43 @@ uint16_t cmp_guess_model_value(int n_model_updates) } +/** + * @brief get a good spill threshold parameter for the selected Golomb parameter + * and compression mode + * + * @param golomb_par Golomb parameter + * @param cmp_mode compression mode + * + * @returns a good spill parameter (optimal for zero escape mechanism) + * @warning icu compression not support yet! + */ + +uint32_t cmp_rdcu_get_good_spill(unsigned int golomb_par, enum cmp_mode cmp_mode) +{ + const uint32_t LUT_IMA_MULIT[MAX_IMA_GOLOMB_PAR+1] = {0, 8, 16, 23, + 30, 36, 44, 51, 58, 64, 71, 77, 84, 90, 97, 108, 115, 121, 128, + 135, 141, 148, 155, 161, 168, 175, 181, 188, 194, 201, 207, 214, + 229, 236, 242, 250, 256, 263, 269, 276, 283, 290, 296, 303, 310, + 317, 324, 330, 336, 344, 351, 358, 363, 370, 377, 383, 391, 397, + 405, 411, 418, 424, 431, 452 }; + + if (zero_escape_mech_is_used(cmp_mode)) + return cmp_ima_max_spill(golomb_par); + + if (cmp_mode == CMP_MODE_MODEL_MULTI) { + if (golomb_par > MAX_IMA_GOLOMB_PAR) + return 0; + else + return LUT_IMA_MULIT[golomb_par]; + } + + if (cmp_mode == CMP_MODE_DIFF_MULTI) + return CMP_GOOD_SPILL_DIFF_MULTI; + + return 0; +} + + /** * @brief guess a good configuration with pre_cal_method * @@ -79,18 +119,17 @@ uint16_t cmp_guess_model_value(int n_model_updates) static uint32_t pre_cal_method(struct cmp_cfg *cfg) { uint32_t g; - uint32_t cmp_size; - uint32_t cmp_size_best = ~0U; + int cmp_size, cmp_size_best = INT_MAX; uint32_t golomb_par_best = 0; uint32_t spill_best = 0; - for (g = MIN_RDCU_GOLOMB_PAR; g < MAX_RDCU_GOLOMB_PAR; g++) { - uint32_t s = cmp_get_good_spill(g, cfg->cmp_mode); + for (g = MIN_IMA_GOLOMB_PAR; g < MAX_IMA_GOLOMB_PAR; g++) { + uint32_t s = cmp_rdcu_get_good_spill(g, cfg->cmp_mode); cfg->golomb_par = g; cfg->spill = s; - cmp_size = cmp_encode_data(cfg); - if (cmp_size == 0) { + cmp_size = icu_compress_data(cfg); + if (cmp_size <= 0) { return 0; } else if (cmp_size < cmp_size_best) { cmp_size_best = cmp_size; @@ -120,8 +159,7 @@ static uint32_t brute_force(struct cmp_cfg *cfg) uint32_t g, s; uint32_t n_cal_steps = 0, last = 0; const uint32_t max_cal_steps = CMP_GUESS_MAX_CAL_STEPS; - uint32_t cmp_size; - uint32_t cmp_size_best = ~0U; + int cmp_size, cmp_size_best = INT_MAX; uint32_t golomb_par_best = 0; uint32_t spill_best = 0; uint32_t percent; @@ -133,13 +171,13 @@ static uint32_t brute_force(struct cmp_cfg *cfg) printf("0%%... "); fflush(stdout); - for (g = MIN_RDCU_GOLOMB_PAR; g < MAX_RDCU_GOLOMB_PAR; g++) { - for (s = MIN_RDCU_SPILL; s < get_max_spill(g, cfg->cmp_mode); s++) { + for (g = MIN_IMA_GOLOMB_PAR; g < MAX_IMA_GOLOMB_PAR; g++) { + for (s = MIN_IMA_SPILL; s < cmp_ima_max_spill(g); s++) { cfg->golomb_par = g; cfg->spill = s; - cmp_size = cmp_encode_data(cfg); - if (cmp_size == 0) { + cmp_size = icu_compress_data(cfg); + if (cmp_size <= 0) { return 0; } else if (cmp_size < cmp_size_best) { cmp_size_best = cmp_size; @@ -173,11 +211,11 @@ static uint32_t brute_force(struct cmp_cfg *cfg) static void add_rdcu_pars_internal(struct cmp_cfg *cfg) { - if (cfg->golomb_par == MIN_RDCU_GOLOMB_PAR) { + if (cfg->golomb_par == MIN_IMA_GOLOMB_PAR) { cfg->ap1_golomb_par = cfg->golomb_par + 1; cfg->ap2_golomb_par = cfg->golomb_par + 2; - } else if (cfg->golomb_par == MAX_RDCU_GOLOMB_PAR) { + } else if (cfg->golomb_par == MAX_IMA_GOLOMB_PAR) { cfg->ap1_golomb_par = cfg->golomb_par - 2; cfg->ap2_golomb_par = cfg->golomb_par - 1; } else { @@ -185,19 +223,19 @@ static void add_rdcu_pars_internal(struct cmp_cfg *cfg) cfg->ap2_golomb_par = cfg->golomb_par + 1; } - cfg->ap1_spill = cmp_get_good_spill(cfg->ap1_golomb_par, cfg->cmp_mode); - cfg->ap2_spill = cmp_get_good_spill(cfg->ap2_golomb_par, cfg->cmp_mode); + cfg->ap1_spill = cmp_rdcu_get_good_spill(cfg->ap1_golomb_par, cfg->cmp_mode); + cfg->ap2_spill = cmp_rdcu_get_good_spill(cfg->ap2_golomb_par, cfg->cmp_mode); if (model_mode_is_used(cfg->cmp_mode)) { - cfg->rdcu_data_adr = DEFAULT_CFG_MODEL.rdcu_data_adr; - cfg->rdcu_model_adr = DEFAULT_CFG_MODEL.rdcu_model_adr; - cfg->rdcu_new_model_adr = DEFAULT_CFG_MODEL.rdcu_new_model_adr; - cfg->rdcu_buffer_adr = DEFAULT_CFG_MODEL.rdcu_buffer_adr; + cfg->rdcu_data_adr = CMP_DEF_IMA_MODEL_RDCU_DATA_ADR; + cfg->rdcu_model_adr = CMP_DEF_IMA_MODEL_RDCU_MODEL_ADR; + cfg->rdcu_new_model_adr = CMP_DEF_IMA_MODEL_RDCU_UP_MODEL_ADR; + cfg->rdcu_buffer_adr = CMP_DEF_IMA_MODEL_RDCU_BUFFER_ADR; } else { - cfg->rdcu_data_adr = DEFAULT_CFG_DIFF.rdcu_data_adr; - cfg->rdcu_model_adr = DEFAULT_CFG_DIFF.rdcu_model_adr; - cfg->rdcu_new_model_adr = DEFAULT_CFG_DIFF.rdcu_new_model_adr; - cfg->rdcu_buffer_adr = DEFAULT_CFG_DIFF.rdcu_buffer_adr; + cfg->rdcu_data_adr = CMP_DEF_IMA_DIFF_RDCU_DATA_ADR; + cfg->rdcu_model_adr = CMP_DEF_IMA_DIFF_RDCU_MODEL_ADR; + cfg->rdcu_new_model_adr = CMP_DEF_IMA_DIFF_RDCU_UP_MODEL_ADR; + cfg->rdcu_buffer_adr = CMP_DEF_IMA_DIFF_RDCU_BUFFER_ADR; } } @@ -220,7 +258,6 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level) { size_t size; struct cmp_cfg work_cfg; - int err; uint32_t cmp_size = 0; if (!cfg) @@ -228,38 +265,28 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level) if (!cfg->input_buf) return 0; + if (model_mode_is_used(cfg->cmp_mode)) + if (!cfg->model_buf) + return 0; - if (!rdcu_supported_mode_is_used(cfg->cmp_mode)) { + if (!rdcu_supported_cmp_mode_is_used(cfg->cmp_mode)) { printf("This compression mode is not implied yet.\n"); return 0; } /* make a working copy of the input data (and model) because the - * following function works inplace */ + * following function works inplace + */ work_cfg = *cfg; - work_cfg.input_buf = NULL; - work_cfg.model_buf = NULL; work_cfg.icu_new_model_buf = NULL; work_cfg.icu_output_buf = NULL; work_cfg.buffer_length = 0; + work_cfg.data_type = DATA_TYPE_IMAGETTE; /* TODO: adapt to others data types */ - size = cfg->samples * size_of_a_sample(work_cfg.cmp_mode); + size = cmp_cal_size_of_data(cfg->samples, cfg->data_type); if (size == 0) goto error; - work_cfg.input_buf = malloc(size); - if (!work_cfg.input_buf) { - printf("malloc() failed!\n"); - goto error; - } - memcpy(work_cfg.input_buf, cfg->input_buf, size); - - if (cfg->model_buf && model_mode_is_used(cfg->cmp_mode)) { - work_cfg.model_buf = malloc(size); - if (!work_cfg.model_buf) { - printf("malloc() failed!\n"); - goto error; - } - memcpy(work_cfg.model_buf, cfg->model_buf, size); + if (model_mode_is_used(cfg->cmp_mode)) { work_cfg.icu_new_model_buf = malloc(size); if (!work_cfg.icu_new_model_buf) { printf("malloc() failed!\n"); @@ -267,14 +294,6 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level) } } - err = cmp_pre_process(&work_cfg); - if (err) - goto error; - - err = cmp_map_to_pos(&work_cfg); - if (err) - goto error; - /* find the best parameters */ switch (level) { case 3: @@ -294,8 +313,6 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level) if (!cmp_size) goto error; - free(work_cfg.input_buf); - free(work_cfg.model_buf); free(work_cfg.icu_new_model_buf); cfg->golomb_par = work_cfg.golomb_par; @@ -303,16 +320,15 @@ uint32_t cmp_guess(struct cmp_cfg *cfg, int level) cfg->model_value = cmp_guess_model_value(num_model_updates); - if (rdcu_supported_mode_is_used(cfg->cmp_mode)) + if (rdcu_supported_data_type_is_used(cfg->data_type)) add_rdcu_pars_internal(cfg); - cfg->buffer_length = ((cmp_size + 32)&~0x1FU)/(size_of_a_sample(work_cfg.cmp_mode)*8); + /* TODO: check that for non-imagette data */ + cfg->buffer_length = ((cmp_size + 32)&~0x1FU)/(size_of_a_sample(cfg->data_type)*8); return cmp_size; error: - free(work_cfg.input_buf); - free(work_cfg.model_buf); free(work_cfg.icu_new_model_buf); return 0; } diff --git a/lib/cmp_icu.c b/lib/cmp_icu.c index 5409045e74899ebcbfb49457b33458e559b5b4bb..79d1a64f075989c59700f5ceb865048635d64a04 100644 --- a/lib/cmp_icu.c +++ b/lib/cmp_icu.c @@ -15,1761 +15,2422 @@ * * @brief software compression library * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001 + * + * To compress data, first create a compression configuration with the + * cmp_cfg_icu_create() function. + * Then set the different data buffers with the data to compressed, the model + * data and the compressed data with the cmp_cfg_icu_buffers() function. + * Then set the compression data type specific compression parameters. For + * imagette data use the cmp_cfg_icu_imagette() function. For flux and center of + * brightness data use the cmp_cfg_fx_cob() function. And for background, offset + * and smearing data use the cmp_cfg_aux() function. + * Finally, you can compress the data with the icu_compress_data() function. */ -#include <stdio.h> #include <stdint.h> #include <string.h> #include <limits.h> -#include "../include/cmp_support.h" -#include "../include/cmp_data_types.h" -#include "../include/cmp_icu.h" -#include "../include/byteorder.h" -#include "../include/cmp_debug.h" +#include <byteorder.h> +#include <cmp_debug.h> +#include <cmp_data_types.h> +#include <cmp_support.h> +#include <cmp_icu.h> +#include <cmp_entity.h> + + +/* maximum used bits registry */ +extern struct cmp_max_used_bits max_used_bits; + + +/* pointer to a code word generation function */ +typedef uint32_t (*generate_cw_f_pt)(uint32_t value, uint32_t encoder_par1, + uint32_t encoder_par2, uint32_t *cw); + + +/* structure to hold a setup to encode a value */ +struct encoder_setupt { + generate_cw_f_pt generate_cw_f; /* pointer to the code word encoder */ + int (*encode_method_f)(uint32_t data, uint32_t model, int stream_len, + const struct encoder_setupt *setup); /* pointer to the encoding function */ + uint32_t *bitstream_adr; /* start address of the compressed data bitstream */ + uint32_t max_stream_len; /* maximum length of the bitstream/icu_output_buf in bits */ + uint32_t encoder_par1; /* encoding parameter 1 */ + uint32_t encoder_par2; /* encoding parameter 2 */ + uint32_t spillover_par; /* outlier parameter */ + uint32_t lossy_par; /* lossy compression parameter */ + uint32_t max_data_bits; /* how many bits are needed to represent the highest possible value */ +}; /** - * @brief check if the compressor configuration is valid for a SW compression, - * see the user manual for more information (PLATO-UVIE-PL-UM-0001). + * @brief create an ICU compression configuration * - * @param cfg configuration contains all parameters required for compression - * @param info compressor information contains information of an executed - * compression (can be NULL) + * @param data_type compression data product type + * @param cmp_mode compression mode + * @param model_value model weighting parameter (only needed for model compression mode) + * @param lossy_par lossy rounding parameter (use CMP_LOSSLESS for lossless compression) * - * @returns 0 when configuration is valid, invalid configuration otherwise + * @returns a compression configuration containing the chosen parameters; + * on error the data_type record is set to DATA_TYPE_UNKNOWN */ -int icu_cmp_cfg_valid(const struct cmp_cfg *cfg, struct cmp_info *info) +struct cmp_cfg cmp_cfg_icu_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode, + uint32_t model_value, uint32_t lossy_par) { - int cfg_invalid = 0; + struct cmp_cfg cfg; - if (!cfg) { - debug_print("Error: compression configuration structure is NULL.\n"); - return -1; - } + memset(&cfg, 0, sizeof(cfg)); - if (!info) - debug_print("Warning: compressor information structure is NULL.\n"); + cfg.data_type = data_type; + cfg.cmp_mode = cmp_mode; + cfg.model_value = model_value; + cfg.round = lossy_par; - if (info) - info->cmp_err = 0; /* reset errors */ + if (cmp_cfg_icu_gen_par_is_invalid(&cfg)) + cfg.data_type = DATA_TYPE_UNKNOWN; - if (cfg->input_buf == NULL) { - debug_print("Error: The input_buf buffer for the data to be compressed is NULL.\n"); - cfg_invalid++; - } + return cfg; +} - if (cfg->samples == 0) - debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended.\n"); - /* icu_output_buf can be NULL if rdcu compression is used */ - if (cfg->icu_output_buf == NULL) { - debug_print("Error: The icu_output_buf buffer for the compressed data is NULL.\n"); - cfg_invalid++; - } +/** + * @brief setup the different data buffers for an ICU compression + * + * @param cfg pointer to a compression configuration (created + * with the cmp_cfg_icu_create() function) + * @param data_to_compress pointer to the data to be compressed + * @param data_samples length of the data to be compressed measured in + * data samples/entitys (collection header not + * included by imagette data) + * @param model_of_data pointer to model data buffer (can be NULL if no + * model compression mode is used) + * @param updated_model pointer to store the updated model for the next + * model mode compression (can be the same as the model_of_data + * buffer for in-place update or NULL if updated model is not needed) + * @param compressed_data pointer to the compressed data buffer (can be NULL) + * @param compressed_data_len_samples length of the compressed_data buffer in + * measured in the same units as the data_samples + * + * @returns the size of the compressed_data buffer on success; 0 if the + * parameters are invalid + */ - if (cfg->buffer_length == 0 && cfg->samples != 0) { - debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data.\n"); - cfg_invalid++; - } +uint32_t cmp_cfg_icu_buffers(struct cmp_cfg *cfg, void *data_to_compress, + uint32_t data_samples, void *model_of_data, + void *updated_model, uint32_t *compressed_data, + uint32_t compressed_data_len_samples) +{ + uint32_t data_size, hdr_size; - if (cfg->icu_output_buf == cfg->input_buf) { - debug_print("Error: The icu_output_buf buffer is the same as the input_buf buffer.\n"); - cfg_invalid++; + if (!cfg) { + debug_print("Error: pointer to the compression configuration structure is NULL.\n"); + return 0; } - if (model_mode_is_used(cfg->cmp_mode)) { - if (cfg->model_buf == NULL) { - debug_print("Error: The model_buf buffer for the model data is NULL.\n"); - cfg_invalid++; - } - - if (cfg->model_buf == cfg->input_buf) { - debug_print("Error: The model_buf buffer is the same as the input_buf buffer.\n"); - cfg_invalid++; - } - - if (cfg->model_buf == cfg->icu_output_buf) { - debug_print("Error: The model_buf buffer is the same as the icu_output_buf buffer.\n"); - cfg_invalid++; - } + cfg->input_buf = data_to_compress; + cfg->model_buf = model_of_data; + cfg->samples = data_samples; + cfg->icu_new_model_buf = updated_model; + cfg->icu_output_buf = compressed_data; + cfg->buffer_length = compressed_data_len_samples; - if (cfg->icu_new_model_buf == cfg->input_buf) { - debug_print("Error: The icu_new_model_buf buffer is the same as the input_buf buffer.\n"); - cfg_invalid++; - } + if (cmp_cfg_icu_buffers_is_invalid(cfg)) + return 0; - if (cfg->icu_new_model_buf == cfg->icu_output_buf) { - debug_print("Error: The icu_output_buf buffer is the same as the icu_output_buf buffer.\n"); - cfg_invalid++; - } - } + data_size = cmp_cal_size_of_data(compressed_data_len_samples, cfg->data_type); + hdr_size = cmp_ent_cal_hdr_size(cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW); - if (raw_mode_is_used(cfg->cmp_mode)) { - if (cfg->samples > cfg->buffer_length) { - debug_print("Error: The buffer_length is to small to hold the data form the input_buf.\n"); - cfg_invalid++; - } - } else { - if (cfg->samples*size_of_a_sample(cfg->cmp_mode) < - cfg->buffer_length*sizeof(uint16_t)/3) /* TODO: have samples and buffer_lengt the same unit */ - debug_print("Warning: The size of the icu_output_buf is 3 times smaller than the input_buf. This is probably unintentional.\n"); + if ((data_size + hdr_size) > CMP_ENTITY_MAX_SIZE) { + debug_print("Error: The buffer for the compressed data is too large to fit in a compression entity.\n"); + return 0; } + return data_size; +} - if (!(diff_mode_is_used(cfg->cmp_mode) - || model_mode_is_used(cfg->cmp_mode) - || raw_mode_is_used(cfg->cmp_mode))) { - debug_print("Error: selected cmp_mode: %u is not supported\n.", - cfg->cmp_mode); - if (info) - info->cmp_err |= 1UL << CMP_MODE_ERR_BIT; - cfg_invalid++; - } - if (raw_mode_is_used(cfg->cmp_mode)) /* additional checks are not needed for the raw mode */ - return -cfg_invalid; +/** + * @brief set up the configuration parameters for an ICU imagette compression + * + * @param cfg pointer to a compression configuration (created + * by the cmp_cfg_icu_create() function) + * @param cmp_par imagette compression parameter (Golomb parameter) + * @param spillover_par imagette spillover threshold parameter + * + * @returns 0 if parameters are valid, non-zero if parameters are invalid + */ - if (model_mode_is_used(cfg->cmp_mode)) { - if (cfg->model_value > MAX_MODEL_VALUE) { - debug_print("Error: selected model_value: %u is invalid. Largest supported value is: %lu.\n", - cfg->model_value, MAX_MODEL_VALUE); - if (info) - info->cmp_err |= 1UL << MODEL_VALUE_ERR_BIT; - cfg_invalid++; - } - } +int cmp_cfg_icu_imagette(struct cmp_cfg *cfg, uint32_t cmp_par, + uint32_t spillover_par) +{ + if (!cfg) + return -1; - if (cfg->golomb_par < MIN_ICU_GOLOMB_PAR || - cfg->golomb_par > MAX_ICU_GOLOMB_PAR) { - debug_print("Error: The selected Golomb parameter: %u is not supported. The Golomb parameter has to be between [%lu, %u].\n", - cfg->golomb_par, MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); - if (info) - info->cmp_err |= 1UL << CMP_PAR_ERR_BIT; - cfg_invalid++; - } + cfg->golomb_par = cmp_par; + cfg->spill = spillover_par; - if (cfg->spill < MIN_ICU_SPILL) { - debug_print("Error: The selected spillover threshold value: %u is too small. Smallest possible spillover value is: %lu.\n", - cfg->spill, MIN_ICU_SPILL); - if (info) - info->cmp_err |= 1UL << CMP_PAR_ERR_BIT; - cfg_invalid++; - } + if (cmp_cfg_imagette_is_invalid(cfg, ICU_CHECK)) + return -1; - if (cfg->spill > get_max_spill(cfg->golomb_par, cfg->cmp_mode)) { - debug_print("Error: The selected spillover threshold value: %u is too large for the selected Golomb parameter: %u, the largest possible spillover value in the selected compression mode is: %u.\n", - cfg->spill, cfg->golomb_par, - get_max_spill(cfg->golomb_par, cfg->cmp_mode)); - if (info) - info->cmp_err |= 1UL << CMP_PAR_ERR_BIT; - cfg_invalid++; - } + return 0; +} -#ifdef ADAPTIVE_CHECK_ENA - /* - * ap1_spill and ap2_spill are not used for the icu_compression - */ - if (cfg->ap1_spill > get_max_spill(cfg->ap1_golomb_par, cfg->cmp_mode)) { - if (info) - info->cmp_err |= 1UL << AP1_CMP_PAR_ERR_BIT; - cfg_invalid++; - } +/** + * @brief set up the configuration parameters for a flux/COB compression + * @note not all parameters are needed for every flux/COB compression data type + * + * @param cfg pointer to a compression configuration (created + * by the cmp_cfg_icu_create() function) + * @param cmp_par_exp_flags exposure flags compression parameter + * @param spillover_exp_flags exposure flags spillover threshold parameter + * @param cmp_par_fx normal flux compression parameter + * @param spillover_fx normal flux spillover threshold parameter + * @param cmp_par_ncob normal center of brightness compression parameter + * @param spillover_ncob normal center of brightness spillover threshold parameter + * @param cmp_par_efx extended flux compression parameter + * @param spillover_efx extended flux spillover threshold parameter + * @param cmp_par_ecob extended center of brightness compression parameter + * @param spillover_ecob extended center of brightness spillover threshold parameter + * @param cmp_par_fx_cob_variance flux/COB variance compression parameter + * @param spillover_fx_cob_variance flux/COB variance spillover threshold parameter + * + * @returns 0 if parameters are valid, non-zero if parameters are invalid + */ - if (cfg->ap2_spill > get_max_spill(cfg->ap2_golomb_par, cfg->cmp_mode)) { - if (info) - info->cmp_err |= 1UL << AP2_CMP_PAR_ERR_BIT; - cfg_invalid++; - } -#endif +int cmp_cfg_fx_cob(struct cmp_cfg *cfg, + uint32_t cmp_par_exp_flags, uint32_t spillover_exp_flags, + uint32_t cmp_par_fx, uint32_t spillover_fx, + uint32_t cmp_par_ncob, uint32_t spillover_ncob, + uint32_t cmp_par_efx, uint32_t spillover_efx, + uint32_t cmp_par_ecob, uint32_t spillover_ecob, + uint32_t cmp_par_fx_cob_variance, uint32_t spillover_fx_cob_variance) +{ + if (!cfg) + return -1; - if (cfg->round > MAX_ICU_ROUND) { - debug_print("Error: selected round parameter: %u is not supported. Largest supported value is: %lu.\n", - cfg->round, MAX_ICU_ROUND); - cfg_invalid++; - } + cfg->cmp_par_exp_flags = cmp_par_exp_flags; + cfg->cmp_par_fx = cmp_par_fx; + cfg->cmp_par_ncob = cmp_par_ncob; + cfg->cmp_par_efx = cmp_par_efx; + cfg->cmp_par_ecob = cmp_par_ecob; + cfg->cmp_par_fx_cob_variance = cmp_par_fx_cob_variance; + + cfg->spill_exp_flags = spillover_exp_flags; + cfg->spill_fx = spillover_fx; + cfg->spill_ncob = spillover_ncob; + cfg->spill_efx = spillover_efx; + cfg->spill_ecob = spillover_ecob; + cfg->spill_fx_cob_variance = spillover_fx_cob_variance; + + if (cmp_cfg_fx_cob_is_invalid(cfg)) + return -1; - return -(cfg_invalid); + return 0; } /** - * @brief sets the compression information used based on the compression - * configuration - * - * @param cfg compression configuration struct - * @param info compressor information struct to set the used compression - * parameters (can be NULL) - * - * @note set cmp_size, ap1_cmp_size, ap2_cmp_size will be set to 0 - * - * @returns 0 on success, error otherwise + * @brief set up the configuration parameters for an auxiliary science data compression + * @note auxiliary compression data types are: DATA_TYPE_OFFSET, DATA_TYPE_BACKGROUND, + DATA_TYPE_SMEARING, DATA_TYPE_F_CAM_OFFSET, DATA_TYPE_F_CAM_BACKGROUND + * @note not all parameters are needed for the every auxiliary compression data type + * + * @param cfg pointer to a compression configuration (created + * with the cmp_cfg_icu_create() function) + * @param cmp_par_mean mean compression parameter + * @param spillover_mean mean spillover threshold parameter + * @param cmp_par_variance variance compression parameter + * @param spillover_variance variance spillover threshold parameter + * @param cmp_par_pixels_error outlier pixels number compression parameter + * @param spillover_pixels_error outlier pixels number spillover threshold parameter + * + * @returns 0 if parameters are valid, non-zero if parameters are invalid */ - -static int set_info(struct cmp_cfg *cfg, struct cmp_info *info) +int cmp_cfg_aux(struct cmp_cfg *cfg, + uint32_t cmp_par_mean, uint32_t spillover_mean, + uint32_t cmp_par_variance, uint32_t spillover_variance, + uint32_t cmp_par_pixels_error, uint32_t spillover_pixels_error) { if (!cfg) return -1; - if (cfg->cmp_mode > UINT8_MAX) - return -1; + cfg->cmp_par_mean = cmp_par_mean; + cfg->cmp_par_variance = cmp_par_variance; + cfg->cmp_par_pixels_error = cmp_par_pixels_error; - if (cfg->round > UINT8_MAX) - return -1; + cfg->spill_mean = spillover_mean; + cfg->spill_variance = spillover_variance; + cfg->spill_pixels_error = spillover_pixels_error; - if (cfg->model_value > UINT8_MAX) + if (cmp_cfg_aux_is_invalid(cfg)) return -1; - if (info) { - info->cmp_err = 0; - info->cmp_mode_used = (uint8_t)cfg->cmp_mode; - info->model_value_used = (uint8_t)cfg->model_value; - info->round_used = (uint8_t)cfg->round; - info->spill_used = cfg->spill; - info->golomb_par_used = cfg->golomb_par; - info->samples_used = cfg->samples; - info->cmp_size = 0; - info->ap1_cmp_size = 0; - info->ap2_cmp_size = 0; - info->rdcu_new_model_adr_used = cfg->rdcu_new_model_adr; - info->rdcu_cmp_adr_used = cfg->rdcu_buffer_adr; - } return 0; } /** - * @brief 1d-differentiating pre-processing and rounding of a uint16_t data buffer - * - * @note change the data_buf in-place - * @note output is I[0] = I[0], I[i] = I[i] - I[i-1], where i is 1,2,..samples-1 + * @brief map a signed value into a positive value range * - * @param data_buf pointer to the uint16_t formatted data buffer to process - * @param samples amount of data samples in the data buffer - * @param round number of bits to round; if zero no rounding takes place + * @param value_to_map signed value to map + * @param max_data_bits how many bits are needed to represent the + * highest possible value * - * @returns 0 on success, error otherwise + * @returns the positive mapped value */ -static int diff_16(uint16_t *data_buf, unsigned int samples, unsigned int round) +static uint32_t map_to_pos(uint32_t value_to_map, unsigned int max_data_bits) { - size_t i; - - if (!data_buf) - return -1; - - lossy_rounding_16(data_buf, samples, round); - - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data_buf[i] = data_buf[i] - data_buf[i-1]; + uint32_t result; + uint32_t mask = (~0U >> (32 - max_data_bits)); /* mask the used bits */ + + value_to_map &= mask; + if (value_to_map >> (max_data_bits - 1)) { /* check the leading signed bit */ + value_to_map |= ~mask; /* convert to 32-bit signed integer */ + /* map negative values to uneven numbers */ + result = (-value_to_map) * 2 - 1; /* possible integer overflow is intended */ + } else { + /* map positive values to even numbers */ + result = value_to_map * 2; /* possible integer overflow is intended */ } - return 0; + + return result; } /** - * @brief 1d-differentiating pre-processing and rounding of a uint32_t data buffer - * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index - * - * @param data_buf pointer to the uint32_t formatted data buffer to process - * @param samples amount of data samples in the data_buf buffer - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise + * @brief put the value of up to 32 bits into a bitstream + * + * @param value the value to put + * @param n_bits number of bits to put in the bitstream + * @param bit_offset bit index where the bits will be put, seen from + * the very beginning of the bitstream + * @param bitstream_adr this is the pointer to the beginning of the + * bitstream (can be NULL) + * @param max_stream_len maximum length of the bitstream in bits; is + * ignored if bitstream_adr is NULL + * + * @returns length in bits of the generated bitstream on success; returns + * negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if + * the bitstream buffer is too small to put the value in the bitstream */ -static int diff_32(uint32_t *data_buf, unsigned int samples, unsigned int round) +static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset, + uint32_t *bitstream_adr, unsigned int max_stream_len) { - size_t i; + uint32_t *local_adr; + uint32_t mask; + unsigned int shiftRight, shiftLeft, bitsLeft, bitsRight; + int stream_len = (int)(n_bits + (unsigned int)bit_offset); /* overflow results in a negative return value */ - if (!data_buf) + /* Leave in case of erroneous input */ + if (bit_offset < 0) return -1; - lossy_rounding_32(data_buf, samples, round); + if (n_bits == 0) + return stream_len; - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data_buf[i] = data_buf[i] - data_buf[i-1]; + if (n_bits > 32) + return -1; + + /* Do we need to write data to the bitstream? */ + if (!bitstream_adr) + return stream_len; + + /* Check if bitstream buffer is large enough */ + if ((unsigned int)stream_len > max_stream_len) { + debug_print("Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n"); + return CMP_ERROR_SMALL_BUF; } - return 0; + + /* (M) is the n_bits parameter large enough to cover all value bits; the + * calculations can be re-used in the unsegmented code, so we have no overhead + */ + shiftRight = 32 - n_bits; + mask = 0xFFFFFFFFU >> shiftRight; + value &= mask; + + /* Separate the bit_offset into word offset (set local_adr pointer) and local bit offset (bitsLeft) */ + local_adr = bitstream_adr + (bit_offset >> 5); + bitsLeft = bit_offset & 0x1F; + + /* Calculate the bitsRight for the unsegmented case. If bitsRight is + * negative we need to split the value over two words + */ + bitsRight = shiftRight - bitsLeft; + + if ((int)bitsRight >= 0) { + /* UNSEGMENTED + * + *|-----------|XXXXX|----------------| + * bitsLeft n bitsRight + * + * -> to get the mask: + * shiftRight = bitsLeft + bitsRight = 32 - n + * shiftLeft = bitsRight = 32 - n - bitsLeft = shiftRight - bitsLeft + */ + + shiftLeft = bitsRight; + + /* generate the mask, the bits for the values will be true + * shiftRight = 32 - n_bits; see (M) above! + * mask = (0XFFFFFFFF >> shiftRight) << shiftLeft; see (M) above! + */ + mask <<= shiftLeft; + value <<= shiftLeft; + + /* clear the destination with inverse mask */ + *(local_adr) &= ~mask; + + /* assign the value */ + *(local_adr) |= value; + + } else { + /* SEGMENTED + * + *|-----------------------------|XXX| |XX|------------------------------| + * bitsLeft n1 n2 bitsRight + * + * -> to get the mask part 1: + * shiftRight = bitsLeft + * n1 = n - (bitsLeft + n - 32) = 32 - bitsLeft + * + * -> to get the mask part 2: + * n2 = bitsLeft + n - 32 = -(32 - n - bitsLeft) = -(bitsRight_UNSEGMENTED) + * shiftLeft = 32 - n2 = 32 - (bitsLeft + n - 32) = 64 - bitsLeft - n + * + */ + + unsigned int n2 = -bitsRight; + + /* part 1: */ + shiftRight = bitsLeft; + mask = 0XFFFFFFFFU >> shiftRight; + + /* clear the destination with inverse mask */ + *(local_adr) &= ~mask; + + /* assign the value part 1 */ + *(local_adr) |= (value >> n2); + + /* part 2: */ + /* adjust address */ + local_adr += 1; + shiftLeft = 32 - n2; + mask = 0XFFFFFFFFU >> n2; + + /* clear the destination */ + *(local_adr) &= mask; + + /* assign the value part 2 */ + *(local_adr) |= (value << shiftLeft); + } + return stream_len; } /** - * @brief 1d-differentiating pre-processing and round of a S_FX data buffer - * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index + * @brief forms the codeword according to the Rice code * - * @param data pointer to a S_FX data buffer - * @param samples amount of data samples in the data buffer - * @param round number of bits to round; if zero no rounding takes place + * @param value value to be encoded + * @param m Golomb parameter, only m's which are power of 2 are allowed + * @param log2_m Rice parameter, is log_2(m) calculate outside function + * for better performance + * @param cw address were the encode code word is stored * - * @returns 0 on success, error otherwise + * @returns the length of the formed code word in bits + * @note no check if the generated code word is not longer than 32 bits! */ -static int diff_S_FX(struct S_FX *data, unsigned int samples, unsigned int - round) +static uint32_t rice_encoder(uint32_t value, uint32_t m, uint32_t log2_m, + uint32_t *cw) { - size_t i; - int err; + uint32_t g; /* quotient of value/m */ + uint32_t q; /* quotient code without ending zero */ + uint32_t r; /* remainder of value/m */ + uint32_t rl; /* remainder length */ - if (!data) - return -1; + g = value >> log2_m; /* quotient, number of leading bits */ + q = (1U << g) - 1; /* prepare the quotient code without ending zero */ - err = lossy_rounding_S_FX(data, samples, round); - if (err) - return err; + r = value & (m-1); /* calculate the remainder */ + rl = log2_m + 1; /* length of the remainder (+1 for the 0 in the quotient code) */ + *cw = (q << rl) | r; /* put the quotient and remainder code together */ + /* + * NOTE: If log2_m = 31 -> rl = 32, (q << rl) leads to an undefined + * behavior. However, in this case, a valid code with a maximum of 32 + * bits can only be formed if q = 0. Any shift with 0 << x always + * results in 0, which forms the correct codeword in this case. For + * performance reasons, this undefined behaviour is not caught. + */ - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data[i] = sub_S_FX(data[i], data[i-1]); - } - return 0; + return rl + g; /* calculate the length of the code word */ } /** - * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX data buffer + * @brief forms a codeword according to the Golomb code * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index - * - * @param data pointer to a S_FX_EFX data buffer - * @param samples amount of data samples in the data buffer - * @param round number of bits to round; if zero no rounding takes place + * @param value value to be encoded + * @param m Golomb parameter (have to be bigger than 0) + * @param log2_m is log_2(m) calculate outside function for better + * performance + * @param cw address were the formed code word is stored * - * @returns 0 on success, error otherwise + * @returns the length of the formed code word in bits + * @note no check if the generated code word is not longer than 32 bits! */ -static int diff_S_FX_EFX(struct S_FX_EFX *data, unsigned int samples, unsigned - int round) +static uint32_t golomb_encoder(uint32_t value, uint32_t m, uint32_t log2_m, + uint32_t *cw) { - size_t i; - int err; - - if (!data) - return -1; + uint32_t len0, b, g, q, lg; + uint32_t len; + uint32_t cutoff; - err = lossy_rounding_S_FX_EFX(data, samples, round); - if (err) - return err; + len0 = log2_m + 1; /* codeword length in group 0 */ + cutoff = (1U << (log2_m + 1)) - m; /* members in group 0 */ - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data[i] = sub_S_FX_EFX(data[i], data[i-1]); + if (value < cutoff) { /* group 0 */ + *cw = value; + len = len0; + } else { /* other groups */ + g = (value-cutoff) / m; /* this group is which one */ + b = cutoff << 1; /* form the base codeword */ + lg = len0 + g; /* it has lg remainder bits */ + q = (1U << g) - 1; /* prepare the left side in unary */ + *cw = (q << (len0+1)) + b + (value-cutoff) - g*m; /* composed codeword */ + len = lg + 1; /* length of the codeword */ } - return 0; + return len; } /** - * @brief 1d-differentiating pre-processing and rounding of a S_FX_NCOB data buffer - * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index + * @brief generate a code word without an outlier mechanism and put in the + * bitstream * - * @param data pointer to a S_FX_NCOB data buffer - * @param samples amount of data samples in the data buffer - * @param round number of bits to round; if zero no rounding takes place + * @param value value to encode in the bitstream + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream with the added encoded value on + * success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer + * is too small to put the value in the bitstream */ -static int diff_S_FX_NCOB(struct S_FX_NCOB *data, unsigned int samples, unsigned - int round) +static int encode_normal(uint32_t value, int stream_len, + const struct encoder_setupt *setup) { - size_t i; - int err; - - if (!data) - return -1; + uint32_t code_word, cw_len; - err = lossy_rounding_S_FX_NCOB(data, samples, round); - if (err) - return err; + cw_len = setup->generate_cw_f(value, setup->encoder_par1, + setup->encoder_par2, &code_word); - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data[i] = sub_S_FX_NCOB(data[i], data[i-1]); - } - return 0; + return put_n_bits32(code_word, cw_len, stream_len, setup->bitstream_adr, + setup->max_stream_len); } /** - * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX_NCOB_ECOB data buffer + * @brief subtract the model from the data, encode the result and put it into + * bitstream, for encoding outlier use the zero escape symbol mechanism * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index + * @param data data to encode + * @param model model of the data (0 if not used) + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup * - * @param data pointer to a S_FX_EFX_NCOB_ECOB data buffer - * @param samples amount of data samples in the data buffer - * @param round number of bits to round; if zero no rounding takes place + * @returns the bit length of the bitstream with the added encoded value on + * success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer + * is too small to put the value in the bitstream * - * @returns 0 on success, error otherwise + * @note no check if the data or model are in the allowed range + * @note no check if the setup->spillover_par is in the allowed range */ -static int diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data, unsigned int - samples, unsigned int round) +static int encode_value_zero(uint32_t data, uint32_t model, int stream_len, + const struct encoder_setupt *setup) { - size_t i; - int err; - - if (!data) - return -1; + data -= model; /* possible underflow is intended */ - err = lossy_rounding_S_FX_EFX_NCOB_ECOB(data, samples, round); - if (err) - return err; + data = map_to_pos(data, setup->max_data_bits); - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data[i] = sub_S_FX_EFX_NCOB_ECOB(data[i], data[i-1]); + /* For performance reasons, we check to see if there is an outlier + * before adding one, rather than the other way around: + * data++; + * if (data < setup->spillover_par && data != 0) + * return ... + */ + if (data < (setup->spillover_par - 1)) { /* detect non-outlier */ + data++; /* add 1 to every value so we can use 0 as escape symbol */ + return encode_normal(data, stream_len, setup); } - return 0; + data++; /* add 1 to every value so we can use 0 as escape symbol */ + + /* use zero as escape symbol */ + stream_len = encode_normal(0, stream_len, setup); + if (stream_len <= 0) + return stream_len; + + /* put the data unencoded in the bitstream */ + stream_len = put_n_bits32(data, setup->max_data_bits, stream_len, + setup->bitstream_adr, setup->max_stream_len); + + return stream_len; } /** - * @brief model pre-processing and rounding of a uint16_t data buffer + * @brief subtract the model from the data, encode the result and put it into + * bitstream, for encoding outlier use the multi escape symbol mechanism * - * @note overwrite the data_buf in-place with the result - * @note update the model_buf in-place if up_model_buf = NULL + * @param data data to encode + * @param model model of the data (0 if not used) + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup * - * @param data_buf pointer to the uint16_t data buffer to process - * @param model_buf pointer to the model buffer of the data to process - * @param up_model_buf pointer to the updated model buffer can be NULL - * @param samples amount of data samples in the data_buf and model_buf buffer - * @param model_value model weighting parameter - * @param round number of bits to round; if zero no rounding takes place + * @returns the bit length of the bitstream with the added encoded value on + * success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer + * is too small to put the value in the bitstream * - * @returns 0 on success, error otherwise + * @note no check if the data or model are in the allowed range + * @note no check if the setup->spillover_par is in the allowed range */ -static int model_16(uint16_t *data_buf, uint16_t *model_buf, uint16_t *up_model_buf, - unsigned int samples, unsigned int model_value, unsigned int round) +static int encode_value_multi(uint32_t data, uint32_t model, int stream_len, + const struct encoder_setupt *setup) { - size_t i; + uint32_t unencoded_data; + unsigned int unencoded_data_len; + uint32_t escape_sym, escape_sym_offset; - if (!data_buf) - return -1; + data -= model; /* possible underflow is intended */ - if (!model_buf) - return -1; + data = map_to_pos(data, setup->max_data_bits); - if (model_value > MAX_MODEL_VALUE) - return -1; + if (data < setup->spillover_par) /* detect non-outlier */ + return encode_normal(data, stream_len, setup); + + /* + * In this mode we put the difference between the data and the spillover + * threshold value (unencoded_data) after an encoded escape symbol, which + * indicate that the next codeword is unencoded. + * We use different escape symbol depended on the size the needed bit of + * unencoded data: + * 0, 1, 2 bits needed for unencoded data -> escape symbol is spillover_par + 0 + * 3, 4 bits needed for unencoded data -> escape symbol is spillover_par + 1 + * 5, 6 bits needed for unencoded data -> escape symbol is spillover_par + 2 + * and so on + */ + unencoded_data = data - setup->spillover_par; - if (!up_model_buf) - up_model_buf = model_buf; + if (!unencoded_data) /* catch __builtin_clz(0) because the result is undefined.*/ + escape_sym_offset = 0; + else + escape_sym_offset = (31U - (uint32_t)__builtin_clz(unencoded_data)) >> 1; - for (i = 0; i < samples; i++) { - uint16_t round_input = (uint16_t)round_fwd(data_buf[i], round); - uint16_t round_model = (uint16_t)round_fwd(model_buf[i], round); - /* possible underflow is intended */ - data_buf[i] = round_input - round_model; /* TDOO: check if this is the right order */ - /* round back input because for decompression the accurate data - * are not available - */ - up_model_buf[i] = (uint16_t)cal_up_model(round_inv(round_input, round), - model_buf[i], model_value); - } - return 0; + escape_sym = setup->spillover_par + escape_sym_offset; + unencoded_data_len = (escape_sym_offset + 1U) << 1; + + /* put the escape symbol in the bitstream */ + stream_len = encode_normal(escape_sym, stream_len, setup); + if (stream_len <= 0) + return stream_len; + + /* put the unencoded data in the bitstream */ + stream_len = put_n_bits32(unencoded_data, unencoded_data_len, stream_len, + setup->bitstream_adr, setup->max_stream_len); + + return stream_len; } /** - * @brief model pre-processing and round_input of a uint32_t data buffer + * @brief put the value unencoded with setup->cmp_par_1 bits without any changes + * in the bitstream * - * @note overwrite the data_buf in-place with the result - * @note update the model_buf in-place if up_model_buf = NULL + * @param value value to put unchanged in the bitstream + * (setup->cmp_par_1 how many bits of the value are used) + * @param unused this parameter is ignored + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup * - * @param data_buf pointer to the uint32_t data buffer to process - * @param model_buf pointer to the model buffer of the data to process - * @param samples amount of data samples in the data_buf and model_buf buffer - * @param model_value model weighting parameter - * @param round number of bits to round; if zero no rounding takes place + * @returns the bit length of the bitstream with the added unencoded value on + * success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer + * is too small to put the value in the bitstream * - * @returns 0 on success, error otherwise */ -static int model_32(uint32_t *data_buf, uint32_t *model_buf, unsigned int samples, - unsigned int model_value, unsigned int round) +static int encode_value_none(uint32_t value, uint32_t unused, int stream_len, + const struct encoder_setupt *setup) { - size_t i; + (void)(unused); - if (!data_buf) - return -1; + return put_n_bits32(value, setup->encoder_par1, stream_len, + setup->bitstream_adr, setup->max_stream_len); +} - if (!model_buf) - return -1; - if (model_value > MAX_MODEL_VALUE) - return -1; +/** + * @brief encodes the data with the model and the given setup and put it into + * the bitstream + * + * @param data data to encode + * @param model model of the data (0 if not used) + * @param stream_len length of the bitstream in bits + * @param setup pointer to the encoder setup + * + * @returns the bit length of the bitstream with the added encoded value on + * success; negative on error, CMP_ERROR_SMALL_BUF if the bitstream buffer + * is too small to put the value in the bitstream, CMP_ERROR_HIGH_VALUE if + * the value or the model is bigger than the max_used_bits parameter allows + */ - for (i = 0; i < samples; i++) { - uint32_t round_input = round_fwd(data_buf[i], round); - uint32_t round_model = round_fwd(model_buf[i], round); - /* possible underflow is intended */ - data_buf[i] = round_input - round_model; - /* round back input because for decompression the accurate data - * are not available - */ - model_buf[i] = cal_up_model(round_inv(round_input, round), - model_buf[i], model_value); +static int encode_value(uint32_t data, uint32_t model, int stream_len, + const struct encoder_setupt *setup) +{ + uint32_t mask = ~(0xFFFFFFFFU >> (32-setup->max_data_bits)); + + /* lossy rounding of the data if lossy_par > 0 */ + data = round_fwd(data, setup->lossy_par); + model = round_fwd(model, setup->lossy_par); + + if (data & mask || model & mask) { + debug_print("Error: The data or the model of the data are bigger than expected.\n"); + return CMP_ERROR_HIGH_VALUE; } - return 0; + + return setup->encode_method_f(data, model, stream_len, setup); } /** - * @brief model pre-processing and round_input of a S_FX data buffer + * @brief calculate the maximum length of the bitstream/icu_output_buf in bits + * @note we round down to the next 4-byte allied address because we access the + * cmp_buffer in uint32_t words * - * @note overwrite the data_buf in-place with the result - * @note update the model_buf in-place if up_model_buf = NULL + * @param buffer_length length of the icu_output_buf in samples + * @param data_type used compression data type * - * @param data_buf pointer to the S_FX data buffer to process - * @param model_buf pointer to the updated model buffer (if NULL model_buf - * will be overwrite with the updated model) - * @param samples amount of data samples in the data_buf and model_buf buffer - * @param model_value model weighting parameter - * @param round number of bits to round; if zero no rounding takes place + * @returns buffer size in bits * - * @returns 0 on success, error otherwise */ -int model_S_FX(struct S_FX *data_buf, struct S_FX *model_buf, - struct S_FX *up_model_buf, unsigned int samples, - unsigned int model_value, unsigned int round) +static uint32_t cmp_buffer_length_to_bits(uint32_t buffer_length, enum cmp_data_type data_type) { - size_t i; + return (cmp_cal_size_of_data(buffer_length, data_type) & ~0x3U) * CHAR_BIT; +} - if (!samples) - return 0; - if (!model_buf) +/** + * @brief configure an encoder setup structure to have a setup to encode a vale + * + * @param setup pointer to the encoder setup + * @param cmp_par compression parameter + * @param spillover spillover_par parameter + * @param lossy_par lossy compression parameter + * @param max_data_bits how many bits are needed to represent the highest possible value + * @param cfg pointer to the compression configuration structure + * + * @returns 0 on success; otherwise error + */ + +static int configure_encoder_setup(struct encoder_setupt *setup, + uint32_t cmp_par, uint32_t spillover, + uint32_t lossy_par, uint32_t max_data_bits, + const struct cmp_cfg *cfg) +{ + if (!setup) return -1; - if (model_value > MAX_MODEL_VALUE) + if (!cfg) return -1; - if (!up_model_buf) /* overwrite the model buffer if no up_model_buf is set */ - up_model_buf = model_buf; + if (max_data_bits > 32) { + debug_print("Error: max_data_bits parameter is bigger than 32 bits.\n"); + return -1; + } + memset(setup, 0, sizeof(*setup)); - for (i = 0; i < samples; i++) { - struct S_FX round_data = data_buf[i]; - struct S_FX round_model = model_buf[i]; - int err; + setup->encoder_par1 = cmp_par; + setup->max_data_bits = max_data_bits; + setup->lossy_par = lossy_par; + setup->bitstream_adr = cfg->icu_output_buf; + setup->max_stream_len = cmp_buffer_length_to_bits(cfg->buffer_length, cfg->data_type); - err = lossy_rounding_S_FX(&round_data, 1, round); - if (err) - return err; + if (cfg->cmp_mode != CMP_MODE_STUFF) { + if (ilog_2(cmp_par) < 0) + return -1; + setup->encoder_par2 = (uint32_t)ilog_2(cmp_par); - err = lossy_rounding_S_FX(&round_model, 1, round); - if (err) - return err; + setup->spillover_par = spillover; - /* possible underflow is intended */ - data_buf[i] = sub_S_FX(round_data, round_model); + /* for encoder_par1 which are a power of two we can use the faster rice_encoder */ + if (is_a_pow_of_2(setup->encoder_par1)) + setup->generate_cw_f = &rice_encoder; + else + setup->generate_cw_f = &golomb_encoder; + } - /* round back input because for decompression the accurate data - * are not available - */ - err = de_lossy_rounding_S_FX(&round_data, 1, round); - if (err) - return err; - up_model_buf[i] = cal_up_model_S_FX(round_data, model_buf[i], - model_value); + switch (cfg->cmp_mode) { + case CMP_MODE_MODEL_ZERO: + case CMP_MODE_DIFF_ZERO: + setup->encode_method_f = &encode_value_zero; + break; + case CMP_MODE_MODEL_MULTI: + case CMP_MODE_DIFF_MULTI: + setup->encode_method_f = &encode_value_multi; + break; + case CMP_MODE_STUFF: + setup->encode_method_f = &encode_value_none; + setup->max_data_bits = cmp_par; + break; + case CMP_MODE_RAW: + default: + return -1; } + return 0; } /** - * @brief data pre-processing to decorrelate the data + * @brief compress imagette data * - * @param cfg configuration contains all parameters required for compression + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream, CMP_ERROR_HIGH_VALUE if the value or the model is + * bigger than the max_used_bits parameter allows */ -int cmp_pre_process(struct cmp_cfg *cfg) +static int compress_imagette(const struct cmp_cfg *cfg) { - if (!cfg) - return -1; + int err; + int stream_len = 0; + size_t i; + struct encoder_setupt setup; - if (cfg->samples == 0) - return 0; + uint16_t *data_buf = cfg->input_buf; + uint16_t *model_buf = cfg->model_buf; + uint16_t model = 0; + uint16_t *next_model_p = data_buf; + uint16_t *up_model_buf = NULL; - if (!cfg->input_buf) + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + up_model_buf = cfg->icu_new_model_buf; + } + + err = configure_encoder_setup(&setup, cfg->golomb_par, cfg->spill, + cfg->round, max_used_bits.nc_imagette, cfg); + if (err) return -1; - switch (cfg->cmp_mode) { - case MODE_RAW: - case MODE_RAW_S_FX: - return 0; /* in raw mode no pre-processing is necessary */ - break; - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - return model_16((uint16_t *)cfg->input_buf, (uint16_t *)cfg->model_buf, - (uint16_t *)cfg->icu_new_model_buf, cfg->samples, - cfg->model_value, cfg->round); - break; - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - return diff_16((uint16_t *)cfg->input_buf, cfg->samples, - cfg->round); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - return model_S_FX((struct S_FX *)cfg->input_buf, (struct S_FX *)cfg->model_buf, - (struct S_FX *)cfg->icu_new_model_buf, cfg->samples, - cfg->model_value, cfg->round); - break; - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return diff_S_FX((struct S_FX *)cfg->input_buf, cfg->samples, cfg->round); - break; - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return diff_S_FX_EFX((struct S_FX_EFX *)cfg->input_buf, - cfg->samples, cfg->round); - break; - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return diff_S_FX_NCOB((struct S_FX_NCOB *)cfg->input_buf, - cfg->samples, cfg->round); - break; - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return diff_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *)cfg->input_buf, - cfg->samples, cfg->round); - break; - case MODE_MODEL_ZERO_32: - case MODE_MODEL_MULTI_32: - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - return model_32((uint32_t *)cfg->input_buf, (uint32_t *)cfg->model_buf, - cfg->samples, cfg->model_value, cfg->round); - break; - case MODE_DIFF_ZERO_32: - case MODE_DIFF_MULTI_32: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - return diff_32((uint32_t *)cfg->input_buf, cfg->samples, cfg->round); - break; - default: - debug_print("Error: Compression mode not supported.\n"); - } - - return -1; -} + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i], model, stream_len, &setup); + if (stream_len <= 0) + break; + if (up_model_buf) + up_model_buf[i] = cmp_up_model(data_buf[i], model, cfg->model_value, + setup.lossy_par); + if (i >= cfg->samples-1) + break; -static uint8_t map_to_pos_alg_8(int8_t value_to_map) -{ - if (value_to_map < 0) - /* NOTE: possible integer overflow is intended */ - return (uint8_t)((-value_to_map) * 2 - 1); - else - /* NOTE: possible integer overflow is intended */ - return (uint8_t)(value_to_map * 2); + model = next_model_p[i]; + } + return stream_len; } -static uint16_t map_to_pos_alg_16(int16_t value_to_map) +/** + * @brief compress the multi-entry packet header structure and sets the data, + * model and up_model pointers to the data after the header + * + * @param data pointer to a pointer pointing to the data to be compressed + * @param model pointer to a pointer pointing to the model of the data + * @param up_model pointer to a pointer pointing to the updated model buffer + * @param compressed_data pointer to the compressed data buffer + * + * @returns the bit length of the bitstream on success; negative on error, + * + * @note the (void **) cast relies on all pointer types having the same internal + * representation which is common, but not universal; http://www.c-faq.com/ptrs/genericpp.html + */ + +static int compress_multi_entry_hdr(void **data, void **model, void **up_model, + void *compressed_data) { - if (value_to_map < 0) - /* NOTE: possible integer overflow is intended */ - return (uint16_t)((-value_to_map) * 2 - 1); - else - /* NOTE: possible integer overflow is intended */ - return (uint16_t)(value_to_map * 2); -} + if (*up_model) { + if (*data) + memcpy(*up_model, *data, MULTI_ENTRY_HDR_SIZE); + *up_model = (uint8_t *)*up_model + MULTI_ENTRY_HDR_SIZE; + } + + if (*data) { + if (compressed_data) + memcpy(compressed_data, *data, MULTI_ENTRY_HDR_SIZE); + *data = (uint8_t *)*data + MULTI_ENTRY_HDR_SIZE; + } + if (*model) + *model = (uint8_t *)*model + MULTI_ENTRY_HDR_SIZE; -static uint32_t map_to_pos_alg_32(int32_t value_to_map) -{ - if (value_to_map < 0) - /* NOTE: possible integer overflow is intended */ - return (uint32_t)((-value_to_map) * 2 - 1); - else - /* NOTE: possible integer overflow is intended */ - return (uint32_t)(value_to_map * 2); + return MULTI_ENTRY_HDR_SIZE * CHAR_BIT; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range for a 16 bit buffer - * - * @note overwrite the data_buf in-place with the result + * @brief compress short normal light flux (S_FX) data * - * @param data_buf pointer to the uint16_t data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static int map_to_pos_16(uint16_t *data_buf, uint32_t samples, int zero_mode_used) +static int compress_s_fx(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) + struct s_fx *data_buf = cfg->input_buf; + struct s_fx *model_buf = cfg->model_buf; + struct s_fx *up_model_buf = NULL; + struct s_fx *next_model_p; + struct s_fx model; + struct encoder_setupt setup_exp_flag, setup_fx; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg); + if (err) return -1; - for (i = 0; i < samples; i++) { - data_buf[i] = map_to_pos_alg_16(data_buf[i]); - if (zero_mode_used) - data_buf[i] += 1; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_len; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range for a 32 bit buffer - * - * @note overwrite the data_buf in-place with the result + * @brief compress S_FX_EFX data * - * @param data_buf pointer to the uint32_t data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static int map_to_pos_32(uint32_t *data_buf, uint32_t samples, int - zero_mode_used) +static int compress_s_fx_efx(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) + struct s_fx_efx *data_buf = cfg->input_buf; + struct s_fx_efx *model_buf = cfg->model_buf; + struct s_fx_efx *up_model_buf = NULL; + struct s_fx_efx *next_model_p; + struct s_fx_efx model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_efx; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.s_efx, cfg); + if (err) return -1; - for (i = 0; i < samples; i++) { - data_buf[i] = map_to_pos_alg_32(data_buf[i]); - if (zero_mode_used) - data_buf[i] += 1; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].efx, model.efx, + stream_len, &setup_efx); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_len; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range for a S_FX buffer - * - * @note overwrite the data_buf in-place with the result + * @brief compress S_FX_NCOB data * - * @param data_buf pointer to the S_FX data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -int map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples, int - zero_mode_used) +static int compress_s_fx_ncob(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) - return -1; + struct s_fx_ncob *data_buf = cfg->input_buf; + struct s_fx_ncob *model_buf = cfg->model_buf; + struct s_fx_ncob *up_model_buf = NULL; + struct s_fx_ncob *next_model_p; + struct s_fx_ncob model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - for (i = 0; i < samples; i++) { - data_buf[i].EXPOSURE_FLAGS = - map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX); + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.s_ncob, cfg); + if (err) + return -1; - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS += 1; */ - data_buf[i].FX += 1; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_len; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range for a S_FX_EFX buffer - * - * @note overwrite the data_buf in-place with the result + * @brief compress S_FX_EFX_NCOB_ECOB data * - * @param data_buf pointer to the S_FX_EFX data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static int map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples, int - zero_mode_used) +static int compress_s_fx_efx_ncob_ecob(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) - return -1; + struct s_fx_efx_ncob_ecob *data_buf = cfg->input_buf; + struct s_fx_efx_ncob_ecob *model_buf = cfg->model_buf; + struct s_fx_efx_ncob_ecob *up_model_buf = NULL; + struct s_fx_efx_ncob_ecob *next_model_p; + struct s_fx_efx_ncob_ecob model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob, setup_efx, + setup_ecob; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); - for (i = 0; i < samples; i++) { - data_buf[i].EXPOSURE_FLAGS = - map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].EFX = map_to_pos_alg_32(data_buf[i].EFX); + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.s_ncob, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.s_efx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->round, max_used_bits.s_ecob, cfg); + if (err) + return -1; - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS += 1; */ - data_buf[i].FX += 1; - data_buf[i].EFX += 1; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].efx, model.efx, + stream_len, &setup_efx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ecob_x, model.ecob_x, + stream_len, &setup_ecob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ecob_y, model.ecob_y, + stream_len, &setup_ecob); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y, + cfg->model_value, setup_ecob.lossy_par); } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_len; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range for a S_FX_NCOB buffer - * - * @note overwrite the data_buf in-place with the result + * @brief compress F_FX data * - * @param data_buf pointer to the S_FX_NCOB data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static int map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t samples, - int zero_mode_used) +static int compress_f_fx(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) + struct f_fx *data_buf = cfg->input_buf; + struct f_fx *model_buf = cfg->model_buf; + struct f_fx *up_model_buf = NULL; + struct f_fx *next_model_p; + struct f_fx model; + struct encoder_setupt setup_fx; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg); + if (err) return -1; - for (i = 0; i < samples; i++) { - data_buf[i].EXPOSURE_FLAGS = - map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = map_to_pos_alg_32(data_buf[i].NCOB_Y); + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS += 1; */ - data_buf[i].FX += 1; - data_buf[i].NCOB_X += 1; - data_buf[i].NCOB_Y += 1; + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_len; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range for a S_FX_EFX_NCOB_ECOB buffer + * @brief compress F_FX_EFX data * - * @note overwrite the data_buf in-place with the result + * @param cfg pointer to the compression configuration structure * - * @param data_buf pointer to the S_FX_EFX_NCOB_ECOB data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static int map_to_pos_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - uint32_t samples, int zero_mode_used) +static int compress_f_fx_efx(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) - return -1; - - for (i = 0; i < samples; i++) { - data_buf[i].EXPOSURE_FLAGS = - map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = map_to_pos_alg_32(data_buf[i].NCOB_Y); - data_buf[i].EFX = map_to_pos_alg_32(data_buf[i].EFX); - data_buf[i].ECOB_X = map_to_pos_alg_32(data_buf[i].ECOB_X); - data_buf[i].ECOB_Y = map_to_pos_alg_32(data_buf[i].ECOB_Y); - - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS += 1; */ - data_buf[i].FX += 1; - data_buf[i].NCOB_X += 1; - data_buf[i].NCOB_Y += 1; - data_buf[i].EFX += 1; - data_buf[i].ECOB_X += 1; - data_buf[i].ECOB_Y += 1; + struct f_fx_efx *data_buf = cfg->input_buf; + struct f_fx_efx *model_buf = cfg->model_buf; + struct f_fx_efx *up_model_buf = NULL; + struct f_fx_efx *next_model_p; + struct f_fx_efx model; + struct encoder_setupt setup_fx, setup_efx; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.f_efx, cfg); + if (err) + return -1; + + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].efx, model.efx, + stream_len, &setup_efx); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_len; } /** - * @brief map the signed output of the pre-processing stage to a unsigned value - * range - * - * @note change the data_buf in-place + * @brief compress F_FX_NCOB data * - * @param cfg configuration contains all parameters required for compression + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -int cmp_map_to_pos(struct cmp_cfg *cfg) +static int compress_f_fx_ncob(const struct cmp_cfg *cfg) { - int zero_mode_used; + int err; + int stream_len = 0; + size_t i; - if (!cfg) - return -1; + struct f_fx_ncob *data_buf = cfg->input_buf; + struct f_fx_ncob *model_buf = cfg->model_buf; + struct f_fx_ncob *up_model_buf = NULL; + struct f_fx_ncob *next_model_p; + struct f_fx_ncob model; + struct encoder_setupt setup_fx, setup_ncob; - if (cfg->samples == 0) - return 0; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!cfg->input_buf) + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.f_ncob, cfg); + if (err) return -1; - zero_mode_used = zero_escape_mech_is_used(cfg->cmp_mode); + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + } - switch (cfg->cmp_mode) { - case MODE_RAW: - case MODE_RAW_S_FX: - return 0; /* in raw mode no mapping is necessary */ - break; - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - return map_to_pos_16((uint16_t *)cfg->input_buf, cfg->samples, - zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return map_to_pos_S_FX((struct S_FX *)cfg->input_buf, - cfg->samples, zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return map_to_pos_S_FX_EFX((struct S_FX_EFX *)cfg->input_buf, - cfg->samples, zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return map_to_pos_S_FX_NCOB((struct S_FX_NCOB *)cfg->input_buf, - cfg->samples, zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return map_to_pos_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *)cfg->input_buf, - cfg->samples, zero_mode_used); - break; - case MODE_MODEL_ZERO_32: - case MODE_MODEL_MULTI_32: - case MODE_DIFF_ZERO_32: - case MODE_DIFF_MULTI_32: - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - return map_to_pos_32((uint32_t *)cfg->input_buf, cfg->samples, - zero_mode_used); - break; - default: - debug_print("Error: Compression mode not supported.\n"); - break; + if (i >= cfg->samples-1) + break; + model = next_model_p[i]; } - - return -1; + return stream_len; } /** - * @brief forms the codeword accurate to the Rice code and returns its length + * @brief compress F_FX_EFX_NCOB_ECOB data * - * @param m Golomb parameter, only m's which are power of 2 and >0 - * are allowed! - * @param log2_m Rice parameter, is log_2(m) calculate outside function - * for better performance - * @param value value to be encoded - * @param cw address were the encode code word is stored + * @param cfg pointer to the compression configuration structure * - * @returns length of the encoded code word in bits + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static unsigned int Rice_encoder(unsigned int value, unsigned int m, - unsigned int log2_m, unsigned int *cw) +static int compress_f_fx_efx_ncob_ecob(const struct cmp_cfg *cfg) { - unsigned int g; /* quotient of value/m */ - unsigned int q; /* quotient code without ending zero */ - unsigned int r; /* remainder of value/m */ - unsigned int rl; /* remainder length */ + int err; + int stream_len = 0; + size_t i; - g = value >> log2_m; /* quotient, number of leading bits */ - q = (1U << g) - 1; /* prepare the quotient code without ending zero */ + struct f_fx_efx_ncob_ecob *data_buf = cfg->input_buf; + struct f_fx_efx_ncob_ecob *model_buf = cfg->model_buf; + struct f_fx_efx_ncob_ecob *up_model_buf = NULL; + struct f_fx_efx_ncob_ecob *next_model_p; + struct f_fx_efx_ncob_ecob model; + struct encoder_setupt setup_fx, setup_ncob, setup_efx, setup_ecob; - r = value & (m-1); /* calculate the remainder */ - rl = log2_m + 1; /* length of the remainder (+1 for the 0 in the - * quotient code) - */ - *cw = (q << rl) | r; /* put the quotient and remainder code together */ + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - return rl + g; /* calculate the length of the code word */ + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.f_ncob, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.f_efx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->round, max_used_bits.f_ecob, cfg); + if (err) + return -1; + + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].efx, model.efx, + stream_len, &setup_efx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ecob_x, model.ecob_x, + stream_len, &setup_ecob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ecob_y, model.ecob_y, + stream_len, &setup_ecob); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y, + cfg->model_value, setup_ecob.lossy_par); + } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; + } + return stream_len; } /** - * @brief forms the codeword accurate to the Golomb code and returns its length + * @brief compress L_FX data * - * @param m Golomb parameter, only m's which are power of 2 and >0 - * are allowed! - * @param log2_m is log_2(m) calculate outside function for better - * performance - * @param value value to be encoded - * @param cw address were the encode code word is stored + * @param cfg pointer to the compression configuration structure * - * @returns length of the encoded code word in bits + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static unsigned int Golomb_encoder(unsigned int value, unsigned int m, - unsigned int log2_m, unsigned int *cw) +static int compress_l_fx(const struct cmp_cfg *cfg) { - unsigned int len0, b, g, q, lg; - unsigned int len; - unsigned int cutoff; + int err; + int stream_len = 0; + size_t i; - len0 = log2_m + 1; /* codeword length in group 0 */ - cutoff = (1U << (log2_m+1)) - m; /* members in group 0 */ - if (cutoff == 0) /* for powers of two we fix cutoff = m */ - cutoff = m; + struct l_fx *data_buf = cfg->input_buf; + struct l_fx *model_buf = cfg->model_buf; + struct l_fx *up_model_buf = NULL; + struct l_fx *next_model_p; + struct l_fx model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_fx_var; - if (value < cutoff) { /* group 0 */ - *cw = value; - len = len0; - } else { /* other groups */ - b = (cutoff << 1); /* form the base codeword */ - g = (value-cutoff)/m; /* this group is which one */ - lg = len0 + g; /* it has lg remainder bits */ - q = (1U << g) - 1; /* prepare the left side in unary */ - *cw = (q << (len0+1)) + b + (value-cutoff)-g*m; /* composed codeword */ - len = lg + 1; /* length of the codeword */ + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; } - return len; -} + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg); + if (err) + return -1; -typedef unsigned int (*encoder_ptr)(unsigned int, unsigned int, unsigned int, - unsigned int*); + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance, + stream_len, &setup_fx_var); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + } -static encoder_ptr select_encoder(unsigned int golomb_par) -{ - if (!golomb_par) - return NULL; + if (i >= cfg->samples-1) + break; - if (is_a_pow_of_2(golomb_par)) - return &Rice_encoder; - else - return &Golomb_encoder; + model = next_model_p[i]; + } + return stream_len; } /** - * @brief safe (but slow) way to put the value of up to 32 bits into a - * bitstream accessed as 32-bit RAM in big endian - * @param value the value to put, it will be masked - * @param bitOffset bit index where the bits will be put, seen from the very - * beginning of the bitstream - * @param nBits number of bits to put in the bitstream - * @param destAddr this is the pointer to the beginning of the bitstream - * @param dest_len length of the bitstream buffer (starting at destAddr) - * @returns TODO number of bits written, 0 if the number was too big, -2 if the - * destAddr buffer is to small to store the bitstream - * @note works in SRAM2 + * @brief compress L_FX_EFX data + * + * @param cfg pointer to the compression configuration structure + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream */ -static unsigned int put_n_bits32(unsigned int value, unsigned int bitOffset, - unsigned int nBits, unsigned int *destAddr, - unsigned int dest_len) +static int compress_l_fx_efx(const struct cmp_cfg *cfg) { - unsigned int *localAddr; - unsigned int bitsLeft, shiftRight, shiftLeft, localEndPos; - unsigned int mask; + int err; + int stream_len = 0; + size_t i; - if (!destAddr) - return nBits; + struct l_fx_efx *data_buf = cfg->input_buf; + struct l_fx_efx *model_buf = cfg->model_buf; + struct l_fx_efx *up_model_buf = NULL; + struct l_fx_efx *next_model_p; + struct l_fx_efx model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_efx, setup_fx_var; - /* check if destination buffer is large enough */ - /* TODO: adapt that to the other science products */ - if ((bitOffset + nBits) > ((dest_len&~0x1U)*16)) { - debug_print("Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n"); - return -2U; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; } - /* leave in case of erroneous input */ - if (nBits == 0) - return 0; - if (nBits > 32) - return 0; + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.l_efx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg); + if (err) + return -1; - /* separate the bitOffset into word offset (set localAddr pointer) and local bit offset (bitsLeft) */ - localAddr = destAddr + (bitOffset >> 5); - bitsLeft = bitOffset & 0x1f; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].efx, model.efx, + stream_len, &setup_efx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance, + stream_len, &setup_fx_var); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + } - /* (M) we mask the value first to match its size in nBits */ - /* the calculations can be re-used in the unsegmented code, so we have no overhead */ - shiftRight = 32 - nBits; - mask = 0xffffffff >> shiftRight; - value &= mask; + if (i >= cfg->samples-1) + break; - /* to see if we need to split the value over two words we need the right end position */ - localEndPos = bitsLeft + nBits; + model = next_model_p[i]; + } + return stream_len; +} - if (localEndPos <= 32) { - /* UNSEGMENTED - * - *|-----------|XXXXX|----------------| - * bitsLeft n bitsRight - * - * -> to get the mask: - * shiftRight = bitsLeft + bitsRight = 32 - n - * shiftLeft = bitsRight - * - */ - /* shiftRight = 32 - nBits; */ /* see (M) above! */ - shiftLeft = shiftRight - bitsLeft; +/** + * @brief compress L_FX_NCOB data + * + * @param cfg pointer to the compression configuration structure + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ - /* generate the mask, the bits for the values will be true */ - /* mask = (0xffffffff >> shiftRight) << shiftLeft; */ /* see (M) above! */ - mask <<= shiftLeft; +static int compress_l_fx_ncob(const struct cmp_cfg *cfg) +{ + int err; + int stream_len = 0; + size_t i; - /* clear the destination with inverse mask */ - *(localAddr) &= ~mask; + struct l_fx_ncob *data_buf = cfg->input_buf; + struct l_fx_ncob *model_buf = cfg->model_buf; + struct l_fx_ncob *up_model_buf = NULL; + struct l_fx_ncob *next_model_p; + struct l_fx_ncob model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob, + setup_fx_var, setup_cob_var; - /* assign the value */ - *(localAddr) |= (value << (32 - localEndPos)); /* NOTE: 32-localEndPos = shiftLeft can be simplified */ - - } else { - /* SEGMENTED - * - *|-----------------------------|XXX| |XX|------------------------------| - * bitsLeft n1 n2 bitsRight - * - * -> to get the mask part 1: - * shiftright = bitsleft - * n1 = n - (bitsleft + n - 32) = 32 - bitsleft - * - * -> to get the mask part 2: - * n2 = bitsleft + n - 32 - * shiftleft = 32 - n2 = 32 - (bitsleft + n - 32) = 64 - bitsleft - n - * - */ - - unsigned int n2 = bitsLeft + nBits - 32; - - /* part 1: */ - shiftRight = bitsLeft; - mask = 0xffffffff >> shiftRight; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - /* clear the destination with inverse mask */ - *(localAddr) &= ~mask; - - /* assign the value part 1 */ - *(localAddr) |= (value >> n2); + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); - /* part 2: */ - /* adjust address */ - localAddr += 1; - shiftLeft = 64 - bitsLeft - nBits; - mask = 0xffffffff << shiftLeft; - - /* clear the destination with inverse mask */ - *(localAddr) &= ~mask; - - /* assign the value part 2 */ - *(localAddr) |= (value << (32 - n2)); + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; } - return nBits; -} - - -struct encoder_struct { - encoder_ptr encoder; - unsigned int log2_golomb_par; /* pre-calculated for performance increase */ - uint32_t cmp_size; /* Compressed data size; measured in bits */ -}; - - -static int encode_raw(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - size_t cmp_size_in_bytes; - if (!cfg) + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg); + if (err) return -1; - - if (!cfg->icu_output_buf) + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg); + if (err) return -1; - - if (!cfg->input_buf) + err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.l_ncob, cfg); + if (err) return -1; - - cmp_size_in_bytes = cfg->samples * size_of_a_sample(cfg->cmp_mode); - - enc->cmp_size = cmp_size_in_bytes * CHAR_BIT; /* cmp_size is measured in bits */ - - if (cmp_size_in_bytes > cfg->buffer_length * sizeof(uint16_t)) + /* we use compression parameter for both variance data fields */ + err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_cob_variance, cfg); + if (err) return -1; - memcpy(cfg->icu_output_buf, cfg->input_buf, cmp_size_in_bytes); - - return 0; -} - - -static int encode_raw_16(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - int err; - size_t i; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance, + stream_len, &setup_fx_var); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].cob_x_variance, model.cob_x_variance, + stream_len, &setup_cob_var); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].cob_y_variance, model.cob_y_variance, + stream_len, &setup_cob_var); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance, + cfg->model_value, setup_cob_var.lossy_par); + up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance, + cfg->model_value, setup_cob_var.lossy_par); + } - enc->cmp_size = 0; + if (i >= cfg->samples-1) + break; - for (i = 0; i < cfg->samples; i++) { - uint16_t *p = cfg->input_buf; - err = put_n_bits32(p[i], enc->cmp_size, 16, cfg->icu_output_buf, - cfg->buffer_length); - if (err <= 0) - return err; - enc->cmp_size += 16; + model = next_model_p[i]; } - - return 0; + return stream_len; } -static int encode_raw_S_FX(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - int err; - - err = encode_raw(cfg, enc); - if (err) - return err; - -#if defined(__LITTLE_ENDIAN) - { - size_t i; - for (i = 0; i < cfg->samples; i++) { - struct S_FX *output_buf = (void *)cfg->icu_output_buf; - output_buf[i].FX = cpu_to_be32(output_buf[i].FX); - } - } -#endif - return 0; -} - +/** + * @brief compress L_FX_EFX_NCOB_ECOB data + * + * @param cfg pointer to the compression configuration structure + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ -static int encode_normal(uint32_t value_to_encode, struct cmp_cfg *cfg, - struct encoder_struct *enc) +static int compress_l_fx_efx_ncob_ecob(const struct cmp_cfg *cfg) { - unsigned int code_word; - unsigned int cw_len; int err; + int stream_len = 0; + size_t i; - if (!enc->encoder) - return -1; - - cw_len = enc->encoder(value_to_encode, cfg->golomb_par, - enc->log2_golomb_par, &code_word); + struct l_fx_efx_ncob_ecob *data_buf = cfg->input_buf; + struct l_fx_efx_ncob_ecob *model_buf = cfg->model_buf; + struct l_fx_efx_ncob_ecob *up_model_buf = NULL; + struct l_fx_efx_ncob_ecob *next_model_p; + struct l_fx_efx_ncob_ecob model; + struct encoder_setupt setup_exp_flag, setup_fx, setup_ncob, setup_efx, + setup_ecob, setup_fx_var, setup_cob_var; - err = put_n_bits32(code_word, enc->cmp_size, cw_len, - cfg->icu_output_buf, cfg->buffer_length); - if (err <= 0) - return err; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - enc->cmp_size += cw_len; + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); - return 0; -} - - -static int encode_outlier_zero(uint32_t value_to_encode, int max_bits, - struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - int err; + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (max_bits > 32) + err = configure_encoder_setup(&setup_exp_flag, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg); + if (err) return -1; - - /* use zero as escape symbol */ - err = encode_normal(0, cfg, enc); + err = configure_encoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg); if (err) - return err; + return -1; + err = configure_encoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.l_ncob, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.l_efx, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->round, max_used_bits.l_ecob, cfg); + if (err) + return -1; + /* we use compression parameter for both variance data fields */ + err = configure_encoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_cob_variance, cfg); + if (err) + return -1; - /* put the data unencoded in the bitstream */ - err = put_n_bits32(value_to_encode, enc->cmp_size, max_bits, - cfg->icu_output_buf, cfg->buffer_length); - if (err <= 0) - return err; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].exp_flags, model.exp_flags, + stream_len, &setup_exp_flag); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx, model.fx, stream_len, + &setup_fx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_x, model.ncob_x, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ncob_y, model.ncob_y, + stream_len, &setup_ncob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].efx, model.efx, + stream_len, &setup_efx); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ecob_x, model.ecob_x, + stream_len, &setup_ecob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].ecob_y, model.ecob_y, + stream_len, &setup_ecob); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].fx_variance, model.fx_variance, + stream_len, &setup_fx_var); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].cob_x_variance, model.cob_x_variance, + stream_len, &setup_cob_var); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].cob_y_variance, model.cob_y_variance, + stream_len, &setup_cob_var); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flag.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance, + cfg->model_value, setup_cob_var.lossy_par); + up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance, + cfg->model_value, setup_cob_var.lossy_par); + } - enc->cmp_size += max_bits; + if (i >= cfg->samples-1) + break; - return 0; + model = next_model_p[i]; + } + return stream_len; } -static int cal_multi_offset(unsigned int unencoded_data) -{ - if (unencoded_data <= 0x3) - return 0; - if (unencoded_data <= 0xF) - return 1; - if (unencoded_data <= 0x3F) - return 2; - if (unencoded_data <= 0xFF) - return 3; - if (unencoded_data <= 0x3FF) - return 4; - if (unencoded_data <= 0xFFF) - return 5; - if (unencoded_data <= 0x3FFF) - return 6; - if (unencoded_data <= 0xFFFF) - return 7; - if (unencoded_data <= 0x3FFFF) - return 8; - if (unencoded_data <= 0xFFFFF) - return 9; - if (unencoded_data <= 0x3FFFFF) - return 10; - if (unencoded_data <= 0xFFFFFF) - return 11; - if (unencoded_data <= 0x3FFFFFF) - return 12; - if (unencoded_data <= 0xFFFFFFF) - return 13; - if (unencoded_data <= 0x3FFFFFFF) - return 14; - else - return 15; -} - +/** + * @brief compress offset data from the normal cameras + * + * @param cfg pointer to the compression configuration structure + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ -static int encode_outlier_multi(uint32_t value_to_encode, struct cmp_cfg *cfg, - struct encoder_struct *enc) +static int compress_nc_offset(const struct cmp_cfg *cfg) { - uint32_t unencoded_data; - unsigned int unencoded_data_len; - uint32_t escape_sym; - int escape_sym_offset; int err; + int stream_len = 0; + size_t i; - /* - * In this mode we put the difference between the data and the spillover - * threshold value (unencoded_data) after a encoded escape symbol, which - * indicate that the next codeword is unencoded. - * We use different escape symbol depended on the size the needed bit of - * unencoded data: - * 0, 1, 2 bits needed for unencoded data -> escape symbol is spill + 0 - * 3, 4 bits needed for unencoded data -> escape symbol is spill + 1 - * .. - */ - - unencoded_data = value_to_encode - cfg->spill; - escape_sym_offset = cal_multi_offset(unencoded_data); - escape_sym = cfg->spill + escape_sym_offset; - unencoded_data_len = (escape_sym_offset + 1) * 2; - - /* put the escape symbol in the bitstream */ - err = encode_normal(escape_sym, cfg, enc); - if (err) - return err; - - /* put the unencoded data in the bitstream */ - err = put_n_bits32(unencoded_data, enc->cmp_size, unencoded_data_len, - cfg->icu_output_buf, cfg->buffer_length); - if (err <= 0) - return err; - - enc->cmp_size += unencoded_data_len; - - return 0; -} - -static int encode_outlier(uint32_t value_to_encode, int bit_len, struct cmp_cfg - *cfg, struct encoder_struct *enc) -{ - if (multi_escape_mech_is_used(cfg->cmp_mode)) - return encode_outlier_multi(value_to_encode, cfg, enc); - - if (zero_escape_mech_is_used(cfg->cmp_mode)) - return encode_outlier_zero(value_to_encode, bit_len, cfg, enc); - - return -1; -} - + struct nc_offset *data_buf = cfg->input_buf; + struct nc_offset *model_buf = cfg->model_buf; + struct nc_offset *up_model_buf = NULL; + struct nc_offset *next_model_p; + struct nc_offset model; + struct encoder_setupt setup_mean, setup_var; -int encode_value(uint32_t value_to_encode, int bit_len, struct cmp_cfg *cfg, - struct encoder_struct *enc) -{ - /* 0 is an outlier in case of a zero-escape mechanism, because an - * overflow can occur by incrementing by one - */ - if (value_to_encode >= cfg->spill || - (zero_escape_mech_is_used(cfg->cmp_mode) && value_to_encode == 0)) - return encode_outlier(value_to_encode, bit_len, cfg, enc); - else - return encode_normal(value_to_encode, cfg, enc); -} + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); -static int encode_16(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - size_t i; - uint16_t *data_to_encode; + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!cfg) + err = configure_encoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean, + cfg->round, max_used_bits.nc_offset_mean, cfg); + if (err) return -1; - - if (!enc) + err = configure_encoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance, + cfg->round, max_used_bits.nc_offset_variance, cfg); + if (err) return -1; - data_to_encode = cfg->input_buf; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].mean, model.mean, + stream_len, &setup_mean); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].variance, model.variance, + stream_len, &setup_var); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, model.mean, + cfg->model_value, setup_mean.lossy_par); + up_model_buf[i].variance = cmp_up_model(data_buf[i].variance, model.variance, + cfg->model_value, setup_var.lossy_par); + } + + if (i >= cfg->samples-1) + break; - for (i = 0; i < cfg->samples; i++) { - int err = encode_value(data_to_encode[i], 16, cfg, enc); - if (err) - return err; + model = next_model_p[i]; } - return 0; + return stream_len; } -static int encode_32(struct cmp_cfg *cfg, struct encoder_struct *enc) +/** + * @brief compress background data from the normal cameras + * + * @param cfg pointer to the compression configuration structure + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ + +static int compress_nc_background(const struct cmp_cfg *cfg) { - uint32_t *data_to_encode = cfg->input_buf; + int err; + int stream_len = 0; size_t i; - for (i = 0; i < cfg->samples; i++) { - int err = encode_value(data_to_encode[i], 32, cfg, enc); - if (err) - return err; - } - return 0; -} + struct nc_background *data_buf = cfg->input_buf; + struct nc_background *model_buf = cfg->model_buf; + struct nc_background *up_model_buf = NULL; + struct nc_background *next_model_p; + struct nc_background model; + struct encoder_setupt setup_mean, setup_var, setup_pix; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; -static int encode_S_FX(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - struct S_FX *data_to_encode = cfg->input_buf; - size_t i; - struct cmp_cfg cfg_exp_flag = *cfg; - struct encoder_struct enc_exp_flag = *enc; + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); - cfg_exp_flag.golomb_par = GOLOMB_PAR_EXPOSURE_FLAGS; - enc_exp_flag.log2_golomb_par = ilog_2(GOLOMB_PAR_EXPOSURE_FLAGS); + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - for (i = 0; i < cfg->samples; i++) { - int err; + err = configure_encoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean, + cfg->round, max_used_bits.nc_background_mean, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance, + cfg->round, max_used_bits.nc_background_variance, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error, + cfg->round, max_used_bits.nc_background_outlier_pixels, cfg); + if (err) + return -1; - /* err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, &cfg_exp_flag, enc); */ - err = encode_normal(data_to_encode[i].EXPOSURE_FLAGS, &cfg_exp_flag, &enc_exp_flag); - if (err) - return err; - enc->cmp_size = enc_exp_flag.cmp_size; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].mean, model.mean, + stream_len, &setup_mean); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].variance, model.variance, + stream_len, &setup_var); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].outlier_pixels, model.outlier_pixels, + stream_len, &setup_pix); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, model.mean, + cfg->model_value, setup_mean.lossy_par); + up_model_buf[i].variance = cmp_up_model(data_buf[i].variance, model.variance, + cfg->model_value, setup_var.lossy_par); + up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels, model.outlier_pixels, + cfg->model_value, setup_pix.lossy_par); + } - enc->log2_golomb_par = ilog_2(cfg->golomb_par); - err = encode_value(data_to_encode[i].FX, 32, cfg, enc); - if (err) - return err; + if (i >= cfg->samples-1) + break; - enc_exp_flag.cmp_size = enc->cmp_size; + model = next_model_p[i]; } - - return 0; + return stream_len; } -static int encode_S_FX_EFX(struct cmp_cfg *cfg, struct encoder_struct *enc) +/** + * @brief compress smearing data from the normal cameras + * + * @param cfg pointer to the compression configuration structure + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ + +static int compress_smearing(const struct cmp_cfg *cfg) { - struct S_FX_EFX *data_to_encode = cfg->input_buf; + int err; + int stream_len = 0; size_t i; - for (i = 0; i < cfg->samples; i++) { - int err; + struct smearing *data_buf = cfg->input_buf; + struct smearing *model_buf = cfg->model_buf; + struct smearing *up_model_buf = NULL; + struct smearing *next_model_p; + struct smearing model; + struct encoder_setupt setup_mean, setup_var_mean, setup_pix; - err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, cfg, enc); - if (err) - return err; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - err = encode_value(data_to_encode[i].FX, 32, cfg, enc); - if (err) - return err; + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg->icu_output_buf); - err = encode_value(data_to_encode[i].EFX, 32, cfg, enc); - if (err) - return err; + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; } - return 0; -} - - -static int encode_S_FX_NCOB(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - struct S_FX_NCOB *data_to_encode = cfg->input_buf; - size_t i; - - for (i = 0; i < cfg->samples; i++) { - int err; - err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, cfg, enc); - if (err) - return err; + err = configure_encoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean, + cfg->round, max_used_bits.smearing_mean, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_var_mean, cfg->cmp_par_variance, cfg->spill_variance, + cfg->round, max_used_bits.smearing_variance_mean, cfg); + if (err) + return -1; + err = configure_encoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error, + cfg->round, max_used_bits.smearing_outlier_pixels, cfg); + if (err) + return -1; - err = encode_value(data_to_encode[i].FX, 32, cfg, enc); - if (err) - return err; + for (i = 0;; i++) { + stream_len = encode_value(data_buf[i].mean, model.mean, + stream_len, &setup_mean); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].variance_mean, model.variance_mean, + stream_len, &setup_var_mean); + if (stream_len <= 0) + return stream_len; + stream_len = encode_value(data_buf[i].outlier_pixels, model.outlier_pixels, + stream_len, &setup_pix); + if (stream_len <= 0) + return stream_len; + + if (up_model_buf) { + up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, model.mean, + cfg->model_value, setup_mean.lossy_par); + up_model_buf[i].variance_mean = cmp_up_model(data_buf[i].variance_mean, model.variance_mean, + cfg->model_value, setup_var_mean.lossy_par); + up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels, model.outlier_pixels, + cfg->model_value, setup_pix.lossy_par); + } - err = encode_value(data_to_encode[i].NCOB_X, 32, cfg, enc); - if (err) - return err; + if (i >= cfg->samples-1) + break; - err = encode_value(data_to_encode[i].NCOB_Y, 32, cfg, enc); - if (err) - return err; + model = next_model_p[i]; } - return 0; + return stream_len; } -static int encode_S_FX_EFX_NCOB_ECOB(struct cmp_cfg *cfg, struct encoder_struct - *enc) -{ - struct S_FX_EFX_NCOB_ECOB *data_to_encode = cfg->input_buf; - size_t i; - - for (i = 0; i < cfg->samples; i++) { - int err; - - err = encode_value(data_to_encode[i].EXPOSURE_FLAGS, 8, cfg, enc); - if (err) - return err; +/** + * @brief fill the last part of the bitstream with zeros + * + * @param cfg pointer to the compression configuration structure + * @param cmp_size length of the bitstream in bits + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ - err = encode_value(data_to_encode[i].FX, 32, cfg, enc); - if (err) - return err; +static int pad_bitstream(const struct cmp_cfg *cfg, int cmp_size) +{ + unsigned int output_buf_len_bits, n_pad_bits; - err = encode_value(data_to_encode[i].NCOB_X, 32, cfg, enc); - if (err) - return err; + if (cmp_size < 0) + return cmp_size; - err = encode_value(data_to_encode[i].NCOB_Y, 32, cfg, enc); - if (err) - return err; + if (!cfg->icu_output_buf) + return cmp_size; - err = encode_value(data_to_encode[i].EFX, 32, cfg, enc); - if (err) - return err; + /* no padding in RAW mode; ALWAYS BIG-ENDIAN */ + if (cfg->cmp_mode == CMP_MODE_RAW) + return cmp_size; - err = encode_value(data_to_encode[i].ECOB_X, 32, cfg, enc); - if (err) - return err; + /* maximum length of the bitstream/icu_output_buf in bits */ + output_buf_len_bits = cmp_buffer_length_to_bits(cfg->buffer_length, cfg->data_type); - err = encode_value(data_to_encode[i].ECOB_Y, 32, cfg, enc); - if (err) - return err; + n_pad_bits = 32 - ((unsigned int)cmp_size & 0x1FU); + if (n_pad_bits < 32) { + int n_bits = put_n_bits32(0, n_pad_bits, cmp_size, cfg->icu_output_buf, + output_buf_len_bits); + if (n_bits < 0) + return n_bits; } - return 0; -} - -/* pad the bitstream with zeros */ -int pad_bitstream(struct cmp_cfg *cfg, uint32_t cmp_size) -{ - int n_bits = 0; - - if (!cfg) - return -1; - - /* is padding needed */ - if (cmp_size) { - int n_pad_bits = 32U - (cmp_size & 0x1f); - if (n_pad_bits < 32) { - n_bits = put_n_bits32(0, cmp_size, n_pad_bits, - cfg->icu_output_buf, - cfg->buffer_length); - if (n_bits <= 0) - return -2; - } - } - return n_bits; + return cmp_size; } -uint32_t cmp_encode_data(struct cmp_cfg *cfg) -{ - struct encoder_struct enc; - int err, n_bits; - - enc.encoder = select_encoder(cfg->golomb_par); - enc.log2_golomb_par = ilog_2(cfg->golomb_par); - enc.cmp_size = 0; +/** + * @brief change the endianness of the compressed data to big-endian + * + * @param cfg pointer to the compression configuration structure + * @param cmp_size length of the bitstream in bits + * + * @returns 0 on success; non-zero on failure + */ - switch (cfg->cmp_mode) { - case MODE_RAW: - err = encode_raw_16(cfg, &enc); - break; - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - err = encode_16(cfg, &enc); - break; - case MODE_RAW_S_FX: - err = encode_raw_S_FX(cfg, &enc); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - err = encode_S_FX(cfg, &enc); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - err = encode_S_FX_EFX(cfg, &enc); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - err = encode_S_FX_NCOB(cfg, &enc); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - err = encode_S_FX_EFX_NCOB_ECOB(cfg, &enc); - break; - case MODE_MODEL_ZERO_32: - case MODE_MODEL_MULTI_32: - case MODE_DIFF_ZERO_32: - case MODE_DIFF_MULTI_32: - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - err = encode_32(cfg, &enc); - break; - default: - debug_print("Error: Compression mode not supported.\n"); - return -1; - break; - } +static int cmp_data_to_big_endian(const struct cmp_cfg *cfg, int cmp_size) +{ +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + size_t i; + uint32_t *p; + uint32_t s = (uint32_t)cmp_size; - n_bits = pad_bitstream(cfg, enc.cmp_size); - if (n_bits < 0) - return n_bits; + if (cmp_size < 0) + return cmp_size; -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - { - size_t i; - uint32_t *p = (uint32_t *)cfg->icu_output_buf; + if (!cfg->icu_output_buf) + return cmp_size; - if (p) { - for (i = 0; i < cmp_bit_to_4byte(enc.cmp_size)/sizeof(uint32_t); i++) - cpu_to_be32s(&p[i]); + if (cfg->cmp_mode == CMP_MODE_RAW) { + if (s & 0x7) /* size must be a multiple of 8 in RAW mode */ + return -1; + if (cmp_input_big_to_cpu_endianness(cfg->icu_output_buf, + s/CHAR_BIT, cfg->data_type)) + cmp_size = -1; + } else { + if (rdcu_supported_data_type_is_used(cfg->data_type)) { + p = cfg->icu_output_buf; + } else { + p = &cfg->icu_output_buf[MULTI_ENTRY_HDR_SIZE/sizeof(uint32_t)]; + s -= MULTI_ENTRY_HDR_SIZE * CHAR_BIT; } + + for (i = 0; i < cmp_bit_to_4byte(s)/sizeof(uint32_t); i++) + cpu_to_be32s(&p[i]); } +#else + /* do nothing data are already in big-endian */ + (void)cfg; #endif /*__BYTE_ORDER__ */ - - if (err) - return err; - else - return enc.cmp_size; + return cmp_size; } /** - * @brief compress data on the ICU + * @brief compress data on the ICU in software * - * @param cfg compressor configuration contains all parameters required for - * compression - * @param info compressor information contains information of the executed - * compression + * @param cfg pointer to a compression configuration (created with the + * cmp_cfg_icu_create() function, setup with the cmp_cfg_xxx() functions) * - * @note this function violates the input_buf in place - * @note if icu_new_model_buf = model_buf or NULL, the model will be updated in place * @note the validity of the cfg structure is checked before the compression is * started - * @note when using the 1d-differencing mode or the raw mode (cmp_mode = 0,2,4), - * the model parameters (model_value, model_buf, rdcu_model_adr) are ignored - * @note the rdcu_***_adr configuration parameters are ignored for icu - * compression - * @note semi adaptive compression not supported; configuration parameters - * ap1\_golomb\_par, ap2\_golomb\_par, ap1\_spill ap2\_spill will be - * ignored; information parameters ap1_cmp_size, ap2_cmp_size will always - * be 0 - * - * @returns 0 on success, error otherwise + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF (-2) if the compressed data buffer is too small to + * hold the whole compressed data, CMP_ERROR_HIGH_VALUE (-3) if a data or + * model value is bigger than the max_used_bits parameter allows (set with + * the cmp_set_max_used_bits() function) */ -int icu_compress_data(struct cmp_cfg *cfg, struct cmp_info *info) +int icu_compress_data(const struct cmp_cfg *cfg) { - int err; int cmp_size = 0; - err = set_info(cfg, info); - if (err) - return err; + if (!cfg) + return -1; - err = icu_cmp_cfg_valid(cfg, info); - if (err) - return err; + if (cfg->samples == 0) /* nothing to compress we are done*/ + return 0; - err = cmp_pre_process(cfg); - if (err) - return err; + if (raw_mode_is_used(cfg->cmp_mode)) + if (cfg->samples > cfg->buffer_length) + return CMP_ERROR_SMALL_BUF; - err = cmp_map_to_pos(cfg); - if (err) - return err; + if (cmp_cfg_is_invalid(cfg)) + return -1; - cmp_size = cmp_encode_data(cfg); - if (cmp_size == -2 && info) - /* the icu_output_buf is to small to store the whole bitstream */ - info->cmp_err |= 1UL << SMALL_BUFFER_ERR_BIT; /* set small buffer error */ - if (cmp_size < 0) - return cmp_size; - if (info) - info->cmp_size = cmp_size; + if (raw_mode_is_used(cfg->cmp_mode)) { + cmp_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type); + if (cfg->icu_output_buf) + memcpy(cfg->icu_output_buf, cfg->input_buf, cmp_size); + cmp_size *= CHAR_BIT; /* convert to bits */ + } else { + if (cfg->icu_output_buf && cfg->samples/3 > cfg->buffer_length) + debug_print("Warning: The size of the compressed_data buffer is 3 times smaller than the data_to_compress. This is probably unintended.\n"); + + switch (cfg->data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + cmp_size = compress_imagette(cfg); + break; + + case DATA_TYPE_S_FX: + cmp_size = compress_s_fx(cfg); + break; + case DATA_TYPE_S_FX_EFX: + cmp_size = compress_s_fx_efx(cfg); + break; + case DATA_TYPE_S_FX_NCOB: + cmp_size = compress_s_fx_ncob(cfg); + break; + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + cmp_size = compress_s_fx_efx_ncob_ecob(cfg); + break; + + case DATA_TYPE_F_FX: + cmp_size = compress_f_fx(cfg); + break; + case DATA_TYPE_F_FX_EFX: + cmp_size = compress_f_fx_efx(cfg); + break; + case DATA_TYPE_F_FX_NCOB: + cmp_size = compress_f_fx_ncob(cfg); + break; + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + cmp_size = compress_f_fx_efx_ncob_ecob(cfg); + break; + + case DATA_TYPE_L_FX: + cmp_size = compress_l_fx(cfg); + break; + case DATA_TYPE_L_FX_EFX: + cmp_size = compress_l_fx_efx(cfg); + break; + case DATA_TYPE_L_FX_NCOB: + cmp_size = compress_l_fx_ncob(cfg); + break; + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + cmp_size = compress_l_fx_efx_ncob_ecob(cfg); + break; + + case DATA_TYPE_OFFSET: + cmp_size = compress_nc_offset(cfg); + break; + case DATA_TYPE_BACKGROUND: + cmp_size = compress_nc_background(cfg); + break; + case DATA_TYPE_SMEARING: + cmp_size = compress_smearing(cfg); + break; + + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + /* LCOV_EXCL_START */ + case DATA_TYPE_UNKNOWN: + default: + debug_print("Error: Data type not supported.\n"); + cmp_size = -1; + } + /* LCOV_EXCL_STOP */ + } - return 0; + cmp_size = pad_bitstream(cfg, cmp_size); + cmp_size = cmp_data_to_big_endian(cfg, cmp_size); + + return cmp_size; } diff --git a/lib/cmp_io.c b/lib/cmp_io.c index 9f7fd7294ee4884cc7624deea3588b6cad403dbb..0dfcc8d71d2f656934383000d5f71ac109af9ec3 100644 --- a/lib/cmp_io.c +++ b/lib/cmp_io.c @@ -15,6 +15,7 @@ * more details. * * @brief compression tool Input/Output library + * @warning this part of the software is not intended to run on-board on the ICU. */ #include <stdio.h> @@ -24,10 +25,44 @@ #include <ctype.h> #include <sys/stat.h> -#include "../include/cmp_io.h" -#include "../include/cmp_support.h" -#include "../include/rdcu_cmd.h" -#include "../include/byteorder.h" +#include <cmp_tool-config.h> +#include <cmp_io.h> +#include <cmp_support.h> +#include <rdcu_cmd.h> +#include <byteorder.h> +#include <cmp_data_types.h> + + +/* directory to convert from data_type to string */ +static const struct { + enum cmp_data_type data_type; + const char *str; +} data_type_string_table[] = { + {DATA_TYPE_IMAGETTE, "DATA_TYPE_IMAGETTE"}, + {DATA_TYPE_IMAGETTE_ADAPTIVE, "DATA_TYPE_IMAGETTE_ADAPTIVE"}, + {DATA_TYPE_SAT_IMAGETTE, "DATA_TYPE_SAT_IMAGETTE"}, + {DATA_TYPE_SAT_IMAGETTE_ADAPTIVE, "DATA_TYPE_SAT_IMAGETTE_ADAPTIVE"}, + {DATA_TYPE_OFFSET, "DATA_TYPE_OFFSET"}, + {DATA_TYPE_BACKGROUND, "DATA_TYPE_BACKGROUND"}, + {DATA_TYPE_SMEARING, "DATA_TYPE_SMEARING"}, + {DATA_TYPE_S_FX, "DATA_TYPE_S_FX"}, + {DATA_TYPE_S_FX_EFX, "DATA_TYPE_S_FX_EFX"}, + {DATA_TYPE_S_FX_NCOB, "DATA_TYPE_S_FX_NCOB"}, + {DATA_TYPE_S_FX_EFX_NCOB_ECOB, "DATA_TYPE_S_FX_EFX_NCOB_ECOB"}, + {DATA_TYPE_L_FX, "DATA_TYPE_L_FX"}, + {DATA_TYPE_L_FX_EFX, "DATA_TYPE_L_FX_EFX"}, + {DATA_TYPE_L_FX_NCOB, "DATA_TYPE_L_FX_NCOB"}, + {DATA_TYPE_L_FX_EFX_NCOB_ECOB, "DATA_TYPE_L_FX_EFX_NCOB_ECOB"}, + {DATA_TYPE_F_FX, "DATA_TYPE_F_FX"}, + {DATA_TYPE_F_FX_EFX, "DATA_TYPE_F_FX_EFX"}, + {DATA_TYPE_F_FX_NCOB, "DATA_TYPE_F_FX_NCOB"}, + {DATA_TYPE_F_FX_EFX_NCOB_ECOB, "DATA_TYPE_F_FX_EFX_NCOB_ECOB"}, + {DATA_TYPE_F_CAM_IMAGETTE, "DATA_TYPE_F_CAM_IMAGETTE"}, + {DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE, "DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE"}, + {DATA_TYPE_F_CAM_OFFSET, "DATA_TYPE_F_CAM_OFFSET"}, + {DATA_TYPE_F_CAM_BACKGROUND, "DATA_TYPE_F_CAM_BACKGROUND"}, + {DATA_TYPE_UNKNOWN, "DATA_TYPE_UNKNOWN"} +}; /** @@ -112,31 +147,34 @@ static FILE *open_file(const char *dirname, const char *filename) /** - * @brief write a uint16_t buffer to an output file - * - * @param buf the buffer to write a file - * @param buf_len length of the buffer + * @brief write uncompressed input data to an output file * + * @param data the data to write a file + * @param data_size size of the data in bytes * @param output_prefix file name without file extension * @param name_extension file extension (with leading point character) - * * @param verbose print verbose output if not zero * * @returns 0 on success, error otherwise */ -int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char - *output_prefix, const char *name_extension, int verbose) +int write_input_data_to_file(void *data, uint32_t data_size, enum cmp_data_type data_type, + const char *output_prefix, const char *name_extension, int verbose) { - uint32_t i; + uint32_t i = 0; FILE *fp; + uint8_t *tmp_buf; + size_t sample_size = size_of_a_sample(data_type); - if (!buf) + if (!data) abort(); - if (buf_len == 0) + if (data_size == 0) return 0; + if (!sample_size) + return -1; + fp = open_file(output_prefix, name_extension); if (fp == NULL) { fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix, @@ -144,8 +182,12 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char return -1; } - for (i = 0; i < buf_len; i++) { - fprintf(fp, "%02X %02X", buf[i] >> 8, buf[i] & 0xFF); + tmp_buf = malloc(data_size); + memcpy(tmp_buf, data, data_size); + cmp_input_big_to_cpu_endianness(tmp_buf, data_size, data_type); + + for (i = 0 ; i < data_size; i++) { + fprintf(fp, "%02X", tmp_buf[i]); if ((i + 1) % 16 == 0) fprintf(fp, "\n"); else @@ -157,8 +199,8 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char if (verbose) { printf("\n\n"); - for (i = 0; i < buf_len; i++) { - printf("%02X %02X", buf[i] >> 8, buf[i] & 0xFF); + for (i = 0; i < data_size; i++) { + printf("%02X", tmp_buf[i]); if ((i + 1) % 16 == 0) printf("\n"); else @@ -168,6 +210,7 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char printf("\n\n"); } + free(tmp_buf); return 0; } @@ -354,6 +397,67 @@ int atoui32(const char *dep_str, const char *val_str, uint32_t *red_val) } +/** + * @brief parse a compression data_type string to a data_type + * @note string can be either a number or the name of the compression data type + * + * @param data_type_str string containing the compression data type to parse + * + * @returns data type on success, DATA_TYPE_UNKNOWN on error + */ + +enum cmp_data_type string2data_type(const char *data_type_str) +{ + enum cmp_data_type data_type = DATA_TYPE_UNKNOWN; + + if (data_type_str) { + if (isalpha(data_type_str[0])) { /* check if mode is given as text */ + size_t j; + + for (j = 0; j < sizeof(data_type_string_table) / sizeof(data_type_string_table[0]); j++) { + if (!strcmp(data_type_str, data_type_string_table[j].str)) { + data_type = data_type_string_table[j].data_type; + break; + } + } + } else { + uint32_t read_val; + + if (!atoui32("Compression Data Type", data_type_str, &read_val)) { + data_type = read_val; + if (!cmp_data_type_valid(data_type)) + data_type = DATA_TYPE_UNKNOWN; + } + } + } + return data_type; +} + +/** + * @brief parse a compression data_type string to a data_type + * @note string can be either a number or the name of the compression data type + * + * @param data_type compression data type to convert in string + * + * @returns data type on success, DATA_TYPE_UNKNOWN on error + */ + +const char *data_type2string(enum cmp_data_type data_type) +{ + size_t j; + const char *string = "DATA_TYPE_UNKNOWN"; + + for (j = 0; j < sizeof(data_type_string_table) / sizeof(data_type_string_table[0]); j++) { + if (data_type == data_type_string_table[j].data_type) { + string = data_type_string_table[j].str; + break; + } + } + + return string; +} + + /** * @brief parse a compression mode vale string to an integer * @note string can be either a number or the name of the compression mode @@ -368,14 +472,19 @@ int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode) { size_t j; static const struct { - uint32_t cmp_mode; + uint32_t cmp_mode; const char *str; } conversion[] = { - {MODE_RAW, "MODE_RAW"}, - {MODE_MODEL_ZERO, "MODE_MODEL_ZERO"}, - {MODE_DIFF_ZERO, "MODE_DIFF_ZERO"}, - {MODE_MODEL_MULTI, "MODE_MODEL_MULTI"}, - {MODE_DIFF_MULTI, "MODE_DIFF_MULTI"}, + {CMP_MODE_RAW, "MODE_RAW"}, + {CMP_MODE_MODEL_ZERO, "MODE_MODEL_ZERO"}, + {CMP_MODE_DIFF_ZERO, "MODE_DIFF_ZERO"}, + {CMP_MODE_MODEL_MULTI, "MODE_MODEL_MULTI"}, + {CMP_MODE_DIFF_MULTI, "MODE_DIFF_MULTI"}, + {CMP_MODE_RAW, "CMP_MODE_RAW"}, + {CMP_MODE_MODEL_ZERO, "CMP_MODE_MODEL_ZERO"}, + {CMP_MODE_DIFF_ZERO, "CMP_MODE_DIFF_ZERO"}, + {CMP_MODE_MODEL_MULTI, "CMP_MODE_MODEL_MULTI"}, + {CMP_MODE_DIFF_MULTI, "CMP_MODE_DIFF_MULTI"}, }; if (!cmp_mode_str) @@ -384,7 +493,7 @@ int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode) return -1; if (isalpha(cmp_mode_str[0])) { /* check if mode is given as text */ - for (j = 0; j < sizeof(conversion) / sizeof(conversion[0]); ++j) { + for (j = 0; j < sizeof(conversion) / sizeof(conversion[0]); ++j) { if (!strcmp(cmp_mode_str, conversion[j].str)) { *cmp_mode = conversion[j].cmp_mode; return 0; @@ -396,7 +505,7 @@ int cmp_mode_parse(const char *cmp_mode_str, uint32_t *cmp_mode) return -1; } - if (!cmp_mode_available(*cmp_mode)) + if (!cmp_mode_is_supported(*cmp_mode)) return -1; return 0; @@ -418,7 +527,7 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg) { char *token1, *token2; char line[MAX_CONFIG_LINE]; - enum {CMP_MODE, GOLOMB_PAR, SPILL, SAMPLES, BUFFER_LENGTH, LAST_ITEM}; + enum {CMP_MODE, SAMPLES, BUFFER_LENGTH, LAST_ITEM}; int j, must_read_items[LAST_ITEM] = {0}; if (!fp) @@ -448,48 +557,26 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg) continue; + if (!strcmp(token1, "data_type")) { + cfg->data_type = string2data_type(token2); + if (cfg->data_type == DATA_TYPE_UNKNOWN) + return -1; + continue; + } if (!strcmp(token1, "cmp_mode")) { must_read_items[CMP_MODE] = 1; - if (isalpha(*token2)) { /* check if mode is given as text or val*/ - if (!strcmp(token2, "MODE_RAW")) { - cfg->cmp_mode = 0; - continue; - } - if (!strcmp(token2, "MODE_MODEL_ZERO")) { - cfg->cmp_mode = 1; - continue; - } - if (!strcmp(token2, "MODE_DIFF_ZERO")) { - cfg->cmp_mode = 2; - continue; - } - if (!strcmp(token2, "MODE_MODEL_MULTI")) { - cfg->cmp_mode = 3; - continue; - } - if (!strcmp(token2, "MODE_DIFF_MULTI")) { - cfg->cmp_mode = 4; - continue; - } - fprintf(stderr, "%s: Error read in cmp_mode.\n", - PROGRAM_NAME); + if (cmp_mode_parse(token2, &cfg->cmp_mode)) return -1; - } else { - if (atoui32(token1, token2, &cfg->cmp_mode)) - return -1; - continue; - } + continue; } if (!strcmp(token1, "golomb_par")) { if (atoui32(token1, token2, &cfg->golomb_par)) return -1; - must_read_items[GOLOMB_PAR] = 1; continue; } if (!strcmp(token1, "spill")) { if (atoui32(token1, token2, &cfg->spill)) return -1; - must_read_items[SPILL] = 1; continue; } if (!strcmp(token1, "model_value")) { @@ -522,6 +609,96 @@ static int parse_cfg(FILE *fp, struct cmp_cfg *cfg) return -1; continue; } + if (!strcmp(token1, "cmp_par_exp_flags")) { + if (atoui32(token1, token2, &cfg->cmp_par_exp_flags)) + return -1; + continue; + } + if (!strcmp(token1, "spill_exp_flags")) { + if (atoui32(token1, token2, &cfg->spill_exp_flags)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_fx")) { + if (atoui32(token1, token2, &cfg->cmp_par_fx)) + return -1; + continue; + } + if (!strcmp(token1, "spill_fx")) { + if (atoui32(token1, token2, &cfg->spill_fx)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_ncob")) { + if (atoui32(token1, token2, &cfg->cmp_par_ncob)) + return -1; + continue; + } + if (!strcmp(token1, "spill_ncob")) { + if (atoui32(token1, token2, &cfg->spill_ncob)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_efx")) { + if (atoui32(token1, token2, &cfg->cmp_par_efx)) + return -1; + continue; + } + if (!strcmp(token1, "spill_efx")) { + if (atoui32(token1, token2, &cfg->spill_efx)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_ecob")) { + if (atoui32(token1, token2, &cfg->cmp_par_ecob)) + return -1; + continue; + } + if (!strcmp(token1, "spill_ecob")) { + if (atoui32(token1, token2, &cfg->spill_ecob)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_fx_cob_variance")) { + if (atoui32(token1, token2, &cfg->cmp_par_fx_cob_variance)) + return -1; + continue; + } + if (!strcmp(token1, "spill_fx_cob_variance")) { + if (atoui32(token1, token2, &cfg->spill_fx_cob_variance)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_mean")) { + if (atoui32(token1, token2, &cfg->cmp_par_mean)) + return -1; + continue; + } + if (!strcmp(token1, "spill_mean")) { + if (atoui32(token1, token2, &cfg->spill_mean)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_variance")) { + if (atoui32(token1, token2, &cfg->cmp_par_variance)) + return -1; + continue; + } + if (!strcmp(token1, "spill_variance")) { + if (atoui32(token1, token2, &cfg->spill_variance)) + return -1; + continue; + } + if (!strcmp(token1, "cmp_par_pixels_error")) { + if (atoui32(token1, token2, &cfg->cmp_par_pixels_error)) + return -1; + continue; + } + if (!strcmp(token1, "spill_pixels_error")) { + if (atoui32(token1, token2, &cfg->spill_pixels_error)) + return -1; + continue; + } if (!strcmp(token1, "rdcu_data_adr")) { int i = sram_addr_to_int(token2); @@ -643,18 +820,12 @@ int read_cmp_cfg(const char *file_name, struct cmp_cfg *cfg, int verbose_en) printf("\n"); } - if (cfg->buffer_length < cfg->samples/2) { - fprintf(stderr, - "%s: warning: buffer_length: %u is relative small to the chosen samples parameter of %u.\n", - PROGRAM_NAME, cfg->buffer_length, cfg->samples); - } - return 0; } /** - * @brief parse a file containing a decompression information + * @brief parse a file containing a decompression information * @note internal use only! * * @param fp FILE pointer @@ -703,6 +874,7 @@ static int parse_info(FILE *fp, struct cmp_info *info) if (!strcmp(token1, "cmp_mode_used")) { must_read_items[CMP_MODE_USED] = 1; if (isalpha(*token2)) { /* check if mode is given as text or val*/ + /* TODO: use conversion function for this: */ if (!strcmp(token2, "MODE_RAW")) { info->cmp_mode_used = 0; continue; @@ -1011,7 +1183,7 @@ static uint8_t str_to_uint8(const char *str, char **str_end) /** - * @brief reads n_word words of a hex-encoded string to a uint8_t buffer + * @brief reads buf_size words of a hex-encoded string to a uint8_t buffer * * @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage * return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a @@ -1024,14 +1196,14 @@ static uint8_t str_to_uint8(const char *str, char **str_end) * * @param str pointer to the null-terminated byte string to be interpreted * @param data buffer to write the interpreted content (can be NULL) - * @param n_word number of uint8_t data words to read in + * @param buf_size number of uint8_t data words to read in * @param file_name file name for better error output (can be NULL) * @param verbose_en print verbose output if not zero * * @returns the size in bytes to store the string content; negative on error */ -static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word, +static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t buf_size, const char *file_name, int verbose_en) { const char *nptr = str; @@ -1041,12 +1213,12 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word, errno = 0; if (!data) - n_word = ~0; + buf_size = ~0; if (!file_name) file_name = "unknown file name"; - for (i = 0; i < n_word; ) { + for (i = 0; i < buf_size; ) { uint8_t read_val; unsigned char c = *nptr; @@ -1116,8 +1288,7 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word, /** - * @brief reads n_word words of a hex-encoded uint8_t data form a file to a - * buffer + * @brief reads hex-encoded uint8_t data form a file to a buffer * * @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage * return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a @@ -1130,13 +1301,13 @@ static ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t n_word, * * @param file_name data/model file name * @param buf buffer to write the file content (can be NULL) - * @param n_word number of uint8_t data words to read in + * @param buf_size number of uint8_t data words to read in * @param verbose_en print verbose output if not zero * * @returns the size in bytes to store the file content; negative on error */ -ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int verbose_en) +ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, int verbose_en) { FILE *fp; char *file_cpy = NULL; @@ -1163,6 +1334,10 @@ ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int ver fclose(fp); return 0; } + if ((unsigned long)file_size < buf_size) { + fprintf(stderr, "%s: %s: Error: The files do not contain enough data as requested.\n", PROGRAM_NAME, file_name); + goto fail; + } /* reset the file position indicator to the beginning of the file */ if (fseek(fp, 0L, SEEK_SET) != 0) goto fail; @@ -1186,7 +1361,7 @@ ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int ver fclose(fp); fp = NULL; - size = str2uint8_arr(file_cpy, buf, n_word, file_name, verbose_en); + size = str2uint8_arr(file_cpy, buf, buf_size, file_name, verbose_en); free(file_cpy); file_cpy = NULL; @@ -1204,75 +1379,38 @@ fail: /** - * @brief reads the number of uint16_t samples of a hex-encoded data (or model) - * file into a buffer + * @brief reads hex-encoded data from a file into a buffer * * @param file_name data/model file name + * @param data_type compression data type used for the data * @param buf buffer to write the file content (can be NULL) - * @param samples amount of uint16_t data samples to read in + * @param buf_size size in bytes of the buffer * @param verbose_en print verbose output if not zero * * @returns the size in bytes to store the file content; negative on error */ -ssize_t read_file16(const char *file_name, uint16_t *buf, uint32_t samples, - int verbose_en) +ssize_t read_file_data(const char *file_name, enum cmp_data_type data_type, + void *buf, uint32_t buf_size, int verbose_en) { - ssize_t size = read_file8(file_name, (uint8_t *)buf, - samples*sizeof(uint16_t), verbose_en); + ssize_t size; + int samples, err; + + size = read_file8(file_name, (uint8_t *)buf, buf_size, verbose_en); if (size < 0) return size; - if (size & 0x1) { - fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected multiple of 2 hex words.\n", + samples = cmp_input_size_to_samples(size, data_type); + if (samples < 0) { + fprintf(stderr, "%s: %s: Error: The data are not correct formatted for the used compression data type.\n", PROGRAM_NAME, file_name); return -1; } - if (buf) { - size_t i; - for (i = 0; i < samples; i++) - be16_to_cpus(&buf[i]); - } - - - return size; -} - - -/** - * @brief reads the number of uint32_t samples of a hex-encoded data (or model) - * file into a buffer - * - * @param file_name data/model file name - * @param buf buffer to write the file content (can be NULL) - * @param samples amount of uint32_t data samples to read in - * @param verbose_en print verbose output if not zero - * - * @returns the size in bytes to store the file content; negative on error - */ - -ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t samples, - int verbose_en) -{ - ssize_t size = read_file8(file_name, (uint8_t *)buf, - samples*sizeof(uint32_t), verbose_en); - - if (size < 0) - return -1; - - if (size & 0x3) { - fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected multiple of 4 hex words.\n", - PROGRAM_NAME, file_name); + err = cmp_input_big_to_cpu_endianness(buf, size, data_type); + if (err) return -1; - } - - if (buf) { - size_t i; - for (i = 0; i < samples; i++) - be32_to_cpus(&buf[i]); - } return size; } @@ -1290,7 +1428,7 @@ ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t samples, */ ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent, - uint32_t ent_size, int verbose_en) + uint32_t ent_size, int verbose_en) { ssize_t size; @@ -1305,9 +1443,9 @@ ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent, } if (ent) { - enum cmp_ent_data_type data_type = cmp_ent_get_data_type(ent); + enum cmp_data_type data_type = cmp_ent_get_data_type(ent); - if (!cmp_ent_data_type_valid(data_type)) { + if (data_type == DATA_TYPE_UNKNOWN) { fprintf(stderr, "%s: %s: Error: Compression data type is not supported.\n", PROGRAM_NAME, file_name); return -1; @@ -1326,6 +1464,41 @@ ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent, } +/** + * @brief reads hex-encoded uint32_t samples from a file into a buffer + * + * @param file_name data/model file name + * @param buf buffer to write the file content (can be NULL) + * @param buf_size size of the buf buffer in bytes + * @param verbose_en print verbose output if not zero + * + * @returns the size in bytes to store the file content; negative on error + */ + +ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t buf_size, + int verbose_en) +{ + ssize_t size = read_file8(file_name, (uint8_t *)buf, buf_size, verbose_en); + + if (size < 0) + return -1; + + if (size & 0x3) { + fprintf(stderr, "%s: %s: Error: The data are not correct formatted. Expected multiple of 4 hex words.\n", + PROGRAM_NAME, file_name); + return -1; + } + + if (buf) { + size_t i; + for (i = 0; i < buf_size/sizeof(uint32_t); i++) + be32_to_cpus(&buf[i]); + } + + return size; +} + + /* * @brief generate from the cmp_tool version string a version_id for the * compression entity header @@ -1369,7 +1542,7 @@ uint32_t cmp_tool_gen_version_id(const char *version) version_id |= n; - return version_id |= CMP_TOOL_VERSION_ID_BIT; + return version_id | CMP_TOOL_VERSION_ID_BIT; } @@ -1387,6 +1560,10 @@ static void write_cfg_internal(FILE *fp, const struct cmp_cfg *cfg, int rdcu_cfg fprintf(fp, "#-------------------------------------------------------------------------------\n"); fprintf(fp, "# Default Configuration File\n"); fprintf(fp, "#-------------------------------------------------------------------------------\n"); + fprintf(fp, "# Selected compression data type\n"); + fprintf(fp, "\n"); + fprintf(fp, "data_type = %s\n", data_type2string(cfg->data_type)); + fprintf(fp, "\n"); fprintf(fp, "# Selected compression mode\n"); fprintf(fp, "# 0: raw mode\n"); fprintf(fp, "# 1: model mode with zero escape symbol mechanism\n"); diff --git a/lib/cmp_rdcu.c b/lib/cmp_rdcu.c index c24ebed0e8eefb9e8e297ed1919d0b72e851442a..6a7354573e94d64a5e5b982c01ac71f979e5a6ee 100644 --- a/lib/cmp_rdcu.c +++ b/lib/cmp_rdcu.c @@ -15,21 +15,37 @@ * * @brief hardware compressor control library * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001 + * + * To compress data, first create a compression configuration with the + * rdcu_cfg_create() function. + * Then set the different data buffers with the data to compressed, the model + * data and the RDCU SRAM addresses with the rdcu_cfg_buffers() function. + * Then set the imagette compression parameters with the rdcu_cfg_imagette() + * function. + * Finally, you can compress the data with the RDCU using the + * rdcu_compress_data() function. */ #include <stdint.h> #include <stdio.h> +#include <string.h> + +#include <rdcu_cmd.h> +#include <cmp_debug.h> +#include <cmp_support.h> +#include <cmp_data_types.h> +#include <rdcu_ctrl.h> +#include <rdcu_rmap.h> -#include "../include/rdcu_cmd.h" -#include "../include/cmp_support.h" -#include "../include/rdcu_ctrl.h" -#include "../include/rdcu_rmap.h" +#define IMA_SAM2BYT \ + 2 /* imagette sample to byte conversion factor; one imagette samples has 16 bits (2 bytes) */ #define RDCU_INTR_SIG_ENA 1 /* RDCU interrupt signal enabled */ #define RDCU_INTR_SIG_DIS 0 /* RDCU interrupt signal disable */ -#define RDCU_INTR_SIG_DEFAULT RDCU_INTR_SIG_ENA /* default start value for RDCU - interrupt signal */ +#define RDCU_INTR_SIG_DEFAULT RDCU_INTR_SIG_ENA /* default start value for RDCU interrupt signal */ + + /* RDCU interrupt signal status */ static int interrupt_signal_enabled = RDCU_INTR_SIG_DEFAULT; @@ -48,6 +64,7 @@ static void sync(void) not needed for packed generation int cnt = 0; + printf("syncing..."); while (rdcu_rmap_sync_status()) { printf("pending: %d\n", rdcu_rmap_sync_status()); @@ -63,6 +80,87 @@ static void sync(void) } +/** + * @brief check if the compression data product type, compression mode, model + * value and the lossy rounding parameters are valid for an RDCU compression + * + * @param cfg pointer to a compression configuration containing the compression + * data product type, compression mode, model value and the rounding parameters + * + * @returns 0 if the compression data type, compression mode, model value and + * the lossy rounding parameters are valid for an RDCU compression, non-zero + * if parameters are invalid + */ + +static int rdcu_cfg_gen_par_is_invalid(const struct cmp_cfg *cfg) +{ + int cfg_invalid = 0; + + if (!cfg) + return -1; + + if (!cmp_imagette_data_type_is_used(cfg->data_type)) { + debug_print("Error: The selected compression data type is not supported for RDCU compression"); + cfg_invalid++; + } + + if (cfg->cmp_mode > MAX_RDCU_CMP_MODE) { + debug_print("Error: selected cmp_mode: %u is not supported. Largest supported mode is: %u.\n", + cfg->cmp_mode, MAX_RDCU_CMP_MODE); + cfg_invalid++; + } + + if (cfg->model_value > MAX_MODEL_VALUE) { + debug_print("Error: selected model_value: %u is invalid. Largest supported value is: %u.\n", + cfg->model_value, MAX_MODEL_VALUE); + cfg_invalid++; + } + + if (cfg->round > MAX_RDCU_ROUND) { + debug_print("Error: selected round parameter: %u is not supported. Largest supported value is: %u.\n", + cfg->round, MAX_RDCU_ROUND); + cfg_invalid++; + } + +#ifdef SKIP_CMP_PAR_CHECK + return 0; +#endif + + return -cfg_invalid; +} + + +/** + * @brief create an RDCU compression configuration + * + * @param data_type compression data product type + * @param cmp_mode compression mode + * @param model_value model weighting parameter (only needed for model compression mode) + * @param lossy_par lossy rounding parameter (use CMP_LOSSLESS for lossless compression) + * + * @returns a compression configuration containing the chosen parameters; + * on error the data_type record is set to DATA_TYPE_UNKNOWN + */ + +struct cmp_cfg rdcu_cfg_create(enum cmp_data_type data_type, enum cmp_mode cmp_mode, + uint32_t model_value, uint32_t lossy_par) +{ + struct cmp_cfg cfg; + + memset(&cfg, 0, sizeof(cfg)); + + cfg.data_type = data_type; + cfg.cmp_mode = cmp_mode; + cfg.model_value = model_value; + cfg.round = lossy_par; + + if (rdcu_cfg_gen_par_is_invalid(&cfg)) + cfg.data_type = DATA_TYPE_UNKNOWN; + + return cfg; +} + + /** * @brief check if a buffer is in inside the RDCU SRAM * @@ -99,6 +197,7 @@ static int in_sram_range(uint32_t addr, uint32_t size) * @returns 0 if buffers are not overlapping, otherwise buffer are * overlapping */ + static int buffers_overlap(uint32_t start_a, uint32_t end_a, uint32_t start_b, uint32_t end_b) { @@ -110,302 +209,372 @@ static int buffers_overlap(uint32_t start_a, uint32_t end_a, uint32_t start_b, /** - * @brief check if the compressor configuration is valid for a RDCU compression, - * see the user manual for more information (PLATO-UVIE-PL-UM-0001). + * @brief check if RDCU buffer settings are invalid * - * @param cfg configuration contains all parameters required for compression + * @param cfg a pointer to a compression configuration * - * @returns >= 0 on success, error otherwise + * @returns 0 if buffers configuration is valid, otherwise the configuration is + * invalid */ -int rdcu_cmp_cfg_valid(const struct cmp_cfg *cfg) +static int rdcu_cfg_buffers_is_invalid(const struct cmp_cfg *cfg) { int cfg_invalid = 0; - int cfg_warning = 0; - - if (cfg == NULL) - return -1; - if (cfg->cmp_mode > MAX_RDCU_CMP_MODE) { - printf("Error: selected cmp_mode: %u is not supported. " - "Largest supported mode is: %lu.\n", cfg->cmp_mode, - MAX_RDCU_CMP_MODE); - cfg_invalid++; - } - - if (cfg->model_value > MAX_MODEL_VALUE) { - printf("Error: selected model_value: %u is invalid. " - "Largest supported value is: %lu.\n", cfg->model_value, - MAX_MODEL_VALUE); - cfg_invalid++; - } - - if (cfg->golomb_par < MIN_RDCU_GOLOMB_PAR|| - cfg->golomb_par > MAX_RDCU_GOLOMB_PAR) { - printf("Error: The selected Golomb parameter: %u is not supported. " - "The Golomb parameter has to be between [%lu, %lu].\n", - cfg->golomb_par, MIN_RDCU_GOLOMB_PAR, - MAX_RDCU_GOLOMB_PAR); - cfg_invalid++; - } - - if (cfg->ap1_golomb_par < MIN_RDCU_GOLOMB_PAR || - cfg->ap1_golomb_par > MAX_RDCU_GOLOMB_PAR) { - printf("Error: The selected adaptive 1 Golomb parameter: %u is not supported. " - "The Golomb parameter has to be between [%lu, %lu].\n", - cfg->ap1_golomb_par, MIN_RDCU_GOLOMB_PAR, - MAX_RDCU_GOLOMB_PAR); - cfg_invalid++; - } - - if (cfg->ap2_golomb_par < MIN_RDCU_GOLOMB_PAR || - cfg->ap2_golomb_par > MAX_RDCU_GOLOMB_PAR) { - printf("Error: The selected adaptive 2 Golomb parameter: %u is not supported. " - "The Golomb parameter has to be between [%lu, %lu].\n", - cfg->ap2_golomb_par, MIN_RDCU_GOLOMB_PAR, - MAX_RDCU_GOLOMB_PAR); - cfg_invalid++; - } - - if (cfg->spill < MIN_RDCU_SPILL) { - printf("Error: The selected spillover threshold value: %u is too small. " - "Smallest possible spillover value is: %lu.\n", - cfg->spill, MIN_RDCU_SPILL); - cfg_invalid++; - } - - if (cfg->spill > get_max_spill(cfg->golomb_par, cfg->cmp_mode)) { - printf("Error: The selected spillover threshold value: %u is " - "too large for the selected Golomb parameter: %u, the " - "largest possible spillover value is: %u.\n", - cfg->spill, cfg->golomb_par, - get_max_spill(cfg->golomb_par, cfg->cmp_mode)); - cfg_invalid++; - } - - if (cfg->ap1_spill < MIN_RDCU_SPILL) { - printf("Error: The selected adaptive 1 spillover threshold " - "value: %u is too small. " - "Smallest possible spillover value is: %lu.\n", - cfg->ap1_spill, MIN_RDCU_SPILL); - cfg_invalid++; - } - - if (cfg->ap1_spill > get_max_spill(cfg->ap1_golomb_par, cfg->cmp_mode)) { - printf("Error: The selected adaptive 1 spillover threshold " - "value: %u is too large for the selected adaptive 1 " - "Golomb parameter: %u, the largest possible adaptive 1 " - "spillover value is: %u.\n", - cfg->ap1_spill, cfg->ap1_golomb_par, - get_max_spill(cfg->ap1_golomb_par, cfg->cmp_mode)); - cfg_invalid++; - } - - if (cfg->ap2_spill < MIN_RDCU_SPILL) { - printf("Error: The selected adaptive 2 spillover threshold " - "value: %u is too small." - "Smallest possible spillover value is: %lu.\n", - cfg->ap2_spill, MIN_RDCU_SPILL); - cfg_invalid++; - } - - if (cfg->ap2_spill > get_max_spill(cfg->ap2_golomb_par, cfg->cmp_mode)) { - printf("Error: The selected adaptive 2 spillover threshold " - "value: %u is too large for the selected adaptive 2 " - "Golomb parameter: %u, the largest possible adaptive 2 " - "spillover value is: %u.\n", - cfg->ap2_spill, cfg->ap2_golomb_par, - get_max_spill(cfg->ap2_golomb_par, cfg->cmp_mode)); - cfg_invalid++; - } - - if (cfg->round > MAX_RDCU_ROUND) { - printf("Error: selected round parameter: %u is not supported. " - "Largest supported value is: %lu.\n", - cfg->round, MAX_RDCU_ROUND); - cfg_invalid++; - } - - if (cfg->samples == 0) { - printf("Warning: The samples parameter is set to 0. No data will be compressed.\n"); - cfg_warning++; - } - - if (cfg->buffer_length == 0) { - printf("Error: The buffer_length is set to 0. There is no place " - "to store the compressed data.\n"); - cfg_invalid++; - } - - if (cfg->cmp_mode == MODE_RAW) { + if (cfg->cmp_mode == CMP_MODE_RAW) { if (cfg->buffer_length < cfg->samples) { - printf("buffer_length is smaller than samples parameter. " - "There is not enough space to copy the data in " - "RAW mode.\n"); + debug_print("rdcu_buffer_length is smaller than samples parameter. There is not enough space to copy the data in RAW mode.\n"); cfg_invalid++; } } - if (!cfg->input_buf) { - printf("Warning: The data to compress buffer is set to NULL. " - "No data will be transferred to the rdcu_data_adr in " - "the RDCU-SRAM.\n"); - cfg_warning++; - } - if (cfg->rdcu_data_adr & 0x3) { - printf("Error: The RDCU data to compress start address is not 4-Byte aligned.\n"); + debug_print("Error: The RDCU data to compress start address is not 4-Byte aligned.\n"); cfg_invalid++; } if (cfg->rdcu_buffer_adr & 0x3) { - printf("Error: The RDCU compressed data start address is not 4-Byte aligned.\n"); + debug_print("Error: The RDCU compressed data start address is not 4-Byte aligned.\n"); cfg_invalid++; } - if (!in_sram_range(cfg->rdcu_data_adr, cfg->samples * SAM2BYT)) { - printf("Error: The RDCU data to compress buffer is outside the RDCU SRAM address space.\n"); + if (!in_sram_range(cfg->rdcu_data_adr, cfg->samples * IMA_SAM2BYT)) { + debug_print("Error: The RDCU data to compress buffer is outside the RDCU SRAM address space.\n"); cfg_invalid++; } - if (!in_sram_range(cfg->rdcu_buffer_adr, cfg->buffer_length * SAM2BYT)) { - printf("Error: The RDCU compressed data buffer is outside the RDCU SRAM address space.\n"); + if (!in_sram_range(cfg->rdcu_buffer_adr, cfg->buffer_length * IMA_SAM2BYT)) { + debug_print("Error: The RDCU compressed data buffer is outside the RDCU SRAM address space.\n"); cfg_invalid++; } if (buffers_overlap(cfg->rdcu_data_adr, - cfg->rdcu_data_adr + cfg->samples * SAM2BYT, + cfg->rdcu_data_adr + cfg->samples * IMA_SAM2BYT, cfg->rdcu_buffer_adr, - cfg->rdcu_buffer_adr + cfg->buffer_length * SAM2BYT)) { - printf("Error: The RDCU data to compress buffer and the RDCU " - "compressed data buffer are overlapping.\n"); + cfg->rdcu_buffer_adr + cfg->buffer_length * IMA_SAM2BYT)) { + debug_print("Error: The RDCU data to compress buffer and the RDCU compressed data buffer are overlapping.\n"); cfg_invalid++; } if (model_mode_is_used(cfg->cmp_mode)) { - if (cfg->model_buf == cfg->input_buf) { - printf("Error: The model buffer (model_buf) and the data " - "to be compressed (input_buf) are equal."); + if (cfg->model_buf && cfg->model_buf == cfg->input_buf) { + debug_print("Error: The model buffer (model_buf) and the data to be compressed (input_buf) are equal."); cfg_invalid++; } - if (!cfg->model_buf) { - printf("Warning: The model buffer is set to NULL. No " - "model data will be transferred to the " - "rdcu_model_adr in the RDCU-SRAM.\n"); - cfg_warning++; - } - if (cfg->rdcu_model_adr & 0x3) { - printf("Error: The RDCU model start address is not 4-Byte aligned.\n"); + debug_print("Error: The RDCU model start address is not 4-Byte aligned.\n"); cfg_invalid++; } - if (!in_sram_range(cfg->rdcu_model_adr, cfg->samples * SAM2BYT)) { - printf("Error: The RDCU model buffer is outside the RDCU SRAM address space.\n"); + if (!in_sram_range(cfg->rdcu_model_adr, cfg->samples * IMA_SAM2BYT)) { + debug_print("Error: The RDCU model buffer is outside the RDCU SRAM address space.\n"); cfg_invalid++; } if (buffers_overlap( cfg->rdcu_model_adr, - cfg->rdcu_model_adr + cfg->samples * SAM2BYT, + cfg->rdcu_model_adr + cfg->samples * IMA_SAM2BYT, cfg->rdcu_data_adr, - cfg->rdcu_data_adr + cfg->samples * SAM2BYT)) { - printf("Error: The model buffer and the data to compress buffer are overlapping.\n"); + cfg->rdcu_data_adr + cfg->samples * IMA_SAM2BYT)) { + debug_print("Error: The model buffer and the data to compress buffer are overlapping.\n"); cfg_invalid++; } if (buffers_overlap( cfg->rdcu_model_adr, - cfg->rdcu_model_adr + cfg->samples * SAM2BYT, + cfg->rdcu_model_adr + cfg->samples * IMA_SAM2BYT, cfg->rdcu_buffer_adr, - cfg->rdcu_buffer_adr + cfg->buffer_length * SAM2BYT) - ){ - printf("Error: The model buffer and the compressed data buffer are overlapping.\n"); + cfg->rdcu_buffer_adr + cfg->buffer_length * IMA_SAM2BYT) + ) { + debug_print("Error: The model buffer and the compressed data buffer are overlapping.\n"); cfg_invalid++; } if (cfg->rdcu_model_adr != cfg->rdcu_new_model_adr) { if (cfg->rdcu_new_model_adr & 0x3) { - printf("Error: The RDCU updated model start address " - "(rdcu_new_model_adr) is not 4-Byte aligned.\n"); + debug_print("Error: The RDCU updated model start address (rdcu_new_model_adr) is not 4-Byte aligned.\n"); cfg_invalid++; } if (!in_sram_range(cfg->rdcu_new_model_adr, - cfg->samples * SAM2BYT)) { - printf("Error: The RDCU updated model buffer is " - "outside the RDCU SRAM address space.\n"); + cfg->samples * IMA_SAM2BYT)) { + debug_print("Error: The RDCU updated model buffer is outside the RDCU SRAM address space.\n"); cfg_invalid++; } if (buffers_overlap( cfg->rdcu_new_model_adr, - cfg->rdcu_new_model_adr + cfg->samples * SAM2BYT, + cfg->rdcu_new_model_adr + cfg->samples * IMA_SAM2BYT, cfg->rdcu_data_adr, - cfg->rdcu_data_adr + cfg->samples * SAM2BYT) - ){ - printf("Error: The updated model buffer and the data to " - "compress buffer are overlapping.\n"); + cfg->rdcu_data_adr + cfg->samples * IMA_SAM2BYT) + ) { + debug_print("Error: The updated model buffer and the data to compress buffer are overlapping.\n"); cfg_invalid++; } if (buffers_overlap( cfg->rdcu_new_model_adr, - cfg->rdcu_new_model_adr + cfg->samples * SAM2BYT, + cfg->rdcu_new_model_adr + cfg->samples * IMA_SAM2BYT, cfg->rdcu_buffer_adr, - cfg->rdcu_buffer_adr + cfg->buffer_length * SAM2BYT) - ){ - printf("Error: The updated model buffer and the compressed " - "data buffer are overlapping.\n"); + cfg->rdcu_buffer_adr + cfg->buffer_length * IMA_SAM2BYT) + ) { + debug_print("Error: The updated model buffer and the compressed data buffer are overlapping.\n"); cfg_invalid++; } if (buffers_overlap( cfg->rdcu_new_model_adr, - cfg->rdcu_new_model_adr + cfg->samples * SAM2BYT, + cfg->rdcu_new_model_adr + cfg->samples * IMA_SAM2BYT, cfg->rdcu_model_adr, - cfg->rdcu_model_adr + cfg->samples * SAM2BYT) - ){ - printf("Error: The updated model buffer and the " - "model buffer are overlapping.\n"); + cfg->rdcu_model_adr + cfg->samples * IMA_SAM2BYT) + ) { + debug_print("Error: The updated model buffer and the model buffer are overlapping.\n"); cfg_invalid++; } } } - if (cfg->icu_new_model_buf) { - printf("Warning: ICU updated model buffer is set. This " - "buffer is not used for an RDCU compression.\n"); - cfg_warning++; + if (cfg->icu_new_model_buf) + debug_print("Warning: ICU updated model buffer is set. This buffer is not used for an RDCU compression.\n"); + + if (cfg->icu_output_buf) + debug_print("Warning: ICU compressed data buffer is set. This buffer is not used for an RDCU compression.\n"); + +#ifdef SKIP_CMP_PAR_CHECK + return 0; +#endif + return -cfg_invalid; +} + + +/** + * @brief setup of the different data buffers for an RDCU compression + * + * @param cfg pointer to a compression configuration (created + * with the rdcu_cfg_create() function) + * @param data_to_compress pointer to the data to be compressed (if NULL no + * data transfer to the RDCU) + * @param data_samples length of the data to be compressed measured in + * 16-bit data samples (ignoring the collection header) + * @param model_of_data pointer to model data buffer (only needed for + * model compression mode, if NULL no model data + * transfer to the RDCU) + * @param rdcu_data_adr RDCU SRAM data to compress start address + * @param rdcu_model_adr RDCU SRAM model start address (only need for + * model compression mode) + * @param rdcu_new_model_adr RDCU SRAM new/updated model start address(can be the + * by the same as rdcu_model_adr for in-place model update) + * @param rdcu_buffer_adr RDCU SRAM compressed data start address + * @param rdcu_buffer_lenght length of the RDCU compressed data SRAM buffer + * measured in 16-bit units (same as data_samples) + * + * @returns 0 if parameters are valid, non-zero if parameters are invalid + */ + +int rdcu_cfg_buffers(struct cmp_cfg *cfg, uint16_t *data_to_compress, + uint32_t data_samples, uint16_t *model_of_data, + uint32_t rdcu_data_adr, uint32_t rdcu_model_adr, + uint32_t rdcu_new_model_adr, uint32_t rdcu_buffer_adr, + uint32_t rdcu_buffer_lenght) +{ + if (!cfg) { + debug_print("Error: pointer to the compression configuration structure is NULL.\n"); + return -1; } - if (cfg->icu_output_buf) { - printf("Warning: ICU compressed data buffer is set. This " - "buffer is not used for an RDCU compression.\n"); - cfg_warning++; + cfg->input_buf = data_to_compress; + cfg->samples = data_samples; + cfg->model_buf = model_of_data; + cfg->rdcu_data_adr = rdcu_data_adr; + cfg->rdcu_model_adr = rdcu_model_adr; + cfg->rdcu_new_model_adr = rdcu_new_model_adr; + cfg->rdcu_buffer_adr = rdcu_buffer_adr; + cfg->buffer_length = rdcu_buffer_lenght; + + if (rdcu_cfg_buffers_is_invalid(cfg)) + return -1; + + return 0; +} + + +/** + * @brief check if the Golomb and spillover threshold parameter combination is + * invalid for an RDCU compression + * @note also checked the adaptive Golomb and spillover threshold parameter combinations + * + * @param cfg a pointer to a compression configuration + * + * @returns 0 if (adaptive) Golomb spill threshold parameter combinations are + * valid, otherwise the configuration is invalid + */ + +static int rdcu_cfg_imagette_is_invalid(const struct cmp_cfg *cfg) +{ + int cfg_invalid = 0; + + if (cfg->golomb_par < MIN_IMA_GOLOMB_PAR || + cfg->golomb_par > MAX_IMA_GOLOMB_PAR) { + debug_print("Error: The selected Golomb parameter: %u is not supported. The Golomb parameter has to be between [%u, %u].\n", + cfg->golomb_par, MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg_invalid++; + } + + if (cfg->ap1_golomb_par < MIN_IMA_GOLOMB_PAR || + cfg->ap1_golomb_par > MAX_IMA_GOLOMB_PAR) { + debug_print("Error: The selected adaptive 1 Golomb parameter: %u is not supported. The Golomb parameter has to be between [%u, %u].\n", + cfg->ap1_golomb_par, MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg_invalid++; + } + + if (cfg->ap2_golomb_par < MIN_IMA_GOLOMB_PAR || + cfg->ap2_golomb_par > MAX_IMA_GOLOMB_PAR) { + debug_print("Error: The selected adaptive 2 Golomb parameter: %u is not supported. The Golomb parameter has to be between [%u, %u].\n", + cfg->ap2_golomb_par, MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg_invalid++; + } + + if (cfg->spill < MIN_IMA_SPILL) { + debug_print("Error: The selected spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n", + cfg->spill, MIN_IMA_SPILL); + cfg_invalid++; + } + + if (cfg->spill > cmp_ima_max_spill(cfg->golomb_par)) { + debug_print("Error: The selected spillover threshold value: %u is too large for the selected Golomb parameter: %u, the largest possible spillover value is: %u.\n", + cfg->spill, cfg->golomb_par, cmp_ima_max_spill(cfg->golomb_par)); + cfg_invalid++; + } + + if (cfg->ap1_spill < MIN_IMA_SPILL) { + debug_print("Error: The selected adaptive 1 spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n", + cfg->ap1_spill, MIN_IMA_SPILL); + cfg_invalid++; + } + + if (cfg->ap1_spill > cmp_ima_max_spill(cfg->ap1_golomb_par)) { + debug_print("Error: The selected adaptive 1 spillover threshold value: %u is too large for the selected adaptive 1 Golomb parameter: %u, the largest possible adaptive 1 spillover value is: %u.\n", + cfg->ap1_spill, cfg->ap1_golomb_par, cmp_ima_max_spill(cfg->ap1_golomb_par)); + cfg_invalid++; + } + + if (cfg->ap2_spill < MIN_IMA_SPILL) { + debug_print("Error: The selected adaptive 2 spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n", + cfg->ap2_spill, MIN_IMA_SPILL); + cfg_invalid++; + } + + if (cfg->ap2_spill > cmp_ima_max_spill(cfg->ap2_golomb_par)) { + debug_print("Error: The selected adaptive 2 spillover threshold value: %u is too large for the selected adaptive 2 Golomb parameter: %u, the largest possible adaptive 2 spillover value is: %u.\n", + cfg->ap2_spill, cfg->ap2_golomb_par, cmp_ima_max_spill(cfg->ap2_golomb_par)); + cfg_invalid++; } #ifdef SKIP_CMP_PAR_CHECK return 0; #endif - if (cfg_invalid) - return -cfg_invalid; - else - return cfg_warning; + + return -cfg_invalid; +} + + +/** + * @brief set up the configuration parameters for an RDCU imagette compression + * + * @param cfg pointer to a compression configuration (created + * with the rdcu_cfg_create() function) + * @param golomb_par imagette compression parameter + * @param spillover_par imagette spillover threshold parameter + * @param ap1_golomb_par adaptive 1 imagette compression parameter + * @param ap1_spillover_par adaptive 1 imagette spillover threshold parameter + * @param ap2_golomb_par adaptive 2 imagette compression parameter + * @param ap2_spillover_par adaptive 2 imagette spillover threshold parameter + * + * @returns 0 if parameters are valid, non-zero if parameters are invalid + */ + +int rdcu_cfg_imagette(struct cmp_cfg *cfg, + uint32_t golomb_par, uint32_t spillover_par, + uint32_t ap1_golomb_par, uint32_t ap1_spillover_par, + uint32_t ap2_golomb_par, uint32_t ap2_spillover_par) +{ + if (!cfg) { + debug_print("Error: pointer to the compression configuration structure is NULL.\n"); + return -1; + } + + cfg->golomb_par = golomb_par; + cfg->spill = spillover_par; + cfg->ap1_golomb_par = ap1_golomb_par; + cfg->ap1_spill = ap1_spillover_par; + cfg->ap2_golomb_par = ap2_golomb_par; + cfg->ap2_spill = ap2_spillover_par; + + if (rdcu_cfg_imagette_is_invalid(cfg)) + return -1; + + return 0; +} + + +/** + * @brief check if the compressor configuration is invalid for an RDCU compression, + * see the user manual for more information (PLATO-UVIE-PL-UM-0001). + * + * @param cfg pointer to a compression configuration contains all parameters + * required for compression + * + * @returns 0 if parameters are valid, non-zero if parameters are invalid + */ + +int rdcu_cmp_cfg_is_invalid(const struct cmp_cfg *cfg) +{ + int cfg_invalid = 0; + + if (!cfg) { + debug_print("Error: pointer to the compression configuration structure is NULL.\n"); + return -1; + } + + if (!cfg->input_buf) + debug_print("Warning: The data to compress buffer is set to NULL. No data will be transferred to the rdcu_data_adr in the RDCU-SRAM.\n"); + + if (model_mode_is_used(cfg->cmp_mode)) { + if (!cfg->model_buf) + debug_print("Warning: The model buffer is set to NULL. No model data will be transferred to the rdcu_model_adr in the RDCU-SRAM.\n"); + } + + if (cfg->input_buf && cfg->samples == 0) + debug_print("Warning: The samples parameter is set to 0. No data will be compressed.\n"); + + if (cfg->buffer_length == 0) { + debug_print("Error: The buffer_length is set to 0. There is no place to store the compressed data.\n"); + cfg_invalid++; + } + + if (rdcu_cfg_gen_par_is_invalid(cfg)) + cfg_invalid++; + if (rdcu_cfg_buffers_is_invalid(cfg)) + cfg_invalid++; + if (rdcu_cfg_imagette_is_invalid(cfg)) + cfg_invalid++; + + return -cfg_invalid; } /** * @brief set up RDCU compression register * - * @param cfg configuration contains all parameters required for compression + * @param cfg pointer to a compression configuration contains all parameters + * required for compression * * @returns 0 on success, error otherwise */ int rdcu_set_compression_register(const struct cmp_cfg *cfg) { - if (rdcu_cmp_cfg_valid(cfg) < 0) + if (rdcu_cmp_cfg_is_invalid(cfg)) return -1; /* first, set compression parameters in local mirror registers */ @@ -507,12 +676,11 @@ int rdcu_start_compression(void) * * @param cfg configuration contains all parameters required for compression * - * @note when using the 1d-differencing mode or the raw mode (cmp_mode = 0,2,4), - * the model parameters (model_value, model_buf, rdcu_model_adr) are ignored - * @note the icu_output_buf will not be used for the RDCU compression - * @note the overlapping of the different rdcu buffers is not checked - * @note the validity of the cfg structure is checked before the compression is - * started + * @note Before the rdcu_compress function can be used, an initialisation of + * the RMAP library is required. This is achieved with the functions + * rdcu_ctrl_init() and rdcu_rmap_init(). + * @note The validity of the cfg structure is checked before the compression is + * started. * * @returns 0 on success, error otherwise */ @@ -593,7 +761,7 @@ int rdcu_read_cmp_status(struct cmp_status *status) /** - * @brief read out the metadata of a RDCU compression + * @brief read out the metadata of an RDCU compression * * @param info compression information contains the metadata of a compression * @@ -637,9 +805,9 @@ int rdcu_read_cmp_info(struct cmp_info *info) info->rdcu_new_model_adr_used = rdcu_get_new_model_addr_used(); info->samples_used = rdcu_get_samples_used(); info->rdcu_cmp_adr_used = rdcu_get_compr_data_start_addr(); - info->cmp_size = rdcu_get_compr_data_size(); - info->ap1_cmp_size = rdcu_get_compr_data_adaptive_1_size(); - info->ap2_cmp_size = rdcu_get_compr_data_adaptive_2_size(); + info->cmp_size = rdcu_get_compr_data_size_bit(); + info->ap1_cmp_size = rdcu_get_compr_data_adaptive_1_size_bit(); + info->ap2_cmp_size = rdcu_get_compr_data_adaptive_2_size_bit(); info->cmp_err = rdcu_get_compr_error(); } return 0; @@ -649,15 +817,14 @@ int rdcu_read_cmp_info(struct cmp_info *info) /** * @brief read the compressed bitstream from the RDCU SRAM * - * @param info compression information contains the metadata of a compression - * - * @param output_buf the buffer to store the bitstream (if NULL, the required - * size is returned) + * @param info compression information contains the metadata of a compression + * @param compressed_data the buffer to store the bitstream (if NULL, the + * required size is returned) * * @returns the number of bytes read, < 0 on error */ -int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf) +int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *compressed_data) { uint32_t s; @@ -667,7 +834,7 @@ int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf) /* calculate the need bytes for the bitstream */ s = cmp_bit_to_4byte(info->cmp_size); - if (output_buf == NULL) + if (compressed_data == NULL) return (int)s; if (rdcu_sync_sram_to_mirror(info->rdcu_cmp_adr_used, s, @@ -677,22 +844,22 @@ int rdcu_read_cmp_bitstream(const struct cmp_info *info, void *output_buf) /* wait for it */ sync(); - return rdcu_read_sram(output_buf, info->rdcu_cmp_adr_used, s); + return rdcu_read_sram(compressed_data, info->rdcu_cmp_adr_used, s); } /** - * @brief read the model from the RDCU SRAM + * @brief read the updated model from the RDCU SRAM * - * @param info compression information contains the metadata of a compression + * @param info compression information contains the metadata of a compression * - * @param model_buf the buffer to store the model (if NULL, the required size - * is returned) + * @param updated_model the buffer to store the updated model (if NULL, the required size + * is returned) * * @returns the number of bytes read, < 0 on error */ -int rdcu_read_model(const struct cmp_info *info, void *model_buf) +int rdcu_read_model(const struct cmp_info *info, void *updated_model) { uint32_t s; @@ -700,9 +867,9 @@ int rdcu_read_model(const struct cmp_info *info, void *model_buf) return -1; /* calculate the need bytes for the model */ - s = cmp_cal_size_of_data(info->samples_used, info->cmp_mode_used); + s = info->samples_used * IMA_SAM2BYT; - if (model_buf == NULL) + if (updated_model == NULL) return (int)s; if (rdcu_sync_sram_to_mirror(info->rdcu_new_model_adr_used, (s+3) & ~3U, @@ -712,7 +879,7 @@ int rdcu_read_model(const struct cmp_info *info, void *model_buf) /* wait for it */ sync(); - return rdcu_read_sram(model_buf, info->rdcu_new_model_adr_used, s); + return rdcu_read_sram(updated_model, info->rdcu_new_model_adr_used, s); } @@ -790,19 +957,17 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg, if (last_info->cmp_err) return -1; - /* TODO: check read write buffer overlapping */ - rdcu_set_compression_register(cfg); /* round up needed size must be a multiple of 4 bytes */ - samples_4byte = (cfg->samples * SAM2BYT + 3) & ~3U; + samples_4byte = (cfg->samples * IMA_SAM2BYT + 3) & ~3U; if (cfg->input_buf != NULL) { uint32_t cmp_size_4byte; /* now set the data in the local mirror... */ if (rdcu_write_sram_16(cfg->input_buf, cfg->rdcu_data_adr, - cfg->samples * SAM2BYT) < 0) + cfg->samples * IMA_SAM2BYT) < 0) return -1; /* calculate the need bytes for the bitstream */ @@ -823,7 +988,7 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg, return -1; } } else { - printf("Warning: input_buf = NULL; input_buf is not written to the sram and compressed data is not read from the sram\n"); + debug_print("Warning: input_buf = NULL; input_buf is not written to the sram and compressed data is not read from the SRAM\n"); } /* read model and write model in parallel */ @@ -832,10 +997,10 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg, /* set the model in the local mirror... */ if (rdcu_write_sram_16(cfg->model_buf, cfg->rdcu_model_adr, - cfg->samples * SAM2BYT) < 0) + cfg->samples * IMA_SAM2BYT) < 0) return -1; - new_model_size_4byte = last_info->samples_used * SAM2BYT ; + new_model_size_4byte = last_info->samples_used * IMA_SAM2BYT; if (rdcu_sync_sram_mirror_parallel(last_info->rdcu_new_model_adr_used, (new_model_size_4byte+3) & ~0x3U, cfg->rdcu_model_adr, @@ -853,7 +1018,7 @@ int rdcu_compress_data_parallel(const struct cmp_cfg *cfg, } else if (cfg->model_buf && model_mode_is_used(cfg->cmp_mode)) { /* set the model in the local mirror... */ if (rdcu_write_sram_16(cfg->model_buf, cfg->rdcu_model_adr, - cfg->samples * SAM2BYT) < 0) + cfg->samples * IMA_SAM2BYT) < 0) return -1; if (rdcu_sync_mirror_to_sram(cfg->rdcu_model_adr, samples_4byte, diff --git a/lib/cmp_support.c b/lib/cmp_support.c index a9459718e1a8c79cc913e574e1072b268fff0f72..17deeed1809dd0c03be345763ed50b64953e5c8b 100644 --- a/lib/cmp_support.c +++ b/lib/cmp_support.c @@ -18,75 +18,15 @@ */ -#include "../include/cmp_support.h" -#include "../include/cmp_data_types.h" -#include "../include/cmp_debug.h" - - -/** - * @brief Default configuration of the Compressor in model imagette mode. - * @warning All ICU buffers are set to NULL. Samples and buffer_length are set to 0 - * @note see PLATO-IWF-PL-RS-0005 V1.1 - */ - - -const struct cmp_cfg DEFAULT_CFG_MODEL = { - MODE_MODEL_MULTI, /* cmp_mode */ - 4, /* golomb_par */ - 48, /* spill */ - 8, /* model_value */ - 0, /* round */ - 3, /* ap1_golomb_par */ - 35, /* ap1_spill */ - 5, /* ap2_golomb_par */ - 60, /* ap2_spill */ - NULL, /* *input_buf */ - 0x000000, /* rdcu_data_adr */ - NULL, /* *model_buf */ - 0x200000, /* rdcu_model_adr */ - NULL, /* *icu_new_model_buf */ - 0x400000, /* rdcu_up_model_adr */ - 0, /* samples */ - NULL, /* *icu_output_buf */ - 0x600000, /* rdcu_buffer_adr */ - 0x0 /* buffer_length */ -}; - - -/** - * @brief Default configuration of the Compressor in 1d-differencing imagette mode. - * @warning All ICU buffers are set to NULL. Samples and buffer_length are set to 0 - * @note see PLATO-IWF-PL-RS-0005 V1.1 - */ - -const struct cmp_cfg DEFAULT_CFG_DIFF = { - MODE_DIFF_ZERO, /* cmp_mode */ - 7, /* golomb_par */ - 60, /* spill */ - 8, /* model_value */ - 0, /* round */ - 6, /* ap1_golomb_par */ - 48, /* ap1_spill */ - 8, /* ap2_golomb_par */ - 72, /* ap2_spill */ - NULL, /* *input_buf */ - 0x000000, /* rdcu_data_adr */ - NULL, /* *model_buf */ - 0x000000, /* rdcu_model_adr */ - NULL, /* *icu_new_model_buf */ - 0x000000, /* rdcu_up_model_adr */ - 0, /* samples */ - NULL, /* *icu_output_buf */ - 0x600000, /* rdcu_buffer_adr */ - 0x0 /* buffer_length */ -}; +#include <cmp_support.h> +#include <cmp_debug.h> /** * @brief implementation of the logarithm base of floor(log2(x)) for integers * @note ilog_2(0) = -1 defined * - * @param x input parameter + * @param x input parameter * * @returns the result of floor(log2(x)) */ @@ -101,10 +41,10 @@ int ilog_2(uint32_t x) /** - * @brief Determining if an integer is a power of 2 + * @brief determining if an integer is a power of 2 * @note 0 is incorrectly considered a power of 2 here * - * @param v we want to see if v is a power of 2 + * @param v we want to see if v is a power of 2 * * @returns 1 if v is a power of 2, otherwise 0 * @@ -117,231 +57,274 @@ int is_a_pow_of_2(unsigned int v) } +/** + * @brief check if the compression entity data product type is supported + * + * @param data_type compression entity data product type to check + * + * @returns zero if data_type is invalid; non-zero if data_type is valid + */ + +int cmp_data_type_valid(enum cmp_data_type data_type) +{ + if (data_type == DATA_TYPE_F_CAM_OFFSET) + debug_print("Error: DATA_TYPE_F_CAM_OFFSET is TBD and not implemented yet.\n"); + if (data_type == DATA_TYPE_F_CAM_BACKGROUND) + debug_print("Error: DATA_TYPE_F_CAM_BACKGROUND is TBD and not implemented yet.\n"); + + if (data_type <= DATA_TYPE_UNKNOWN || data_type > DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE) + return 0; + + return 1; +} + + /** * @brief check if a model mode is selected * - * @param cmp_mode compression mode + * @param cmp_mode compression mode * - * @returns 1 when model mode is set, otherwise 0 + * @returns 1 when the model mode is used, otherwise 0 */ -int model_mode_is_used(unsigned int cmp_mode) +int model_mode_is_used(enum cmp_mode cmp_mode) { - switch (cmp_mode) { - case MODE_MODEL_ZERO: - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_ZERO_F_FX_EFX: - case MODE_MODEL_ZERO_F_FX_NCOB: - case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI: - case MODE_MODEL_MULTI_S_FX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_F_FX: - case MODE_MODEL_MULTI_F_FX_EFX: - case MODE_MODEL_MULTI_F_FX_NCOB: - case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB: - case MODE_MODEL_ZERO_32: - case MODE_MODEL_MULTI_32: + if (cmp_mode == CMP_MODE_MODEL_ZERO || + cmp_mode == CMP_MODE_MODEL_MULTI) return 1; - break; - default: - return 0; - break; - } + + return 0; } /** * @brief check if a 1d-differencing mode is selected * - * @param cmp_mode compression mode + * @param cmp_mode compression mode * - * @returns 1 when 1d-differencing mode is set, otherwise 0 + * @returns 1 when the 1d-differencing mode is used, otherwise 0 */ -int diff_mode_is_used(unsigned int cmp_mode) +int diff_mode_is_used(enum cmp_mode cmp_mode) { - switch (cmp_mode) { - case MODE_DIFF_ZERO: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_ZERO_F_FX_EFX: - case MODE_DIFF_ZERO_F_FX_NCOB: - case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI: - case MODE_DIFF_MULTI_S_FX: - case MODE_DIFF_MULTI_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_F_FX: - case MODE_DIFF_MULTI_F_FX_EFX: - case MODE_DIFF_MULTI_F_FX_NCOB: - case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_32: - case MODE_DIFF_MULTI_32: + if (cmp_mode == CMP_MODE_DIFF_ZERO || + cmp_mode == CMP_MODE_DIFF_MULTI) return 1; - break; - default: - return 0; - break; - } + + return 0; } /** * @brief check if the raw mode is selected * - * @param cmp_mode compression mode + * @param cmp_mode compression mode * - * @returns 1 when raw mode is set, otherwise 0 + * @returns 1 when the raw mode is used, otherwise 0 */ -int raw_mode_is_used(unsigned int cmp_mode) +int raw_mode_is_used(enum cmp_mode cmp_mode) +{ + if (cmp_mode == CMP_MODE_RAW) + return 1; + + return 0; +} + + +/** + * @brief check if the compression mode is supported by the RDCU compressor + * + * @param cmp_mode compression mode + * + * @returns 1 when the compression mode is supported by the RDCU, otherwise 0 + */ + +int rdcu_supported_cmp_mode_is_used(enum cmp_mode cmp_mode) { switch (cmp_mode) { - case MODE_RAW: - case MODE_RAW_S_FX: - case MODE_RAW_32: + case CMP_MODE_RAW: + case CMP_MODE_MODEL_ZERO: + case CMP_MODE_DIFF_ZERO: + case CMP_MODE_MODEL_MULTI: + case CMP_MODE_DIFF_MULTI: return 1; - break; + case CMP_MODE_STUFF: default: return 0; - break; } + } /** - * @brief check if the mode is supported by the RDCU compressor + * @brief check if the data product data type is supported by the RDCU compressor * - * @param cmp_mode compression mode + * @param data_type compression data product type * - * @returns 1 when mode is supported by the RDCU, otherwise 0 + * @returns 1 when the data type is supported by the RDCU, otherwise 0 */ -int rdcu_supported_mode_is_used(unsigned int cmp_mode) +int rdcu_supported_data_type_is_used(enum cmp_data_type data_type) { - switch (cmp_mode) { - case MODE_RAW: - case MODE_MODEL_ZERO: - case MODE_DIFF_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_MULTI: + switch (data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: return 1; - break; default: return 0; - break; } } /** - * @brief check if the mode is available + * @brief check if the compression mode is supported for an ICU compression * - * @param cmp_mode compression mode + * @param cmp_mode compression mode * - * @returns 1 when mode is available, otherwise 0 + * @returns 1 when the compression mode is supported, otherwise 0 */ -int cmp_mode_available(unsigned int cmp_mode) +int cmp_mode_is_supported(enum cmp_mode cmp_mode) { - if (diff_mode_is_used(cmp_mode) || - model_mode_is_used(cmp_mode) || - raw_mode_is_used(cmp_mode)) + switch (cmp_mode) { + case CMP_MODE_RAW: + case CMP_MODE_MODEL_ZERO: + case CMP_MODE_DIFF_ZERO: + case CMP_MODE_MODEL_MULTI: + case CMP_MODE_DIFF_MULTI: + case CMP_MODE_STUFF: return 1; - else - return 0; - + } + return 0; } /** * @brief check if zero escape symbol mechanism mode is used * - * @param cmp_mode compression mode + * @param cmp_mode compression mode * * @returns 1 when zero escape symbol mechanism is set, otherwise 0 */ -int zero_escape_mech_is_used(unsigned int cmp_mode) +int zero_escape_mech_is_used(enum cmp_mode cmp_mode) { - switch (cmp_mode) { - case MODE_MODEL_ZERO: - case MODE_DIFF_ZERO: - case MODE_MODEL_ZERO_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_ZERO_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_MODEL_ZERO_F_FX_EFX: - case MODE_DIFF_ZERO_F_FX_EFX: - case MODE_MODEL_ZERO_F_FX_NCOB: - case MODE_DIFF_ZERO_F_FX_NCOB: - case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_MODEL_ZERO_32: - case MODE_DIFF_ZERO_32: + if (cmp_mode == CMP_MODE_MODEL_ZERO || + cmp_mode == CMP_MODE_DIFF_ZERO) + return 1; + + return 0; +} + + +/** + * @brief check if multi escape symbol mechanism mode is used + * + * @param cmp_mode compression mode + * + * @returns 1 when multi escape symbol mechanism is set, otherwise 0 + */ + +int multi_escape_mech_is_used(enum cmp_mode cmp_mode) +{ + if (cmp_mode == CMP_MODE_MODEL_MULTI || + cmp_mode == CMP_MODE_DIFF_MULTI) + return 1; + + return 0; +} + + +/** + * @brief check if an imagette compression data type is used + * @note adaptive imagette compression data types included + * + * @param data_type compression data type + * + * @returns 1 when data_type is an imagette data type, otherwise 0 + */ + +int cmp_imagette_data_type_is_used(enum cmp_data_type data_type) +{ + return rdcu_supported_data_type_is_used(data_type); +} + + +/** + * @brief check if an adaptive imagette compression data type is used + * + * @param data_type compression data type + * + * @returns 1 when data_type is an adaptive imagette data type, otherwise 0 + */ + +int cmp_ap_imagette_data_type_is_used(enum cmp_data_type data_type) +{ + switch (data_type) { + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: return 1; - break; default: return 0; - break; } +} + + +/** + * @brief check if a flux/center of brightness compression data type is used + * + * @param data_type compression data type + * + * @returns 1 when data_type is a flux/center of brightness data type, otherwise 0 + */ +int cmp_fx_cob_data_type_is_used(enum cmp_data_type data_type) +{ + switch (data_type) { + case DATA_TYPE_S_FX: + case DATA_TYPE_S_FX_EFX: + case DATA_TYPE_S_FX_NCOB: + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + case DATA_TYPE_L_FX: + case DATA_TYPE_L_FX_EFX: + case DATA_TYPE_L_FX_NCOB: + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + case DATA_TYPE_F_FX: + case DATA_TYPE_F_FX_EFX: + case DATA_TYPE_F_FX_NCOB: + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + return 1; + default: + return 0; + } } /** - * @brief check if multi escape symbol mechanism mode is used + * @brief check if an auxiliary science compression data type is used * - * @param cmp_mode compression mode + * @param data_type compression data type * - * @returns 1 when multi escape symbol mechanism is set, otherwise 0 + * @returns 1 when data_type is an auxiliary science data type, otherwise 0 */ -int multi_escape_mech_is_used(unsigned int cmp_mode) +int cmp_aux_data_type_is_used(enum cmp_data_type data_type) { - switch (cmp_mode) { - case MODE_MODEL_MULTI: - case MODE_DIFF_MULTI: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_MULTI_S_FX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_MULTI_F_FX: - case MODE_MODEL_MULTI_F_FX_EFX: - case MODE_DIFF_MULTI_F_FX_EFX: - case MODE_MODEL_MULTI_F_FX_NCOB: - case MODE_DIFF_MULTI_F_FX_NCOB: - case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_32: - case MODE_DIFF_MULTI_32: + switch (data_type) { + case DATA_TYPE_OFFSET: + case DATA_TYPE_BACKGROUND: + case DATA_TYPE_SMEARING: + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: return 1; - break; default: return 0; - break; } } @@ -349,8 +332,8 @@ int multi_escape_mech_is_used(unsigned int cmp_mode) /** * @brief method for lossy rounding * - * @param value value to round - * @param round round parameter + * @param value the value to round + * @param round rounding parameter * * @return rounded value */ @@ -364,8 +347,8 @@ unsigned int round_fwd(unsigned int value, unsigned int round) /** * @brief inverse method for lossy rounding * - * @param value value to round back - * @param round round parameter + * @param value the value to round back + * @param round rounding parameter * * @return back rounded value */ @@ -378,9 +361,8 @@ unsigned int round_inv(unsigned int value, unsigned int round) /** * @brief implantation of the model update equation - * * @note check before that model_value is not greater than MAX_MODEL_VALUE - + * * @param data data to process * @param model (current) model of the data to process * @param model_value model weighting parameter @@ -388,203 +370,502 @@ unsigned int round_inv(unsigned int value, unsigned int round) * @returns (new) updated model */ -unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int - model_value) +unsigned int cmp_up_model(unsigned int data, unsigned int model, + unsigned int model_value, unsigned int round) + { + uint64_t weighted_model, weighted_data; + + /* round and round back input because for decompression the accurate + * data values are not available + */ + data = round_inv(round_fwd(data, round), round); /* cast uint64_t to prevent overflow in the multiplication */ - uint64_t weighted_model = (uint64_t)model * model_value; - uint64_t weighted_data = (uint64_t)data * (MAX_MODEL_VALUE - model_value); + weighted_model = (uint64_t)model * model_value; + weighted_data = (uint64_t)data * (MAX_MODEL_VALUE - model_value); /* truncation is intended */ return (unsigned int)((weighted_model + weighted_data) / MAX_MODEL_VALUE); } /** - * @brief get the maximum valid spill threshold value for a given golomb_par + * @brief get the maximum valid spill threshold value for a RDCU HW imagette + * compression in diff or model mode * - * @param golomb_par Golomb parameter - * @param cmp_mode compression mode + * @param golomb_par Golomb parameter * - * @returns the highest still valid spill threshold value + * @returns the highest still valid spill threshold value for a diff of model + * mode compression; 0 if golomb_par is invalid */ -uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode) +uint32_t cmp_ima_max_spill(unsigned int golomb_par) { - const uint32_t LUT_MAX_RDCU[MAX_RDCU_GOLOMB_PAR+1] = { 0, 8, 22, 35, 48, + /* the RDCU can only generate 16 bit long code words -> lower max spill needed */ + const uint32_t LUT_MAX_RDCU[MAX_IMA_GOLOMB_PAR+1] = { 0, 8, 22, 35, 48, 60, 72, 84, 96, 107, 118, 129, 140, 151, 162, 173, 184, 194, 204, 214, 224, 234, 244, 254, 264, 274, 284, 294, 304, 314, 324, 334, 344, 353, 362, 371, 380, 389, 398, 407, 416, 425, 434, 443, 452, 461, 470, 479, 488, 497, 506, 515, 524, 533, 542, 551, 560, 569, 578, 587, 596, 605, 614, 623 }; - if (golomb_par == 0) + + if (golomb_par > MAX_IMA_GOLOMB_PAR) return 0; - if (rdcu_supported_mode_is_used(cmp_mode)) { - if (golomb_par > MAX_RDCU_GOLOMB_PAR) - return 0; + return LUT_MAX_RDCU[golomb_par]; +} - return LUT_MAX_RDCU[golomb_par]; - } else { - if (golomb_par > MAX_ICU_GOLOMB_PAR) { - return 0; - } else { - /* the ICU compressor can generate code words with a length of - * maximal 32 bits. */ - unsigned int max_cw_bits = 32; - unsigned int cutoff = (1UL << (ilog_2(golomb_par)+1)) - golomb_par; - unsigned int max_n_sym_offset = max_cw_bits/2 - 1; - return (max_cw_bits-1-ilog_2(golomb_par))*golomb_par + cutoff - - max_n_sym_offset - 1; + +/** + * @brief get the maximum valid spill threshold value for a ICU SW compression + * in diff or model mode + * + * @param cmp_par compression parameter + * + * @returns the highest still valid spill threshold value for diff or model + * mode compression; 0 if the cmp_par is not valid + */ + +uint32_t cmp_icu_max_spill(unsigned int cmp_par) +{ + /* the ICU compressor can generate code words with a length of maximal 32 bits. */ + unsigned int max_cw_bits = 32; + unsigned int cutoff = (1UL << (ilog_2(cmp_par)+1)) - cmp_par; + unsigned int max_n_sym_offset = max_cw_bits/2 - 1; + + if (!cmp_par || cmp_par > MAX_ICU_GOLOMB_PAR) + return 0; + + return (max_cw_bits-1-ilog_2(cmp_par))*cmp_par + cutoff + - max_n_sym_offset - 1; +} + + +/** + * @brief calculate the need bytes to hold a bitstream + * + * @param cmp_size_bit compressed data size, measured in bits + * + * @returns the size in bytes to store the hole bitstream + * @note we round up the result to multiples of 4 bytes + */ + +unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit) +{ + return (((cmp_size_bit + 7) / 8) + 3) & ~0x3UL; +} + + +/** + * @brief check if the compression data type, compression mode, model value and + * the lossy rounding parameters are invalid for a ICU compression + * + * @param cfg pointer to the compressor configuration + * + * @returns 0 if generic compression parameters are valid, otherwise invalid + */ + +int cmp_cfg_icu_gen_par_is_invalid(const struct cmp_cfg *cfg) +{ + int cfg_invalid = 0; + + if (!cfg) + return 0; + + if (!cmp_data_type_valid(cfg->data_type)) { + debug_print("Error: selected compression data type is not supported.\n"); + cfg_invalid++; + } + + if (cfg->cmp_mode > CMP_MODE_STUFF) { + debug_print("Error: selected cmp_mode: %i is not supported.\n", cfg->cmp_mode); + cfg_invalid++; + } + + if (model_mode_is_used(cfg->cmp_mode)) { + if (cfg->model_value > MAX_MODEL_VALUE) { + debug_print("Error: selected model_value: %u is invalid. Largest supported value is: %u.\n", + cfg->model_value, MAX_MODEL_VALUE); + cfg_invalid++; } } + + if (cfg->round > MAX_ICU_ROUND) { + debug_print("Error: selected lossy parameter: %u is not supported. Largest supported value is: %u.\n", + cfg->round, MAX_ICU_ROUND); + cfg_invalid++; + } + + return cfg_invalid; } /** - * @brief get a good spill threshold parameter for the selected Golomb parameter - * and compression mode + * @brief check if the buffer parameters are invalid * - * @param golomb_par Golomb parameter - * @param cmp_mode compression mode + * @param cfg pointer to the compressor configuration * - * @returns a good spill parameter (optimal for zero escape mechanism) - * @warning icu compression not support yet! + * @returns 0 if the buffer parameters are valid, otherwise invalid */ -uint32_t cmp_get_good_spill(unsigned int golomb_par, unsigned int cmp_mode) +int cmp_cfg_icu_buffers_is_invalid(const struct cmp_cfg *cfg) { - const uint32_t LUT_RDCU_MULIT[MAX_RDCU_GOLOMB_PAR+1] = {0, 8, 16, 23, - 30, 36, 44, 51, 58, 64, 71, 77, 84, 90, 97, 108, 115, 121, 128, - 135, 141, 148, 155, 161, 168, 175, 181, 188, 194, 201, 207, 214, - 229, 236, 242, 250, 256, 263, 269, 276, 283, 290, 296, 303, 310, - 317, 324, 330, 336, 344, 351, 358, 363, 370, 377, 383, 391, 397, - 405, 411, 418, 424, 431, 452 }; - - if (zero_escape_mech_is_used(cmp_mode)) - return get_max_spill(golomb_par, cmp_mode); - - if (cmp_mode == MODE_MODEL_MULTI) { - if (golomb_par > MAX_RDCU_GOLOMB_PAR) - return 0; - else - return LUT_RDCU_MULIT[golomb_par]; + int cfg_invalid = 0; + + if (!cfg) + return 0; + + if (cfg->input_buf == NULL) { + debug_print("Error: The data_to_compress buffer for the data to be compressed is NULL.\n"); + cfg_invalid++; } - if (cmp_mode == MODE_DIFF_MULTI) - return CMP_GOOD_SPILL_DIFF_MULTI; + if (cfg->samples == 0) + debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended.\n"); - return 0; + if (cfg->icu_output_buf) { + if (cfg->buffer_length == 0 && cfg->samples != 0) { + debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data.\n"); + cfg_invalid++; + } + + if (raw_mode_is_used(cfg->cmp_mode) && cfg->buffer_length < cfg->samples) { + debug_print("Error: The compressed_data_len_samples is to small to hold the data form the data_to_compress.\n"); + cfg_invalid++; + } + + if (cfg->icu_output_buf == cfg->input_buf) { + debug_print("Error: The compressed_data buffer is the same as the data_to_compress buffer.\n"); + cfg_invalid++; + } + } + + if (model_mode_is_used(cfg->cmp_mode)) { + if (cfg->model_buf == NULL) { + debug_print("Error: The model_of_data buffer for the model data is NULL.\n"); + cfg_invalid++; + } + + if (cfg->model_buf == cfg->input_buf) { + debug_print("Error: The model_of_data buffer is the same as the data_to_compress buffer.\n"); + cfg_invalid++; + } + + if (cfg->model_buf == cfg->icu_output_buf) { + debug_print("Error: The model_of_data buffer is the same as the compressed_data buffer.\n"); + cfg_invalid++; + } + + if (cfg->icu_new_model_buf) { + if (cfg->icu_new_model_buf == cfg->input_buf) { + debug_print("Error: The updated_model buffer is the same as the data_to_compress buffer.\n"); + cfg_invalid++; + } + + if (cfg->icu_new_model_buf == cfg->icu_output_buf) { + debug_print("Error: The compressed_data buffer is the same as the compressed_data buffer.\n"); + cfg_invalid++; + } + } + } + + return cfg_invalid; } /** - * @brief calculate the size of a sample for the different compression modes + * @brief check if the combination of the different compression parameters is invalid * - * @param cmp_mode compression mode + * @param cmp_par compression parameter + * @param spill spillover threshold parameter + * @param cmp_mode compression mode + * @param data_type compression data type + * @param par_name string describing the use of the compression par. for + * debug messages (can be NULL) * - * @returns the size of a data sample in bytes for the selected compression - * mode; + * @returns 0 if the parameter combination is valid, otherwise the combination is invalid */ -size_t size_of_a_sample(unsigned int cmp_mode) +static int cmp_pars_are_invalid(uint32_t cmp_par, uint32_t spill, enum cmp_mode cmp_mode, + enum cmp_data_type data_type, char *par_name) { - size_t sample_len; + int cfg_invalid = 0; + uint32_t min_golomb_par; + uint32_t max_golomb_par; + uint32_t min_spill; + uint32_t max_spill; + + if (!par_name) + par_name = ""; + + /* The maximum compression parameter for imagette data are smaller to + * fit into the imagette compression entity header */ + if (cmp_imagette_data_type_is_used(data_type)) { + min_golomb_par = MIN_IMA_GOLOMB_PAR; + max_golomb_par = MAX_IMA_GOLOMB_PAR; + min_spill = MIN_IMA_SPILL; + max_spill = cmp_ima_max_spill(cmp_par); + } else { + min_golomb_par = MIN_ICU_GOLOMB_PAR; + max_golomb_par = MAX_ICU_GOLOMB_PAR; + min_spill = MIN_ICU_SPILL; + max_spill = cmp_icu_max_spill(cmp_par); + } + switch (cmp_mode) { - case MODE_RAW: - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - sample_len = sizeof(uint16_t); + case CMP_MODE_RAW: + /* no checks needed */ break; - case MODE_RAW_S_FX: - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - sample_len = sizeof(struct S_FX); + case CMP_MODE_DIFF_ZERO: + case CMP_MODE_DIFF_MULTI: + case CMP_MODE_MODEL_ZERO: + case CMP_MODE_MODEL_MULTI: + if (cmp_par < min_golomb_par || cmp_par > max_golomb_par) { + debug_print("Error: The selected %s compression parameter: %u is not supported. The compression parameter has to be between [%u, %u].\n", + par_name, cmp_par, min_golomb_par, max_golomb_par); + cfg_invalid++; + } + if (spill < min_spill) { + debug_print("Error: The selected %s spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n", + par_name, spill, min_spill); + cfg_invalid++; + } + if (spill > max_spill) { + debug_print("Error: The selected %s spillover threshold value: %u is too large for the selected %s compression parameter: %u, the largest possible spillover value in the selected compression mode is: %u.\n", + par_name, spill, par_name, cmp_par, max_spill); + cfg_invalid++; + } + break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - sample_len = sizeof(struct S_FX_NCOB); + case CMP_MODE_STUFF: + if (cmp_par > MAX_STUFF_CMP_PAR) { + debug_print("Error: The selected %s stuff mode compression parameter: %u is too large, the largest possible value in the selected compression mode is: %u.\n", + par_name, cmp_par, MAX_STUFF_CMP_PAR); + cfg_invalid++; + } break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - sample_len = sizeof(struct S_FX_EFX_NCOB_ECOB); + default: + debug_print("Error: The compression mode is not supported.\n"); + cfg_invalid++; break; - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - sample_len = sizeof(struct F_FX); + } + + return cfg_invalid; +} + + +/** + * @brief check if the imagette specific compression parameters are invalid + * + * @param cfg pointer to the compressor configuration + * @param rdcu_check set to non-zero if a check for a imagette RDCU compression + * should be done; zero for imagette ICU compression + * + * @returns 0 if the imagette specific parameters are valid, otherwise invalid + */ + +int cmp_cfg_imagette_is_invalid(const struct cmp_cfg *cfg, int rdcu_check) +{ + int cfg_invalid = 0; + enum cmp_mode cmp_mode; + + if (!cfg) + return 0; + + if (!cmp_imagette_data_type_is_used(cfg->data_type)) { + debug_print("Error: The compression data type is not an imagette compression data type.\n"); + cfg_invalid++; + } + + /* The RDCU needs valid compression parameters also in RAW_MODE */ + if (rdcu_check && cfg->cmp_mode == CMP_MODE_RAW) + cmp_mode = CMP_MODE_MODEL_ZERO; + else + cmp_mode = cfg->cmp_mode; + + cfg_invalid += cmp_pars_are_invalid(cfg->golomb_par, cfg->spill, cmp_mode, + cfg->data_type, "imagette"); + + /* for the RDCU the adaptive parameters have to be always valid */ + if (rdcu_check || cmp_ap_imagette_data_type_is_used(cfg->data_type)) { + cfg_invalid += cmp_pars_are_invalid(cfg->ap1_golomb_par, cfg->ap1_spill, + cmp_mode, cfg->data_type, "adaptive 1 imagette"); + cfg_invalid += cmp_pars_are_invalid(cfg->ap2_golomb_par, cfg->ap2_spill, + cmp_mode, cfg->data_type, "adaptive 2 imagette"); + } + + return cfg_invalid; +} + + +/** + * @brief check if the flux/center of brightness specific compression parameters + * are invalid + * + * @param cfg pointer to the compressor configuration + * + * @returns 0 if the flux/center of brightness specific parameters are valid, otherwise invalid + */ + +int cmp_cfg_fx_cob_is_invalid(const struct cmp_cfg *cfg) +{ + int cfg_invalid = 0; + int check_exp_flags = 0, check_ncob = 0, check_efx = 0, check_ecob = 0, check_var = 0; + + if (!cfg) + return 0; + + if (!cmp_fx_cob_data_type_is_used(cfg->data_type)) { + debug_print("Error: The compression data type is not a flux/center of brightness compression data type.\n"); + cfg_invalid++; + } + /* flux parameter is needed for every fx_cob data_type */ + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_fx, cfg->spill_fx, + cfg->cmp_mode, cfg->data_type, "flux"); + + switch (cfg->data_type) { + case DATA_TYPE_S_FX: + check_exp_flags = 1; + break; + case DATA_TYPE_S_FX_EFX: + check_exp_flags = 1; + check_efx = 1; + break; + case DATA_TYPE_S_FX_NCOB: + check_exp_flags = 1; + check_ncob = 1; + break; + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + check_exp_flags = 1; + check_ncob = 1; + check_efx = 1; + check_ecob = 1; + break; + case DATA_TYPE_L_FX: + check_exp_flags = 1; + check_var = 1; + break; + case DATA_TYPE_L_FX_EFX: + check_exp_flags = 1; + check_efx = 1; + check_var = 1; break; - case MODE_MODEL_ZERO_F_FX_EFX: - case MODE_MODEL_MULTI_F_FX_EFX: - case MODE_DIFF_ZERO_F_FX_EFX: - case MODE_DIFF_MULTI_F_FX_EFX: - sample_len = sizeof(struct F_FX_EFX); + case DATA_TYPE_L_FX_NCOB: + check_exp_flags = 1; + check_ncob = 1; + check_var = 1; break; - case MODE_MODEL_ZERO_F_FX_NCOB: - case MODE_MODEL_MULTI_F_FX_NCOB: - case MODE_DIFF_ZERO_F_FX_NCOB: - case MODE_DIFF_MULTI_F_FX_NCOB: - sample_len = sizeof(struct F_FX_NCOB); + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + check_exp_flags = 1; + check_ncob = 1; + check_efx = 1; + check_ecob = 1; + check_var = 1; break; - case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB: - sample_len = sizeof(struct F_FX_EFX_NCOB_ECOB); + case DATA_TYPE_F_FX: break; - case MODE_RAW_32: - case MODE_MODEL_ZERO_32: - case MODE_MODEL_MULTI_32: - case MODE_DIFF_ZERO_32: - case MODE_DIFF_MULTI_32: - sample_len = sizeof(uint32_t); + case DATA_TYPE_F_FX_EFX: + check_efx = 1; + break; + case DATA_TYPE_F_FX_NCOB: + check_ncob = 1; + break; + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + check_ncob = 1; + check_efx = 1; + check_ecob = 1; break; default: - debug_print("Error: Compression mode not supported.\n"); - return 0; + cfg_invalid++; break; } - return sample_len; + + if (check_exp_flags) + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->cmp_mode, cfg->data_type, "exposure flags"); + if (check_ncob) + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->cmp_mode, cfg->data_type, "center of brightness"); + if (check_efx) + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_efx, cfg->spill_efx, + cfg->cmp_mode, cfg->data_type, "extended flux"); + if (check_ecob) + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->cmp_mode, cfg->data_type, "extended center of brightness"); + if (check_var) + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_fx_cob_variance, + cfg->spill_fx_cob_variance, cfg->cmp_mode, cfg->data_type, "flux COB varianc"); + + return cfg_invalid; } /** - * @brief calculate the need bytes to hold a bitstream + * @brief check if the auxiliary science specific compression parameters are invalid * - * @param cmp_size_bit compressed data size, measured in bits + * @param cfg pointer to the compressor configuration * - * @returns the size in bytes to store the hole bitstream - * @note we round up the result to multiples of 4 bytes + * @returns 0 if the auxiliary science specific parameters are valid, otherwise + * invalid + * TODO: implemented DATA_TYPE_F_CAM_OFFSET and DATA_TYPE_F_CAM_BACKGROUND */ -unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit) +int cmp_cfg_aux_is_invalid(const struct cmp_cfg *cfg) { - return (((cmp_size_bit + 7) / 8) + 3) & ~0x3UL; + int cfg_invalid = 0; + + if (!cfg) + return 0; + + if (!cmp_aux_data_type_is_used(cfg->data_type)) { + debug_print("Error: The compression data type is not an auxiliary science compression data type.\n"); + cfg_invalid++; + } + + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_mean, cfg->spill_mean, + cfg->cmp_mode, cfg->data_type, "mean"); + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_variance, cfg->spill_variance, + cfg->cmp_mode, cfg->data_type, "variance"); + + /* if (cfg->data_type != DATA_TYPE_OFFSET && cfg->data_type != DATA_TYPE_F_CAM_OFFSET) */ + if (cfg->data_type != DATA_TYPE_OFFSET) + cfg_invalid += cmp_pars_are_invalid(cfg->cmp_par_pixels_error, cfg->spill_pixels_error, + cfg->cmp_mode, cfg->data_type, "outlier pixls num"); + + return cfg_invalid; } /** - * @brief calculate the need bytes for the data + * @brief check if a compression configuration is invalid * - * @param samples number of data samples - * @param cmp_mode used compression mode + * @param cfg pointer to the compressor configuration * - * @returns the size in bytes to store the data sample + * @returns 0 if the compression configuration is valid, otherwise invalid */ -unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode) +int cmp_cfg_is_invalid(const struct cmp_cfg *cfg) { - return samples * size_of_a_sample(cmp_mode); + int cfg_invalid = 0; + + if (!cfg) + return 0; + + cfg_invalid += cmp_cfg_icu_gen_par_is_invalid(cfg); + + cfg_invalid += cmp_cfg_icu_buffers_is_invalid(cfg); + + if (cmp_imagette_data_type_is_used(cfg->data_type)) + cfg_invalid += cmp_cfg_imagette_is_invalid(cfg, ICU_CHECK); + else if (cmp_fx_cob_data_type_is_used(cfg->data_type)) + cfg_invalid += cmp_cfg_fx_cob_is_invalid(cfg); + else if (cmp_aux_data_type_is_used(cfg->data_type)) + cfg_invalid += cmp_cfg_aux_is_invalid(cfg); + else + cfg_invalid++; + + return cfg_invalid; } @@ -593,14 +874,13 @@ unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode) * * @param cfg compressor configuration contains all parameters required for * compression - * */ void print_cmp_cfg(const struct cmp_cfg *cfg) { size_t i; - printf("cmp_mode: %u\n", cfg->cmp_mode); + printf("cmp_mode: %i\n", cfg->cmp_mode); printf("golomb_par: %u\n", cfg->golomb_par); printf("spill: %u\n", cfg->spill); printf("model_value: %u\n", cfg->model_value); diff --git a/lib/decmp.c b/lib/decmp.c index 4953f5d55566e47e1307cf423e626e5795850d48..3be77c96daeac25b6e63b8099ee09af53649679b 100644 --- a/lib/decmp.c +++ b/lib/decmp.c @@ -1,1522 +1,2196 @@ +/** + * @file decmp.c + * @author Dominik Loidolt (dominik.loidolt@univie.ac.at), + * @date 2020 + * + * @copyright GPLv2 + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * @brief software decompression library + * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001 + * + * To decompress a compression entity (consisting of a compression entity header + * and the compressed data) use the decompress_cmp_entiy() function. + */ + #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> -#include "../include/cmp_support.h" -#include "../include/cmp_icu.h" -#include "../include/cmp_data_types.h" -#include "../include/byteorder.h" -#include "../include/cmp_debug.h" - - -double get_compression_ratio(const struct cmp_info *info) -{ - unsigned long orign_len_bits = info->samples_used * size_of_a_sample(info->cmp_mode_used) * CHAR_BIT; - - return (double)orign_len_bits/(double)info->cmp_size; -} +#include "byteorder.h" +#include "cmp_debug.h" +#include "cmp_support.h" +#include "cmp_data_types.h" +#include "cmp_entity.h" -void *malloc_decompressed_data(const struct cmp_info *info) -{ - size_t sample_len; +#define MAX_CW_LEN 32 /* maximum Golomb code word bit length */ - if (!info) - return NULL; - if (info->samples_used == 0) - return NULL; +/* maximum used bits registry */ +extern struct cmp_max_used_bits max_used_bits; - sample_len = size_of_a_sample(info->cmp_mode_used); +/* function pointer to a code word decoder function */ +typedef int (*decoder_ptr)(uint32_t, unsigned int, unsigned int, uint32_t *); - return malloc(info->samples_used * sample_len); -} +/* structure to hold a setup to encode a value */ +struct decoder_setup { + decoder_ptr decode_cw_f; /* pointer to the code word decoder (Golomb/Rice)*/ + int (*decode_method_f)(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup); /* pointer to the decoding function */ + uint32_t *bitstream_adr; /* start address of the compressed data bitstream */ + uint32_t max_stream_len; /* maximum length of the bitstream/icu_output_buf in bits */ + uint32_t encoder_par1; /* encoding parameter 1 */ + uint32_t encoder_par2; /* encoding parameter 2 */ + uint32_t outlier_par; /* outlier parameter */ + uint32_t lossy_par; /* lossy compression parameter */ + uint32_t model_value; /* model value parameter */ + uint32_t max_data_bits; /* how many bits are needed to represent the highest possible value */ +}; /** - * @brief decompression data pre-processing in RAW mode - * - * @note in RAW mode the data are uncompressed no pre_processing needed + * @brief count leading 1-bits * - * @param cmp_mode_used used compression mode + * @param value input vale to count * - * @returns 0 on success, error otherwise + * @returns the number of leading 1-bits in value, starting at the most + * significant bit position */ -static int de_raw_pre_process(uint8_t cmp_mode_used) +static unsigned int count_leading_ones(uint32_t value) { - if (!raw_mode_is_used(cmp_mode_used)) - return -1; + if (value == 0xFFFFFFFF) + return 32; - return 0; + return __builtin_clz(~value); } /** - * @brief model decompression pre-processing + * @brief decode a Rice code word * - * @note change the data_buf in-place + * @param code_word Rice code word bitstream starting at the MSB + * @param m Golomb parameter (not used) + * @param log2_m Rice parameter, must be the same used for encoding + * @param decoded_cw pointer where decoded value is written * - * @param data_buf pointer to the data to process - * @param model_buf pointer to the model of the data to process - * @param samples_used the size of the data and model buffer in 16 bit units - * @param model_value_used used model weighting parameter - * @param round_used used number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise + * @returns the length of the decoded code word in bits (NOT the decoded value); + * 0 on failure */ -static int de_model_16(uint16_t *data_buf, uint16_t *model_buf, uint32_t - samples_used, uint8_t model_value_used, uint8_t - round_used) +static int rice_decoder(uint32_t code_word, unsigned int m, unsigned int log2_m, + uint32_t *decoded_cw) { - size_t i; - int err; + unsigned int q; /* quotient code */ + unsigned int ql; /* length of the quotient code */ + unsigned int r; /* remainder code */ + unsigned int rl = log2_m; /* length of the remainder code */ + unsigned int cw_len; /* length of the decoded code word in bits */ + + (void)m; /* we don't need the Golomb parameter */ - if (!samples_used) + if (log2_m > 32) /* because m has 32 bits log2_m can not be bigger than 32 */ return 0; - if (!data_buf) - return -1; + q = count_leading_ones(code_word); /* decode unary coding */ + ql = q + 1; /* Number of 1's + following 0 */ - if (!model_buf) - return -1; + cw_len = rl + ql; - if (model_value_used > MAX_MODEL_VALUE) - return -1; + if (cw_len > 32) /* can only decode code words with maximum 32 bits */ + return 0; - for (i = 0; i < samples_used; i++) { - /* overflow is intended */ - data_buf[i] = (uint16_t)(data_buf[i] + round_fwd(model_buf[i], - round_used)); - } + code_word = code_word << ql; /* shift quotient code out */ - err = de_lossy_rounding_16(data_buf, samples_used, round_used); - if (err) - return -1; + /* Right shifting an integer by a number of bits equal or greater than + * its size is undefined behavior */ + if (rl == 0) + r = 0; + else + r = code_word >> (32 - rl); - for (i = 0; i < samples_used; i++) { - model_buf[i] = (uint16_t)cal_up_model(data_buf[i], model_buf[i], - model_value_used); - } - return 0; + *decoded_cw = (q << rl) + r; + + return cw_len; } -static int de_model_S_FX(struct S_FX *data_buf, struct S_FX *model_buf, uint32_t - samples_used, uint8_t model_value_used, uint8_t - round_used) -{ - size_t i; - int err; +/** + * @brief decode a Golomb code word + * + * @param code_word Golomb code word bitstream starting at the MSB + * @param m Golomb parameter (have to be bigger than 0) + * @param log2_m is log_2(m) calculate outside function for better + * performance + * @param decoded_cw pointer where decoded value is written + * + * @returns the length of the decoded code word in bits (NOT the decoded value); + * 0 on failure + */ - if (!samples_used) - return 0; +static int golomb_decoder(uint32_t code_word, unsigned int m, + unsigned int log2_m, uint32_t *decoded_cw) +{ + unsigned int q; /* quotient code */ + unsigned int r1; /* remainder code group 1 */ + unsigned int r2; /* remainder code group 2 */ + unsigned int r; /* remainder code */ + unsigned int rl; /* length of the remainder code */ + unsigned int cutoff; /* cutoff between group 1 and 2 */ + unsigned int cw_len; /* length of the decoded code word in bits */ - if (!data_buf) - return -1; + q = count_leading_ones(code_word); /* decode unary coding */ - if (!model_buf) - return -1; + rl = log2_m + 1; + code_word <<= (q+1); /* shift quotient code out */ - if (model_value_used > MAX_MODEL_VALUE) - return -1; + r2 = code_word >> (32 - rl); + r1 = r2 >> 1; - for (i = 0; i < samples_used; i++) { - /* overflow is intended */ - struct S_FX round_model = model_buf[i]; + cutoff = (1UL << rl) - m; - lossy_rounding_S_FX(&round_model, 1, round_used); - data_buf[i] = add_S_FX(data_buf[i], model_buf[i]); + if (r1 < cutoff) { /* group 1 */ + cw_len = q + rl; + r = r1; + } else { /* group 2 */ + cw_len = q + rl + 1; + r = r2 - cutoff; } - err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used); - if (err) - return -1; - - for (i = 0; i < samples_used; i++) - model_buf[i] = cal_up_model_S_FX(data_buf[i], model_buf[i], - model_value_used); + if (cw_len > 32) + return 0; - return 0; + *decoded_cw = q*m + r; + return cw_len; } /** - * @brief 1d-differencing decompression per-processing + * @brief select the decoder based on the used Golomb parameter + * @note if the Golomb parameter is a power of 2 we can use the faster Rice + * decoder * - * @param data_buf pointer to the data to process - * @param samples_used the size of the data and model buffer in 16 bit units - * @param round_used used number of bits to round; if zero no rounding takes place + * @param golomb_par Golomb parameter (have to be bigger than 0) * - * @returns 0 on success, error otherwise + * @returns function pointer to the select decoder function; NULL on failure */ -static int de_diff_16(uint16_t *data_buf, uint32_t samples_used, uint8_t - round_used) +static decoder_ptr select_decoder(unsigned int golomb_par) { - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = data_buf[i] + data_buf[i-1]; - } - - err = de_lossy_rounding_16(data_buf, samples_used, round_used); - if (err) - return -1; + if (!golomb_par) + return NULL; - return 0; + if (is_a_pow_of_2(golomb_par)) + return &rice_decoder; + else + return &golomb_decoder; } -static int de_diff_32(uint32_t *data_buf, uint32_t samples_used, uint8_t - round_used) -{ - size_t i; - int err; +/** + * @brief read a value of up to 32 bits from a bitstream + * + * @param p_value pointer to the read value, the + * read value will be converted to the system + * endianness + * @param n_bits number of bits to read from the bitstream + * @param bit_offset bit index where the bits will be read, seen from + * the very beginning of the bitstream + * @param bitstream_adr this is the pointer to the beginning of the + * bitstream + * @param max_stream_len maximum length of the bitstream in bits * + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF + * if the bitstream buffer is too small to read the value from the + * bitstream + */ - if (!samples_used) - return 0; +static int get_n_bits32(uint32_t *p_value, unsigned int n_bits, int bit_offset, + uint32_t *bitstream_adr, unsigned int max_stream_len) +{ + uint32_t *local_adr; + unsigned int bitsLeft, bitsRight, localEndPos; + unsigned int mask; + int stream_len = (int)(n_bits + (unsigned int)bit_offset); /* overflow results in a negative return value */ - if (!data_buf) + /*leave in case of erroneous input */ + if (bit_offset < 0) return -1; + if (n_bits == 0) + return -1; + if (n_bits > 32) + return -1; + if (!bitstream_adr) + return -1; + if (!p_value) + return -1; + + /* Check if bitstream buffer is large enough */ + if ((unsigned int)stream_len > max_stream_len) { + debug_print("Error: Buffer overflow detected.\n"); + return CMP_ERROR_SMALL_BUF; - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = data_buf[i] + data_buf[i-1]; } - err = de_lossy_rounding_32(data_buf, samples_used, round_used); - if (err) - return -1; + /* separate the bit_offset into word offset (set local_adr pointer) and + * local bit offset (bitsLeft) + */ + local_adr = bitstream_adr + (bit_offset >> 5); + bitsLeft = bit_offset & 0x1f; - return 0; -} + localEndPos = bitsLeft + n_bits; + if (localEndPos <= 32) { + unsigned int shiftRight = 32 - n_bits; -static int de_diff_S_FX(struct S_FX *data_buf, uint32_t samples_used, uint8_t - round_used) -{ - size_t i; - int err; + bitsRight = shiftRight - bitsLeft; - if (!samples_used) - return 0; + *(p_value) = cpu_to_be32(*(local_adr)) >> bitsRight; - if (!data_buf) - return -1; + mask = (0xffffffff >> shiftRight); - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX(data_buf[i], data_buf[i-1]); - } + *(p_value) &= mask; + } else { + unsigned int n1 = 32 - bitsLeft; + unsigned int n2 = n_bits - n1; + /* part 1 ; */ + mask = 0xffffffff >> bitsLeft; + *(p_value) = cpu_to_be32(*(local_adr)) & mask; + *(p_value) <<= n2; + /*part 2: */ + /* adjust address*/ + local_adr += 1; - err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used); - if (err) - return -1; + bitsRight = 32 - n2; + *(p_value) |= cpu_to_be32(*(local_adr)) >> bitsRight; + } - return 0; + return stream_len; } -static int de_diff_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples_used, - uint8_t round_used) +/** + * @brief decode a Golomb/Rice encoded code word from the bitstream + * + * @param decoded_value pointer to the decoded value + * @param stream_pos start bit position code word to be decoded in the bitstream + * @param setup pointer to the decoder setup + * + * @returns bit index of the next code word in the bitstream on success; returns + * negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the + * bitstream buffer is too small to read the value from the bitstream + */ + +static int decode_normal(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup) { - size_t i; - int err; + uint32_t read_val; + unsigned int n_read_bits; + int stream_pos_read, cw_len; - if (!samples_used) - return 0; + /* check if we can read max_cw_len or less; we do not know how long the + * code word actually is so we try to read the maximum cw length */ + if ((unsigned int)stream_pos + 32 > setup->max_stream_len) + n_read_bits = setup->max_stream_len - (unsigned int)stream_pos; + else + n_read_bits = MAX_CW_LEN; - if (!data_buf) - return -1; + stream_pos_read = get_n_bits32(&read_val, n_read_bits, stream_pos, + setup->bitstream_adr, setup->max_stream_len); + if (stream_pos_read < 0) + return stream_pos_read; - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX_EFX(data_buf[i], data_buf[i-1]); - } + /* if we read less than 32, we shift the bitstream so that it starts at the MSB */ + read_val = read_val << (32 - n_read_bits); - err = de_lossy_rounding_S_FX_EFX(data_buf, samples_used, round_used); - if (err) + cw_len = setup->decode_cw_f(read_val, setup->encoder_par1, + setup->encoder_par2, decoded_value); + if (cw_len <= 0) + return -1; + /* consistency check: code word length can not be bigger than the read bits */ + if (cw_len > (int)n_read_bits) return -1; - return 0; + return stream_pos + cw_len; } -static int de_diff_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t samples_used, - uint8_t round_used) -{ - size_t i; - int err; +/** + * @brief decode a Golomb/Rice encoded code word with zero escape system + * mechanism from the bitstream + * + * @param decoded_value pointer to the decoded value + * @param stream_pos start bit position code word to be decoded in the bitstream + * @param setup pointer to the decoder setup + * + * @returns bit index of the next code word in the bitstream on success; returns + * negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the + * bitstream buffer is too small to read the value from the bitstream + */ - if (!samples_used) - return 0; +static int decode_zero(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup) +{ + stream_pos = decode_normal(decoded_value, stream_pos, setup); + if (stream_pos < 0) + return stream_pos; - if (!data_buf) + /* consistency check: value lager than the outlier parameter should not + * be Golomb/Rice encoded */ + if (*decoded_value > setup->outlier_par) return -1; - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX_NCOB(data_buf[i], data_buf[i-1]); + if (*decoded_value == 0) { + /* escape symbol mechanism was used; read unencoded value */ + uint32_t unencoded_val; + + stream_pos = get_n_bits32(&unencoded_val, setup->max_data_bits, stream_pos, + setup->bitstream_adr, setup->max_stream_len); + if (stream_pos < 0) + return stream_pos; + /* consistency check: outliers must be bigger than the outlier_par */ + if (unencoded_val < setup->outlier_par && unencoded_val != 0) + return -1; + + *decoded_value = unencoded_val; } - err = de_lossy_rounding_S_FX_NCOB(data_buf, samples_used, round_used); - if (err) - return -1; + (*decoded_value)--; + if (*decoded_value == 0xFFFFFFFF) /* catch underflow */ + (*decoded_value) >>= (32 - setup->max_data_bits); - return 0; + return stream_pos; } -static int de_diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - uint32_t samples_used, uint8_t round_used) +/** + * @brief decode a Golomb/Rice encoded code word with multi escape system + * mechanism from the bitstream + * + * @param decoded_value pointer to the decoded value + * @param stream_pos start bit position code word to be decoded in the bitstream + * @param setup pointer to the decoder setup + * + * @returns bit index of the next code word in the bitstream on success; returns + * negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the + * bitstream buffer is too small to read the value from the bitstream + */ + +static int decode_multi(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup) { - size_t i; - int err; + stream_pos = decode_normal(decoded_value, stream_pos, setup); + if (stream_pos < 0) + return stream_pos; - if (!samples_used) - return 0; + if (*decoded_value >= setup->outlier_par) { + /* escape symbol mechanism was used; read unencoded value */ + uint32_t unencoded_val; + unsigned int unencoded_len; - if (!data_buf) - return -1; + unencoded_len = (*decoded_value - setup->outlier_par + 1) * 2; - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX_EFX_NCOB_ECOB(data_buf[i], data_buf[i-1]); + stream_pos = get_n_bits32(&unencoded_val, unencoded_len, stream_pos, + setup->bitstream_adr, setup->max_stream_len); + if (stream_pos >= 0) + *decoded_value = unencoded_val + setup->outlier_par; } - - err = de_lossy_rounding_S_FX_EFX_NCOB_ECOB(data_buf, samples_used, - round_used); - if (err) - return -1; - - return 0; + return stream_pos; } -static int de_pre_process(void *decoded_data, void *de_model_buf, - const struct cmp_info *info) -{ - if (!decoded_data) - return -1; - - if (!info) - return -1; - - if (info->samples_used == 0) - return 0; +/** + * @brief get the value unencoded with setup->cmp_par_1 bits without any + * additional changes from the bitstream + * + * @param decoded_value pointer to the decoded value + * @param stream_pos start bit position code word to be decoded in the bitstream + * @param setup pointer to the decoder setup + * + * @returns bit index of the next code word in the bitstream on success; returns + * negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the + * bitstream buffer is too small to read the value from the bitstream + * + */ - switch (info->cmp_mode_used) { - case MODE_RAW: - case MODE_RAW_S_FX: - return de_raw_pre_process(info->cmp_mode_used); - break; - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - return de_model_16((uint16_t *)decoded_data, - (uint16_t *)de_model_buf, info->samples_used, - info->model_value_used, info->round_used); - break; - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - return de_diff_16((uint16_t *)decoded_data, info->samples_used, - info->round_used); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - return de_model_S_FX((struct S_FX *)decoded_data, - (struct S_FX *)de_model_buf, - info->samples_used, info->model_value_used, - info->round_used); - break; - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return de_diff_S_FX((struct S_FX *)decoded_data, - info->samples_used, info->round_used); - break; - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return de_diff_S_FX_EFX((struct S_FX_EFX *)decoded_data, - info->samples_used, info->round_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - return -1; - break; - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return de_diff_S_FX_NCOB((struct S_FX_NCOB *)decoded_data, - info->samples_used, info->round_used); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - return -1; - break; - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return de_diff_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *) - decoded_data, - info->samples_used, - info->round_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - return -1; - break; - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - return de_diff_32((uint32_t *)decoded_data, info->samples_used, - info->round_used); - break; - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - return -1; - break; - default: - debug_print("Error: Compression mode not supported.\n"); - break; - } +static int decode_none(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup) +{ + stream_pos = get_n_bits32(decoded_value, setup->encoder_par1, stream_pos, + setup->bitstream_adr, setup->max_stream_len); - return -1; + return stream_pos; } -static uint8_t de_map_to_pos_alg_8(uint8_t value_to_unmap) +/** + * @brief remap an unsigned value back to a signed value + * @note this is the reverse function of map_to_pos() + * + * @param value_to_unmap unsigned value to remap + * + * @returns the signed remapped value + */ + +static uint32_t re_map_to_pos(uint32_t value_to_unmap) { - if (value_to_unmap & 0x1) /* if uneven */ - return (value_to_unmap + 1) / -2; - else + if (value_to_unmap & 0x1) { /* if uneven */ + if (value_to_unmap == 0xFFFFFFFF) /* catch overflow */ + return 0x80000000; + return -((value_to_unmap + 1) / 2); + } else { return value_to_unmap / 2; + } } -static uint16_t de_map_to_pos_alg_16(uint16_t value_to_unmap) +/** + * @brief decompress the next code word in the bitstream and decorate it with + * the model + * + * @param decoded_value pointer to the decoded value + * @param model model of the decoded_value (0 if not used) + * @param stream_pos start bit position code word to be decoded in the bitstream + * @param setup pointer to the decoder setup + * + * @returns bit index of the next code word in the bitstream on success; returns + * negative in case of erroneous input; returns CMP_ERROR_SMALL_BUF if the + * bitstream buffer is too small to read the value from the bitstream + */ + +static int decode_value(uint32_t *decoded_value, uint32_t model, + int stream_pos, const struct decoder_setup *setup) { - if (value_to_unmap & 0x1) /* if uneven */ - return (value_to_unmap + 1) / -2; - else - return value_to_unmap / 2; -} + uint32_t mask = (~0U >> (32 - setup->max_data_bits)); /* mask the used bits */ + /* decode the next value from the bitstream */ + stream_pos = setup->decode_method_f(decoded_value, stream_pos, setup); + if (stream_pos <= 0) + return stream_pos; -static uint32_t de_map_to_pos_alg_32(uint32_t value_to_unmap) -{ + if (setup->decode_method_f == decode_none) + /* we are done here in stuff mode */ + return stream_pos; - if (value_to_unmap & 0x1) /* if uneven */ - return ((int64_t)value_to_unmap + 1) / -2; /* typecast to prevent overflow */ - else - return value_to_unmap / 2; + /* map the unsigned decode value back to a signed value */ + *decoded_value = re_map_to_pos(*decoded_value); + + /* decorate data the data with the model */ + *decoded_value += round_fwd(model, setup->lossy_par); + + /* we mask only the used bits in case there is an overflow when adding the model */ + *decoded_value &= mask; + + /* inverse step of the lossy compression */ + *decoded_value = round_inv(*decoded_value, setup->lossy_par); + + return stream_pos; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * 16-bit buffer + * @brief configure a decoder setup structure to have a setup to decode a vale * - * @note change the data_buf in-place + * @param setup pointer to the decoder setup + * @param cmp_par compression parameter + * @param spillover spillover_par parameter + * @param lossy_par lossy compression parameter + * @param max_data_bits how many bits are needed to represent the highest possible value + * @param cfg pointer to the compression configuration structure * - * @param data_buf pointer to the uint16_t data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise + * @returns 0 on success; otherwise error */ -static int de_map_to_pos_16(uint16_t *data_buf, uint32_t samples_used, int - zero_mode_used) +static int configure_decoder_setup(struct decoder_setup *setup, + uint32_t cmp_par, uint32_t spillover, + uint32_t lossy_par, uint32_t max_data_bits, + const struct cmp_cfg *cfg) { - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) + if (multi_escape_mech_is_used(cfg->cmp_mode)) + setup->decode_method_f = &decode_multi; + else if (zero_escape_mech_is_used(cfg->cmp_mode)) + setup->decode_method_f = &decode_zero; + else if (cfg->cmp_mode == CMP_MODE_STUFF) + setup->decode_method_f = &decode_none; + else { + setup->decode_method_f = NULL; + debug_print("Error: Compression mode not supported.\n"); return -1; + } - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) - data_buf[i] -= 1; - - data_buf[i] = (uint16_t)de_map_to_pos_alg_16(data_buf[i]); + setup->bitstream_adr = cfg->icu_output_buf; /* start address of the compressed data bitstream */ + if (cfg->buffer_length & 0x3) { + debug_print("Error: The length of the compressed data is not a multiple of 4 bytes."); + return -1; } + setup->max_stream_len = (cfg->buffer_length) * CHAR_BIT; /* maximum length of the bitstream/icu_output_buf in bits */ + setup->encoder_par1 = cmp_par; /* encoding parameter 1 */ + if (ilog_2(cmp_par) < 0) + return -1; + setup->encoder_par2 = ilog_2(cmp_par); /* encoding parameter 2 */ + setup->outlier_par = spillover; /* outlier parameter */ + setup->lossy_par = lossy_par; /* lossy compression parameter */ + setup->model_value = cfg->model_value; /* model value parameter */ + setup->max_data_bits = max_data_bits; /* how many bits are needed to represent the highest possible value */ + setup->decode_cw_f = select_decoder(cmp_par); + return 0; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * 32-bit buffer - * - * @note change the data_buf in-place + * @brief decompress imagette data * - * @param data_buf pointer to the uint16_t data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream */ -static int de_map_to_pos_32(uint32_t *data_buf, uint32_t samples_used, int - zero_mode_used) +static int decompress_imagette(struct cmp_cfg *cfg) { + int err; size_t i; + int stream_pos = 0; + struct decoder_setup setup; + uint16_t *decompressed_data = cfg->input_buf; + uint16_t *model_buf = cfg->model_buf; + uint16_t *up_model_buf = cfg->icu_new_model_buf; + uint32_t decoded_value = 0; + uint16_t model; + + err = configure_decoder_setup(&setup, cfg->golomb_par, cfg->spill, + cfg->round, max_used_bits.nc_imagette, cfg); + if (err) + return -1; - if (!samples_used) - return 0; - if (!data_buf) - return -1; + for (i = 0; i < cfg->samples; i++) { + if (model_mode_is_used(cfg->cmp_mode)) + model = model_buf[i]; + else + model = decoded_value; - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) - data_buf[i] -= 1; + stream_pos = decode_value(&decoded_value, model, stream_pos, &setup); + if (stream_pos <= 0) + return stream_pos; + decompressed_data[i] = decoded_value; - data_buf[i] = (uint32_t)de_map_to_pos_alg_32(data_buf[i]); + if (up_model_buf) { + up_model_buf[i] = cmp_up_model(decoded_value, model, + cfg->model_value, setup.lossy_par); + } } - return 0; + + return stream_pos; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX buffer + * @brief decompress the multi-entry packet header structure and sets the data, + * model and up_model pointers to the data after the header * - * @note change the data_buf in-place + * @param data pointer to a pointer pointing to the data to be compressed + * @param model pointer to a pointer pointing to the model of the data + * @param up_model pointer to a pointer pointing to the updated model buffer + * @param cfg pointer to the compression configuration structure * - * @param data_buf pointer to the S_FX data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @returns the bit length of the bitstream on success * - * @returns 0 on success, error otherwise + * @note the (void **) cast relies on all pointer types having the same internal + * representation which is common, but not universal; http://www.c-faq.com/ptrs/genericpp.html */ -static int de_map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples_used, int - zero_mode_used) +static int decompress_multi_entry_hdr(void **data, void **model, void **up_model, + const struct cmp_cfg *cfg) { - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) + if (cfg->buffer_length < MULTI_ENTRY_HDR_SIZE) return -1; - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - } + if (*data) { + if (cfg->icu_output_buf) + memcpy(*data, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE); + *data = (uint8_t *)*data + MULTI_ENTRY_HDR_SIZE; + } - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); + if (*model) { + if (cfg->icu_output_buf) + memcpy(*model, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE); + *model = (uint8_t *)*model + MULTI_ENTRY_HDR_SIZE; } - return 0; + + if (*up_model) { + if (cfg->icu_output_buf) + memcpy(*up_model, cfg->icu_output_buf, MULTI_ENTRY_HDR_SIZE); + *up_model = (uint8_t *)*up_model + MULTI_ENTRY_HDR_SIZE; + } + + return MULTI_ENTRY_HDR_SIZE * CHAR_BIT; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX_EFX buffer + * @brief decompress short normal light flux (S_FX) data * - * @note change the data_buf in-place + * @param cfg pointer to the compression configuration structure * - * @param data_buf pointer to the S_FX_EFX data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream */ -static int de_map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t - samples_used, int zero_mode_used) +static int decompress_s_fx(const struct cmp_cfg *cfg) { size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx; + struct s_fx *data_buf = cfg->input_buf; + struct s_fx *model_buf = cfg->model_buf; + struct s_fx *up_model_buf = NULL; + struct s_fx *next_model_p; + struct s_fx model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!samples_used) - return 0; - - if (!data_buf) + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg)) return -1; - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - data_buf[i].EFX -= 1; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); } - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].EFX = de_map_to_pos_alg_32(data_buf[i].EFX); + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_pos; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX_NCOB buffer + * @brief decompress S_FX_EFX data * - * @note change the data_buf in-place + * @param cfg pointer to the compression configuration structure * - * @param data_buf pointer to the S_FX_NCOB data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream */ -static int de_map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t - samples_used, int zero_mode_used) +static int decompress_s_fx_efx(const struct cmp_cfg *cfg) { size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_efx; + struct s_fx_efx *data_buf = cfg->input_buf; + struct s_fx_efx *model_buf = cfg->model_buf; + struct s_fx_efx *up_model_buf = NULL; + struct s_fx_efx *next_model_p; + struct s_fx_efx model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!samples_used) - return 0; - - if (!data_buf) + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.s_efx, cfg)) return -1; - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - data_buf[i].NCOB_X -= 1; - data_buf[i].NCOB_Y -= 1; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.efx, stream_pos, + &setup_efx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].efx = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); } - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = de_map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = de_map_to_pos_alg_32(data_buf[i].NCOB_Y); + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_pos; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX_EFX_NCOB_ECOB buffer + * @brief decompress short S_FX_NCOB data * - * @note change the data_buf in-place + * @param cfg pointer to the compression configuration structure * - * @param data_buf pointer to the S_FX_EFX_NCOB_ECOB data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream */ -static int de_map_to_pos_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - uint32_t samples_used, - int zero_mode_used) +static int decompress_s_fx_ncob(const struct cmp_cfg *cfg) { size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_ncob; + struct s_fx_ncob *data_buf = cfg->input_buf; + struct s_fx_ncob *model_buf = cfg->model_buf; + struct s_fx_ncob *up_model_buf = NULL; + struct s_fx_ncob *next_model_p; + struct s_fx_ncob model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!samples_used) - return 0; - - if (!data_buf) + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.s_ncob, cfg)) return -1; - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - data_buf[i].NCOB_X -= 1; - data_buf[i].NCOB_Y -= 1; - data_buf[i].EFX -= 1; - data_buf[i].ECOB_X -= 1; - data_buf[i].ECOB_Y -= 1; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_y = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); } - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = de_map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = de_map_to_pos_alg_32(data_buf[i].NCOB_Y); - data_buf[i].EFX = de_map_to_pos_alg_32(data_buf[i].EFX); - data_buf[i].ECOB_X = de_map_to_pos_alg_32(data_buf[i].ECOB_X); - data_buf[i].ECOB_Y = de_map_to_pos_alg_32(data_buf[i].ECOB_Y); + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return 0; + return stream_pos; } /** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * F_FX buffer - * - * @note change the data_buf in-place + * @brief decompress short S_FX_NCOB_ECOB data * - * @param data_buf pointer to the F_FX data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream */ -static int de_map_to_pos_F_FX(uint32_t *data_buf, uint32_t samples_used, int - zero_mode_used) +static int decompress_s_fx_efx_ncob_ecob(const struct cmp_cfg *cfg) { - return de_map_to_pos_32(data_buf, samples_used, zero_mode_used); + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, setup_efx, setup_ecob; + struct s_fx_efx_ncob_ecob *data_buf = cfg->input_buf; + struct s_fx_efx_ncob_ecob *model_buf = cfg->model_buf; + struct s_fx_efx_ncob_ecob *up_model_buf = NULL; + struct s_fx_efx_ncob_ecob *next_model_p; + struct s_fx_efx_ncob_ecob model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } + + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.s_exp_flags, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.s_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.s_ncob, cfg)) + return -1; + if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.s_efx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->round, max_used_bits.s_ecob, cfg)) + return -1; + + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_y = decoded_value; + + stream_pos = decode_value(&decoded_value, model.efx, stream_pos, + &setup_efx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].efx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ecob_x, stream_pos, + &setup_ecob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ecob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ecob_y, stream_pos, + &setup_ecob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ecob_y = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y, + cfg->model_value, setup_ecob.lossy_par); + } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; + } + return stream_pos; } /** - * @brief map the unsigned output of the pre-stage to a signed value range - * - * @note change the data_buf in-place + * @brief decompress fast normal light flux (F_FX) data * - * @param decompressed_data pointer to the data to process - * @param info compressor information contains information of - * an executed compression + * @param cfg pointer to the compression configuration structure * - * @returns 0 on success, error otherwise + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream */ -static int de_map_to_pos(void *decompressed_data, const struct cmp_info *info) +static int decompress_f_fx(const struct cmp_cfg *cfg) { - int zero_mode_used; + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_fx; + struct f_fx *data_buf = cfg->input_buf; + struct f_fx *model_buf = cfg->model_buf; + struct f_fx *up_model_buf = NULL; + struct f_fx *next_model_p; + struct f_fx model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!info) + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg)) return -1; - if (info->samples_used == 0) - return 0; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; - if (!decompressed_data) - return -1; - - zero_mode_used = zero_escape_mech_is_used(info->cmp_mode_used); - - switch (info->cmp_mode_used) { - case MODE_RAW: - case MODE_RAW_S_FX: - return 0; /* in raw mode no mapping is necessary */ - break; - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - return de_map_to_pos_16((uint16_t *)decompressed_data, - info->samples_used, zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return de_map_to_pos_S_FX((struct S_FX *)decompressed_data, - info->samples_used, zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return de_map_to_pos_S_FX_EFX((struct S_FX_EFX *) - decompressed_data, - info->samples_used, - zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return de_map_to_pos_S_FX_NCOB((struct S_FX_NCOB *) - decompressed_data, - info->samples_used, - zero_mode_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return de_map_to_pos_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *) - decompressed_data, - info->samples_used, - zero_mode_used); - break; - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - return de_map_to_pos_F_FX((uint32_t *)decompressed_data, - info->samples_used, zero_mode_used); - break; - default: - debug_print("Error: Compression mode not supported.\n"); - break; - } - return -1; -} + if (up_model_buf) + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + if (i >= cfg->samples-1) + break; -static unsigned int get_n_bits32(uint32_t *p_value, unsigned int bitOffset, - unsigned int nBits, const unsigned int *srcAddr, - size_t src_len_bit) -{ - const unsigned int *localAddr; - unsigned int bitsLeft, bitsRight, localEndPos; - unsigned int mask; - /*leave in case of erroneous input */ - if (nBits == 0) - return 0; - if (nBits > 32) - return 0; - if (!srcAddr) - return 0; - if (!p_value) - return 0; - if ((bitOffset + nBits) > src_len_bit) { - debug_print("Error: Buffer overflow detected.\n"); - return 0; + model = next_model_p[i]; } - /* separate the bitOffset into word offset (set localAddr pointer) and - * local bit offset (bitsLeft) - */ - - localAddr = srcAddr + (bitOffset >> 5); - bitsLeft = bitOffset & 0x1f; - - localEndPos = bitsLeft + nBits; - - if (localEndPos <= 32) { - unsigned int shiftRight = 32 - nBits; - - bitsRight = shiftRight - bitsLeft; + return stream_pos; +} - *(p_value) = *(localAddr) >> bitsRight; - mask = (0xffffffff >> shiftRight); +/** + * @brief decompress F_FX_EFX data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ - *(p_value) &= mask; +static int decompress_f_fx_efx(const struct cmp_cfg *cfg) +{ + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_fx, setup_efx; + struct f_fx_efx *data_buf = cfg->input_buf; + struct f_fx_efx *model_buf = cfg->model_buf; + struct f_fx_efx *up_model_buf = NULL; + struct f_fx_efx *next_model_p; + struct f_fx_efx model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; } else { - unsigned int n1 = 32 - bitsLeft; - unsigned int n2 = nBits - n1; - /* part 1 ; */ - mask = 0xffffffff >> bitsLeft; - *(p_value) = (*localAddr) & mask; - *(p_value) <<= n2; - /*part 2: */ - /* adjust address*/ - localAddr += 1; - - bitsRight = 32 - n2; - *(p_value) |= *(localAddr) >> bitsRight; + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; } - return nBits; -} -static unsigned int count_leading_ones(unsigned int value) -{ - unsigned int n_ones = 0; /* number of leading 1s */ + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.f_efx, cfg)) + return -1; - while (1) { - unsigned int leading_bit; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.efx, stream_pos, + &setup_efx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].efx = decoded_value; + + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + } - leading_bit = value & 0x80000000; - if (!leading_bit) + if (i >= cfg->samples-1) break; - else { - n_ones++; - value <<= 1; - } + + model = next_model_p[i]; } - return n_ones; + return stream_pos; } -static unsigned int Rice_decoder(uint32_t code_word, unsigned int m, - unsigned int log2_m, unsigned int *decoded_cw) -{ - unsigned int q; /* quotient code */ - unsigned int ql; /* length of the quotient code */ - unsigned int r; /* remainder code */ - unsigned int rl; /* length of the remainder code */ - unsigned int cw_len; /* length of the decoded code word in bits */ - - (void)m; - - q = count_leading_ones(code_word); - ql = q + 1; /* Number of 1's + following 0 */ - - rl = log2_m; - - cw_len = rl + ql; - - if (cw_len > 32) /* can only decode code words with maximum 32 bits */ - return 0; - - code_word = code_word << ql; /* shift quotient code out */ - - /* Right shifting an integer by a number of bits equal orgreater than - * its size is undefined behavior - */ - if (rl == 0) - r = 0; - else - r = code_word >> (32 - rl); - - *decoded_cw = (q << log2_m) + r; - - return cw_len; -} - +/** + * @brief decompress short F_FX_NCOB data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ -static unsigned int Golomb_decoder(unsigned int code_word, unsigned int m, - unsigned int log2_m, unsigned int - *decoded_cw) +static int decompress_f_fx_ncob(const struct cmp_cfg *cfg) { - unsigned int q; /* quotient code */ - unsigned int r1; /* remainder code group 1 */ - unsigned int r2; /* remainder code group 2 */ - unsigned int r; /* remainder code */ - unsigned int rl; /* length of the remainder code */ - unsigned int cutoff; /* cutoff between group 1 and 2 */ - unsigned int cw_len; /* length of the decoded code word in bits */ - - q = count_leading_ones(code_word); + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_fx, setup_ncob; + struct f_fx_ncob *data_buf = cfg->input_buf; + struct f_fx_ncob *model_buf = cfg->model_buf; + struct f_fx_ncob *up_model_buf = NULL; + struct f_fx_ncob *next_model_p; + struct f_fx_ncob model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - rl = log2_m + 1; - code_word <<= (q+1); /* shift quotient code out */ + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.f_ncob, cfg)) + return -1; - r2 = code_word >> (32 - rl); - r1 = r2 >> 1; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_y = decoded_value; + + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + } - cutoff = (1UL << rl) - m; + if (i >= cfg->samples-1) + break; - if (r1 < cutoff) { - cw_len = q + rl; - r = r1; - } else { - cw_len = q + rl + 1; - r = r2 - cutoff; + model = next_model_p[i]; } - - if (cw_len > 32) - return 0; - - *decoded_cw = q*m + r; - return cw_len; + return stream_pos; } -typedef unsigned int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *); +/** + * @brief decompress short F_FX_NCOB_ECOB data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ -static decoder_ptr select_decoder(unsigned int golomb_par) +static int decompress_f_fx_efx_ncob_ecob(const struct cmp_cfg *cfg) { - if (!golomb_par) - return NULL; - - if (is_a_pow_of_2(golomb_par)) - return &Rice_decoder; - else - return &Golomb_decoder; -} - + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_fx, setup_ncob, setup_efx, setup_ecob; + struct f_fx_efx_ncob_ecob *data_buf = cfg->input_buf; + struct f_fx_efx_ncob_ecob *model_buf = cfg->model_buf; + struct f_fx_efx_ncob_ecob *up_model_buf = NULL; + struct f_fx_efx_ncob_ecob *next_model_p; + struct f_fx_efx_ncob_ecob model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } -static int decode_raw(const void *compressed_data, const struct cmp_info - *info, void *const decompressed_data) -{ - if (!info) + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.f_fx, cfg)) return -1; - if (info->samples_used == 0) - return 0; - if (!compressed_data) + if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.f_ncob, cfg)) return -1; - if (!decompressed_data) + if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.f_efx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->round, max_used_bits.f_ecob, cfg)) return -1; - if (info->samples_used*size_of_a_sample(info->cmp_mode_used)*CHAR_BIT - != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; - } - memcpy(decompressed_data, compressed_data, info->cmp_size/CHAR_BIT); + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_x, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_y, stream_pos, + &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_y = decoded_value; + + stream_pos = decode_value(&decoded_value, model.efx, stream_pos, + &setup_efx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].efx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ecob_x, stream_pos, + &setup_ecob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ecob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ecob_y, stream_pos, + &setup_ecob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ecob_y = decoded_value; + + if (up_model_buf) { + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y, + cfg->model_value, setup_ecob.lossy_par); + } - return 0; + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; + } + return stream_pos; } -static int decode_raw_16(const void *compressed_data, const struct cmp_info - *info, uint16_t *const decompressed_data) + +/** + * @brief decompress long normal light flux (L_FX) data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ + +static int decompress_l_fx(const struct cmp_cfg *cfg) { size_t i; - uint16_t *p = decompressed_data; - uint32_t read_pos = 0; - unsigned int read_bits; - uint32_t read_val; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_fx_var; + struct l_fx *data_buf = cfg->input_buf; + struct l_fx *model_buf = cfg->model_buf; + struct l_fx *up_model_buf = NULL; + struct l_fx *next_model_p; + struct l_fx model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!info) + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg)) return -1; - if (info->samples_used == 0) - return 0; - if (!compressed_data) + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg)) return -1; - if (!decompressed_data) + if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg)) return -1; - for (i = 0; i < info->samples_used; ++i) { - read_bits = get_n_bits32(&read_val, read_pos, 16, - compressed_data, info->cmp_size); - if (!read_bits) - return -1; - read_pos += 16; - p[i] =read_val; - } - return 0; -} - + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx_variance, stream_pos, + &setup_fx_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx_variance = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + } -static int decode_raw_S_FX(const void *compressed_data, const struct cmp_info - *info, struct S_FX *const decompressed_data) -{ - int err = decode_raw(compressed_data, info, decompressed_data); - if (err) - return err; + if (i >= cfg->samples-1) + break; -#if defined(LITTLE_ENDIAN) - { - size_t i; - for (i = 0; i < info->samples_used; i++) { - decompressed_data[i].FX = cpu_to_be32(decompressed_data[i].FX); - } + model = next_model_p[i]; } -#endif - return 0; + return stream_pos; } -static unsigned int decode_normal(const void *compressed_data, - const struct cmp_info *info, - unsigned int read_pos, - unsigned int max_cw_len, - uint32_t *const decoded_val) -{ - decoder_ptr decoder; - unsigned int n_read_bits; - uint32_t read_val; - unsigned int n_bits; - unsigned int read_bits; - unsigned int log2_g; - - if (!compressed_data) - return -1U; - - if (!info) - return -1U; - - if (!decoded_val) - return -1U; - - if (read_pos > info->cmp_size) - return -1U; - - if (max_cw_len > 32) - return -1U; - - if (max_cw_len == 0) - return read_pos; - - decoder = select_decoder(info->golomb_par_used); - if (!decoder) - return -1U; - - if (read_pos + max_cw_len > info->cmp_size) /* check buffer overflow */ - n_read_bits = info->cmp_size - read_pos; - else - n_read_bits = max_cw_len; - - read_bits = get_n_bits32(&read_val, read_pos, n_read_bits, - compressed_data, info->cmp_size); - if (!read_bits) - return -1U; - - read_val = read_val << (32 - n_read_bits); - - log2_g = ilog_2(info->golomb_par_used); - n_bits = decoder(read_val, info->golomb_par_used, log2_g, decoded_val); - - return read_pos + n_bits; -} +/** + * @brief decompress L_FX_EFX data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ -static unsigned int decode_zero(const void *compressed_data, - const struct cmp_info *info, - unsigned int read_pos, unsigned int max_cw_len, - uint32_t *const decoded_val) +static int decompress_l_fx_efx(const struct cmp_cfg *cfg) { - if (!info) - return -1U; - - if (info->samples_used == 0) - return read_pos; - - if (!compressed_data) - return -1U; - - if (!decoded_val) - return -1U; - - if (read_pos > info->cmp_size) - return -1U; - - if (max_cw_len > 32) - return -1U; - - if (max_cw_len == 0) - return read_pos; + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_efx, setup_fx_var; + struct l_fx_efx *data_buf = cfg->input_buf; + struct l_fx_efx *model_buf = cfg->model_buf; + struct l_fx_efx *up_model_buf = NULL; + struct l_fx_efx *next_model_p; + struct l_fx_efx model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - read_pos = decode_normal(compressed_data, info, read_pos, max_cw_len, - decoded_val); - if (read_pos == -1U) - return -1U; - if (*decoded_val >= info->spill_used) /* consistency check */ - return -1U; + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.l_efx, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg)) + return -1; - if (*decoded_val == 0) {/* escape symbol mechanism was used; read unencoded value */ - unsigned int n_bits; - uint32_t unencoded_val; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.efx, stream_pos, + &setup_efx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].efx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx_variance, stream_pos, + &setup_fx_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx_variance = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + } - n_bits = get_n_bits32(&unencoded_val, read_pos, max_cw_len, - compressed_data, info->cmp_size); - if (!n_bits) - return -1U; - if (unencoded_val < info->spill_used && unencoded_val != 0) /* consistency check */ - return -1U; + if (i >= cfg->samples-1) + break; - *decoded_val = unencoded_val; - read_pos += n_bits; + model = next_model_p[i]; } - return read_pos; + return stream_pos; } -static unsigned int decode_multi(const void *compressed_data, - const struct cmp_info *info, - unsigned int read_pos, unsigned int max_cw_len, - uint32_t *const decoded_val) -{ - if (!info) - return -1U; - - if (info->samples_used == 0) - return read_pos; - - if (!compressed_data) - return -1U; - - if (!decoded_val) - return -1U; - - if (read_pos > info->cmp_size) - return -1U; - - if (max_cw_len > 32) - return -1U; - - if (max_cw_len == 0) - return read_pos; - - read_pos = decode_normal(compressed_data, info, read_pos, max_cw_len, - decoded_val); - if (read_pos == -1U) - return -1U; +/** + * @brief decompress L_FX_NCOB data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ - if (*decoded_val >= info->spill_used) { - /* escape symbol mechanism was used; read unencoded value */ - unsigned int n_bits; - uint32_t unencoded_val; - unsigned int unencoded_len; +static int decompress_l_fx_ncob(const struct cmp_cfg *cfg) +{ + size_t i; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, + setup_fx_var, setup_cob_var; + struct l_fx_ncob *data_buf = cfg->input_buf; + struct l_fx_ncob *model_buf = cfg->model_buf; + struct l_fx_ncob *up_model_buf = NULL; + struct l_fx_ncob *next_model_p; + struct l_fx_ncob model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - unencoded_len = (*decoded_val - info->spill_used + 1) * 2; - if (unencoded_len > max_cw_len) /* consistency check */ - return -1U; + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.l_ncob, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg)) + return -1; + if (configure_decoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_cob_variance, cfg)) + return -1; - /* check buffer overflow */ - if ((read_pos + unencoded_len) > info->cmp_size) { - /*TODO: debug message */ - return -1U; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_x, + stream_pos, &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_y, + stream_pos, &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_y = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx_variance, + stream_pos, &setup_fx_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx_variance = decoded_value; + + stream_pos = decode_value(&decoded_value, model.cob_x_variance, + stream_pos, &setup_cob_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].cob_x_variance = decoded_value; + + stream_pos = decode_value(&decoded_value, model.cob_y_variance, + stream_pos, &setup_cob_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].cob_y_variance = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance, + cfg->model_value, setup_cob_var.lossy_par); + up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance, + cfg->model_value, setup_cob_var.lossy_par); } - n_bits = get_n_bits32(&unencoded_val, read_pos, unencoded_len, - compressed_data, info->cmp_size); - if (!n_bits) - return -1U; - *decoded_val = unencoded_val + info->spill_used; - read_pos += n_bits; + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } - return read_pos; + return stream_pos; } -static unsigned int decode_value(const void *compressed_data, - const struct cmp_info *info, - unsigned int read_pos, - unsigned int max_cw_len, uint32_t *decoded_val) -{ - if (multi_escape_mech_is_used(info->cmp_mode_used)) - return decode_multi(compressed_data, info, read_pos, max_cw_len, - decoded_val); - - if (zero_escape_mech_is_used(info->cmp_mode_used)) - return decode_zero(compressed_data, info, read_pos, max_cw_len, - decoded_val); - return -1U; -} - +/** + * @brief decompress L_FX_EFX_NCOB_ECOB data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ -static int decode_16(const void *compressed_data, const struct cmp_info *info, - uint16_t *decoded_data) +static int decompress_l_fx_efx_ncob_ecob(const struct cmp_cfg *cfg) { size_t i; - unsigned int read_pos = 0; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_exp_flags, setup_fx, setup_ncob, setup_efx, + setup_ecob, setup_fx_var, setup_cob_var; + struct l_fx_efx_ncob_ecob *data_buf = cfg->input_buf; + struct l_fx_efx_ncob_ecob *model_buf = cfg->model_buf; + struct l_fx_efx_ncob_ecob *up_model_buf = NULL; + struct l_fx_efx_ncob_ecob *next_model_p; + struct l_fx_efx_ncob_ecob model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!info) + if (configure_decoder_setup(&setup_exp_flags, cfg->cmp_par_exp_flags, cfg->spill_exp_flags, + cfg->round, max_used_bits.l_exp_flags, cfg)) return -1; - - if (info->samples_used == 0) - return 0; - - if (!decoded_data) + if (configure_decoder_setup(&setup_fx, cfg->cmp_par_fx, cfg->spill_fx, + cfg->round, max_used_bits.l_fx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.l_ncob, cfg)) + return -1; + if (configure_decoder_setup(&setup_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.l_efx, cfg)) + return -1; + if (configure_decoder_setup(&setup_ecob, cfg->cmp_par_ecob, cfg->spill_ecob, + cfg->round, max_used_bits.l_ecob, cfg)) + return -1; + if (configure_decoder_setup(&setup_fx_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_fx_variance, cfg)) + return -1; + if (configure_decoder_setup(&setup_cob_var, cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, + cfg->round, max_used_bits.l_cob_variance, cfg)) return -1; - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 16, - &decoded_val); - if (read_pos == -1U) { - debug_print("Error: Compressed values could not be decoded.\n"); - return -1; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.exp_flags, + stream_pos, &setup_exp_flags); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].exp_flags = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx, stream_pos, + &setup_fx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_x, + stream_pos, &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ncob_y, + stream_pos, &setup_ncob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ncob_y = decoded_value; + + stream_pos = decode_value(&decoded_value, model.efx, stream_pos, + &setup_efx); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].efx = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ecob_x, + stream_pos, &setup_ecob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ecob_x = decoded_value; + + stream_pos = decode_value(&decoded_value, model.ecob_y, + stream_pos, &setup_ecob); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].ecob_y = decoded_value; + + stream_pos = decode_value(&decoded_value, model.fx_variance, + stream_pos, &setup_fx_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].fx_variance = decoded_value; + + stream_pos = decode_value(&decoded_value, model.cob_x_variance, + stream_pos, &setup_cob_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].cob_x_variance = decoded_value; + + stream_pos = decode_value(&decoded_value, model.cob_y_variance, + stream_pos, &setup_cob_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].cob_y_variance = decoded_value; + + if (up_model_buf) { + up_model_buf[i].exp_flags = cmp_up_model(data_buf[i].exp_flags, model.exp_flags, + cfg->model_value, setup_exp_flags.lossy_par); + up_model_buf[i].fx = cmp_up_model(data_buf[i].fx, model.fx, + cfg->model_value, setup_fx.lossy_par); + up_model_buf[i].ncob_x = cmp_up_model(data_buf[i].ncob_x, model.ncob_x, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].ncob_y = cmp_up_model(data_buf[i].ncob_y, model.ncob_y, + cfg->model_value, setup_ncob.lossy_par); + up_model_buf[i].efx = cmp_up_model(data_buf[i].efx, model.efx, + cfg->model_value, setup_efx.lossy_par); + up_model_buf[i].ecob_x = cmp_up_model(data_buf[i].ecob_x, model.ecob_x, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].ecob_y = cmp_up_model(data_buf[i].ecob_y, model.ecob_y, + cfg->model_value, setup_ecob.lossy_par); + up_model_buf[i].fx_variance = cmp_up_model(data_buf[i].fx_variance, model.fx_variance, + cfg->model_value, setup_fx_var.lossy_par); + up_model_buf[i].cob_x_variance = cmp_up_model(data_buf[i].cob_x_variance, model.cob_x_variance, + cfg->model_value, setup_cob_var.lossy_par); + up_model_buf[i].cob_y_variance = cmp_up_model(data_buf[i].cob_y_variance, model.cob_y_variance, + cfg->model_value, setup_cob_var.lossy_par); } - if (decoded_val > UINT16_MAX) - return -1; - - decoded_data[i] = (uint16_t)decoded_val; - } + if (i >= cfg->samples-1) + break; - if (read_pos != info->cmp_size && - cmp_bit_to_4byte(read_pos) != cmp_bit_to_4byte(info->cmp_size)) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; + model = next_model_p[i]; } - return 0; + return stream_pos; } -static int decode_S_FX(const void *compressed_data, const struct cmp_info *info, - struct S_FX *decoded_data) +/** + * @brief decompress N-CAM offset data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ + +static int decompress_nc_offset(const struct cmp_cfg *cfg) { size_t i; - unsigned int read_pos = 0; - struct cmp_info info_exp_flag; - - info_exp_flag.golomb_par_used = GOLOMB_PAR_EXPOSURE_FLAGS; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_mean, setup_var; + struct nc_offset *data_buf = cfg->input_buf; + struct nc_offset *model_buf = cfg->model_buf; + struct nc_offset *up_model_buf = NULL; + struct nc_offset *next_model_p; + struct nc_offset model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!info) + if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean, + cfg->round, max_used_bits.nc_offset_mean, cfg)) return -1; - - if (info->samples_used == 0) - return 0; - - if (!decoded_data) + if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance, + cfg->round, max_used_bits.nc_offset_variance, cfg)) return -1; - info_exp_flag = *info; - - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; - - /* read_pos = decode_value(compressed_data, &info_exp_flag, read_pos, 8, */ - /* &decoded_val); */ - read_pos = decode_normal(compressed_data, &info_exp_flag, read_pos, 8, - &decoded_val); - if (read_pos == -1U) - return -1; - if (decoded_val > UINT8_MAX) - return -1; - decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.mean, stream_pos, + &setup_mean); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].mean = decoded_value; + + stream_pos = decode_value(&decoded_value, model.variance, stream_pos, + &setup_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].variance = decoded_value; + + if (up_model_buf) { + up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, + model.mean, cfg->model_value, setup_mean.lossy_par); + up_model_buf[i].variance = cmp_up_model(data_buf[i].variance, + model.variance, cfg->model_value, setup_var.lossy_par); + } - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].FX = decoded_val; - } + if (i >= cfg->samples-1) + break; - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression."); - return 1; + model = next_model_p[i]; } - return 0; + return stream_pos; } -static int decode_S_FX_EFX(const void *compressed_data, const struct cmp_info - *info, struct S_FX_EFX *decoded_data) +/** + * @brief decompress N-CAM background data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ + +static int decompress_nc_background(const struct cmp_cfg *cfg) { size_t i; - unsigned int read_pos = 0; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_mean, setup_var, setup_pix; + struct nc_background *data_buf = cfg->input_buf; + struct nc_background *model_buf = cfg->model_buf; + struct nc_background *up_model_buf = NULL; + struct nc_background *next_model_p; + struct nc_background model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!info) + if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean, + cfg->round, max_used_bits.nc_background_mean, cfg)) return -1; - - if (info->samples_used == 0) - return 0; - - if (!decoded_data) + if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance, + cfg->round, max_used_bits.nc_background_variance, cfg)) + return -1; + if (configure_decoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error, + cfg->round, max_used_bits.nc_background_outlier_pixels, cfg)) return -1; - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 8, - &decoded_val); - if (read_pos == -1U) - return -1; - if (decoded_val > UINT8_MAX) - return -1; - decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].FX = decoded_val; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.mean, stream_pos, + &setup_mean); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].mean = decoded_value; + + stream_pos = decode_value(&decoded_value, model.variance, stream_pos, + &setup_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].variance = decoded_value; + + stream_pos = decode_value(&decoded_value, model.outlier_pixels, stream_pos, + &setup_pix); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].outlier_pixels = decoded_value; + + if (up_model_buf) { + up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, + model.mean, cfg->model_value, setup_mean.lossy_par); + up_model_buf[i].variance = cmp_up_model(data_buf[i].variance, + model.variance, cfg->model_value, setup_var.lossy_par); + up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels, + model.outlier_pixels, cfg->model_value, setup_pix.lossy_par); + } - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].EFX = decoded_val; - } + if (i >= cfg->samples-1) + break; - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; + model = next_model_p[i]; } - return 0; + return stream_pos; } -static int decode_S_FX_NCOB(const void *compressed_data, const struct cmp_info - *info, struct S_FX_NCOB *decoded_data) +/** + * @brief decompress N-CAM smearing data + * + * @param cfg pointer to the compression configuration structure + * + * @returns bit position of the last read bit in the bitstream on success; + * returns negative on error, returns CMP_ERROR_SMALL_BUF if the bitstream + * buffer is too small to read the value from the bitstream + */ + +static int decompress_smearing(const struct cmp_cfg *cfg) { size_t i; - unsigned int read_pos = 0; + int stream_pos = 0; + uint32_t decoded_value; + struct decoder_setup setup_mean, setup_var, setup_pix; + struct smearing *data_buf = cfg->input_buf; + struct smearing *model_buf = cfg->model_buf; + struct smearing *up_model_buf = NULL; + struct smearing *next_model_p; + struct smearing model; + + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; + + stream_pos = decompress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); + + if (model_mode_is_used(cfg->cmp_mode)) { + model = model_buf[0]; + next_model_p = &model_buf[1]; + } else { + memset(&model, 0, sizeof(model)); + next_model_p = data_buf; + } - if (!info) + if (configure_decoder_setup(&setup_mean, cfg->cmp_par_mean, cfg->spill_mean, + cfg->round, max_used_bits.smearing_mean, cfg)) return -1; - - if (info->samples_used == 0) - return 0; - - if (!decoded_data) + if (configure_decoder_setup(&setup_var, cfg->cmp_par_variance, cfg->spill_variance, + cfg->round, max_used_bits.smearing_variance_mean, cfg)) + return -1; + if (configure_decoder_setup(&setup_pix, cfg->cmp_par_pixels_error, cfg->spill_pixels_error, + cfg->round, max_used_bits.smearing_outlier_pixels, cfg)) return -1; - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 8, - &decoded_val); - if (read_pos == -1U) - return -1; - if (decoded_val > UINT8_MAX) - return -1; - decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].FX = decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].NCOB_X = decoded_val; + for (i = 0; ; i++) { + stream_pos = decode_value(&decoded_value, model.mean, stream_pos, + &setup_mean); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].mean = decoded_value; + + stream_pos = decode_value(&decoded_value, model.variance_mean, stream_pos, + &setup_var); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].variance_mean = decoded_value; + + stream_pos = decode_value(&decoded_value, model.outlier_pixels, stream_pos, + &setup_pix); + if (stream_pos <= 0) + return stream_pos; + data_buf[i].outlier_pixels = decoded_value; + + if (up_model_buf) { + up_model_buf[i].mean = cmp_up_model(data_buf[i].mean, + model.mean, cfg->model_value, setup_mean.lossy_par); + up_model_buf[i].variance_mean = cmp_up_model(data_buf[i].variance_mean, + model.variance_mean, cfg->model_value, setup_var.lossy_par); + up_model_buf[i].outlier_pixels = cmp_up_model(data_buf[i].outlier_pixels, + model.outlier_pixels, cfg->model_value, setup_pix.lossy_par); + } - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].NCOB_Y = decoded_val; - } + if (i >= cfg->samples-1) + break; - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; + model = next_model_p[i]; } - return 0; + return stream_pos; } -static int decode_S_FX_EFX_NCOB_ECOB(const void *compressed_data, - const struct cmp_info *info, - struct S_FX_EFX_NCOB_ECOB *decoded_data) +/** + * @brief decompress the data based on a compression configuration + * + * @param cfg pointer to a compression configuration + * + * @note cfg->buffer_length is measured in bytes (instead of samples as by the + * compression) + * + * @returns the size of the decompressed data on success; returns negative on failure + */ + +static int decompressed_data_internal(struct cmp_cfg *cfg) { - size_t i; - unsigned int read_pos = 0; + int data_size, strem_len_bit = -1; - if (!info) + if (!cfg) return -1; - if (info->samples_used == 0) - return 0; - - if (!decoded_data) + if (!cfg->icu_output_buf) return -1; - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; + data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type); + if (!cfg->input_buf || !data_size) + return data_size; - read_pos = decode_value(compressed_data, info, read_pos, 8, - &decoded_val); - if (read_pos == -1U) + if (model_mode_is_used(cfg->cmp_mode)) + if (!cfg->model_buf) return -1; - if (decoded_val > UINT8_MAX) - return -1; - decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val; - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].FX = decoded_val; + if (cfg->cmp_mode == CMP_MODE_RAW) { - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) + if ((unsigned int)data_size < cfg->buffer_length/CHAR_BIT) return -1; - decoded_data[i].NCOB_X = decoded_val; - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].NCOB_Y = decoded_val; + if (cfg->input_buf) { + memcpy(cfg->input_buf, cfg->icu_output_buf, data_size); + if (cmp_input_big_to_cpu_endianness(cfg->input_buf, data_size, cfg->data_type)) + return -1; + strem_len_bit = data_size * CHAR_BIT; + } - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].EFX = decoded_val; + } else { + switch (cfg->data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + strem_len_bit = decompress_imagette(cfg); + break; + case DATA_TYPE_S_FX: + strem_len_bit = decompress_s_fx(cfg); + break; + case DATA_TYPE_S_FX_EFX: + strem_len_bit = decompress_s_fx_efx(cfg); + break; + case DATA_TYPE_S_FX_NCOB: + strem_len_bit = decompress_s_fx_ncob(cfg); + break; + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + strem_len_bit = decompress_s_fx_efx_ncob_ecob(cfg); + break; - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].ECOB_X = decoded_val; + case DATA_TYPE_F_FX: + strem_len_bit = decompress_f_fx(cfg); + break; + case DATA_TYPE_F_FX_EFX: + strem_len_bit = decompress_f_fx_efx(cfg); + break; + case DATA_TYPE_F_FX_NCOB: + strem_len_bit = decompress_f_fx_ncob(cfg); + break; + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + strem_len_bit = decompress_f_fx_efx_ncob_ecob(cfg); + break; - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].ECOB_Y = decoded_val; - } + case DATA_TYPE_L_FX: + strem_len_bit = decompress_l_fx(cfg); + break; + case DATA_TYPE_L_FX_EFX: + strem_len_bit = decompress_l_fx_efx(cfg); + break; + case DATA_TYPE_L_FX_NCOB: + strem_len_bit = decompress_l_fx_ncob(cfg); + break; + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + strem_len_bit = decompress_l_fx_efx_ncob_ecob(cfg); + break; - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression."); - return 1; + case DATA_TYPE_OFFSET: + strem_len_bit = decompress_nc_offset(cfg); + break; + case DATA_TYPE_BACKGROUND: + strem_len_bit = decompress_nc_background(cfg); + break; + case DATA_TYPE_SMEARING: + strem_len_bit = decompress_smearing(cfg); + break; + + case DATA_TYPE_F_CAM_OFFSET: + case DATA_TYPE_F_CAM_BACKGROUND: + case DATA_TYPE_UNKNOWN: + default: + strem_len_bit = -1; + debug_print("Error: Compressed data type not supported.\n"); + break; + } } - return 0; + if (strem_len_bit <= 0) + return -1; + + return data_size; } -static int decode_data(const void *compressed_data, const struct cmp_info *info, - void *decompressed_data) +/** + * @brief decompress a compression entity + * + * @param ent pointer to the compression entity to be decompressed + * @param model_of_data pointer to model data buffer (can be NULL if no + * model compression mode is used) + * @param updated_model pointer to store the updated model for the next model + * mode compression (can be the same as the model_of_data + * buffer for in-place update or NULL if updated model is not needed) + * @param decompressed_data pointer to the decompressed data buffer (can be NULL) + * + * @returns the size of the decompressed data on success; returns negative on failure + */ + +int decompress_cmp_entiy(struct cmp_entity *ent, void *model_of_data, + void *up_model_buf, void *decompressed_data) { - if (!info) - return -1; + int err; + struct cmp_cfg cfg = {0}; - if (info->samples_used == 0) - return 0; + cfg.model_buf = model_of_data; + cfg.icu_new_model_buf = up_model_buf; + cfg.input_buf = decompressed_data; - if (!compressed_data) + if (!ent) return -1; - if (!decompressed_data) - return -1; - - switch (info->cmp_mode_used) { - case MODE_RAW: - return decode_raw_16(compressed_data, info, decompressed_data); - break; - case MODE_MODEL_ZERO: - case MODE_DIFF_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_MULTI: - return decode_16(compressed_data, info, - (uint16_t *)decompressed_data); - break; - case MODE_RAW_S_FX: - return decode_raw_S_FX(compressed_data, info, decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return decode_S_FX(compressed_data, info, - (struct S_FX *)decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return decode_S_FX_EFX(compressed_data, info, - (struct S_FX_EFX *)decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return decode_S_FX_NCOB(compressed_data, info, - (struct S_FX_NCOB *)decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return decode_S_FX_EFX_NCOB_ECOB(compressed_data, info, - (struct S_FX_EFX_NCOB_ECOB *) - decompressed_data); - break; -#if 0 - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - break; -#endif - default: - debug_print("Error: Compression mode not supported.\n"); - break; + err = cmp_ent_read_header(ent, &cfg); + if (err) + return -1; - } - return -1; + return decompressed_data_internal(&cfg); } -/* model buffer is overwritten with updated model*/ -int decompress_data(const void *compressed_data, void *de_model_buf, const - struct cmp_info *info, void *decompressed_data) +/** + * @brief decompress RDCU compressed data without a compression entity header + * + * @param compressed_data pointer to the RDCU compressed data (without a + * compression entity header) + * @param model_of_data pointer to model data buffer (can be NULL if no + * model compression mode is used) + * @param updated_model pointer to store the updated model for the next model + * mode compression (can be the same as the model_of_data + * buffer for in-place update or NULL if updated model is not needed) + * @param decompressed_data pointer to the decompressed data buffer (can be NULL) + * + * @returns the size of the decompressed data on success; returns negative on failure + */ + +int decompress_rdcu_data(uint32_t *compressed_data, const struct cmp_info *info, + uint16_t *model_of_data, uint16_t *up_model_buf, + uint16_t *decompressed_data) + { - int err; + struct cmp_cfg cfg = {0}; if (!compressed_data) return -1; @@ -1527,26 +2201,19 @@ int decompress_data(const void *compressed_data, void *de_model_buf, const if (info->cmp_err) return -1; - if (model_mode_is_used(info->cmp_mode_used)) - if (!de_model_buf) - return -1; - /* TODO: add ohter modes */ - - if (!decompressed_data) - return -1; - - - err = decode_data(compressed_data, info, decompressed_data); - if (err) - return err; - - err = de_map_to_pos(decompressed_data, info); - if (err) - return err; - - err = de_pre_process(decompressed_data, de_model_buf, info); - if (err) - return err; - - return 0; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.model_buf = model_of_data; + cfg.icu_new_model_buf = up_model_buf; + cfg.input_buf = decompressed_data; + + cfg.cmp_mode = info->cmp_mode_used; + cfg.model_value = info->model_value_used; + cfg.round = info->round_used; + cfg.spill = info->spill_used; + cfg.golomb_par = info->golomb_par_used; + cfg.samples = info->samples_used; + cfg.icu_output_buf = compressed_data; + cfg.buffer_length = cmp_bit_to_4byte(info->cmp_size); + + return decompressed_data_internal(&cfg); } diff --git a/lib/meson.build b/lib/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..f072ce4371b24f303ac3f51a607735870fd216f2 --- /dev/null +++ b/lib/meson.build @@ -0,0 +1,22 @@ +cmplib_sources = files([ + 'cmp_data_types.c', + 'cmp_icu.c', + 'cmp_support.c', + 'rdcu_ctrl.c', + 'rmap.c', + 'cmp_entity.c', + 'cmp_io.c', + 'decmp.c', + 'rdcu_pkt_to_file.c', + 'cmp_guess.c', + 'cmp_rdcu.c', + 'rdcu_cmd.c', + 'rdcu_rmap.c' +]) + +cmp_lib = static_library('cmp_lib', + sources : cmplib_sources, + include_directories : incdir, + c_args : ['-DDEBUGLEVEL=1'], +# install : 'true' # linking under windows mingw only works if this is set +) diff --git a/lib/rdcu_ctrl.c b/lib/rdcu_ctrl.c index a1e3b0ffdf92197ebba433c04a4291b71c22df1a..6f743c68c09bc656bef11a941845d1d9cb7847ea 100644 --- a/lib/rdcu_ctrl.c +++ b/lib/rdcu_ctrl.c @@ -1305,44 +1305,97 @@ uint32_t rdcu_get_compr_data_start_addr(void) /** - * @brief get compressed data size + * @brief get the need bytes for the given bits + * + * @param cmp_size_bit compressed data size, measured in bits + * + * @returns the size in bytes to store the compressed data + */ + +static uint32_t rdcu_bit_to_byte(unsigned int cmp_size_bit) +{ + return ((cmp_size_bit + 7) / 8); +} + + +/** + * @brief get compressed data size in bits * @see RDCU-FRS-FN-0922 * * @returns the compressed data size in bits */ -uint32_t rdcu_get_compr_data_size(void) +uint32_t rdcu_get_compr_data_size_bit(void) { return rdcu->compr_data_size; } /** - * @brief get compressed data adaptive 1 size + * @brief get compressed data size in bytes + * @see RDCU-FRS-FN-0922 + * + * @returns the compressed data size in bytes + */ + +uint32_t rdcu_get_compr_data_size_byte(void) +{ + return rdcu_bit_to_byte(rdcu_get_compr_data_size_bit()); +} + + +/** + * @brief get compressed data adaptive 1 size in bits * @see RDCU-FRS-FN-0932 * * @returns the adaptive 1 compressed data size in bits */ -uint32_t rdcu_get_compr_data_adaptive_1_size(void) +uint32_t rdcu_get_compr_data_adaptive_1_size_bit(void) { return rdcu->compr_data_adaptive_1_size; } /** - * @brief get compressed data adaptive 2 size + * @brief get compressed data adaptive 1 size in bytes + * @see RDCU-FRS-FN-0932 + * + * @returns the adaptive 1 compressed data size in bytes + */ + +uint32_t rdcu_get_compr_data_adaptive_1_size_byte(void) +{ + return rdcu_bit_to_byte(rdcu_get_compr_data_adaptive_1_size_bit()); +} + + +/** + * @brief get compressed data adaptive 2 size in bits * @see RDCU-FRS-FN-0942 * * @returns the adaptive 2 compressed data size in bits */ -uint32_t rdcu_get_compr_data_adaptive_2_size(void) +uint32_t rdcu_get_compr_data_adaptive_2_size_bit(void) { return rdcu->compr_data_adaptive_2_size; } +/** + * @brief get compressed data adaptive 2 size in bytes + * @see RDCU-FRS-FN-0942 + * + * @returns the adaptive 2 compressed data size in bytes + */ + +uint32_t rdcu_get_compr_data_adaptive_2_size_byte(void) +{ + return rdcu_bit_to_byte(rdcu_get_compr_data_adaptive_2_size_bit()); +} + + /** * @brief get compression error code * @see RDCU-FRS-FN-0954 @@ -1606,7 +1659,7 @@ int rdcu_write_sram_16(uint16_t *buf, uint32_t addr, uint32_t size) { uint32_t i; - for (i = 0; i < size/sizeof(uint16_t); i++){ + for (i = 0; i < size/sizeof(uint16_t); i++) { uint16_t *sram_buf = (uint16_t *)&rdcu->sram[addr]; sram_buf[i] = cpu_to_be16(buf[i]); @@ -1652,9 +1705,9 @@ int rdcu_write_sram_32(uint32_t *buf, uint32_t addr, uint32_t size) { uint32_t i; - for (i = 0; i < size/sizeof(uint32_t); i++){ - uint32_t *sram_buf = (uint32_t *)&rdcu->sram[addr]; - + for (i = 0; i < size/sizeof(uint32_t); i++) { + uint32_t *sram_buf = (uint32_t *)&rdcu->sram[addr]; + sram_buf[i] = cpu_to_be32(buf[i]); } } @@ -2466,14 +2519,12 @@ int rdcu_sync_sram_mirror_parallel(uint32_t rx_addr, uint32_t rx_size, int rdcu_ctrl_init(void) { - rdcu = (struct rdcu_mirror *) malloc(sizeof(struct rdcu_mirror)); - if (!rdcu){ + rdcu = (struct rdcu_mirror *) calloc(1, sizeof(struct rdcu_mirror)); + if (!rdcu) { printf("Error allocating memory for the RDCU mirror\n"); return -1; } - memset(rdcu, 0, sizeof(struct rdcu_mirror)); - #if (__sparc__) rdcu->sram = (uint8_t *) 0x60000000; #else /* assume PC */ @@ -2485,7 +2536,7 @@ int rdcu_ctrl_init(void) } #endif - memset(rdcu->sram, 0, RDCU_SRAM_SIZE); - + memset(rdcu->sram, 0, RDCU_SRAM_SIZE); /* clear sram buffer */ + return 0; } diff --git a/lib/rdcu_pkt_to_file.c b/lib/rdcu_pkt_to_file.c index 83074d70141cdcbc9b3ae6f196b802215cfd46fc..9e80125f0335a9576dc56194c79479155a906368 100644 --- a/lib/rdcu_pkt_to_file.c +++ b/lib/rdcu_pkt_to_file.c @@ -17,7 +17,7 @@ * * This library provided a rmap_rx and rmap_tx function for the rdcu_rmap * library to write generated packets into text files. - * + * @warning this part of the software is not intended to run on-board on the ICU. */ #include <stdint.h> @@ -28,11 +28,11 @@ #include <errno.h> #include <sys/stat.h> -#include "../include/rdcu_pkt_to_file.h" -#include "../include/cmp_rdcu_extended.h" -#include "../include/rdcu_rmap.h" -#include "../include/rdcu_ctrl.h" -#include "../include/rdcu_cmd.h" +#include <rdcu_pkt_to_file.h> +#include <cmp_rdcu_extended.h> +#include <rdcu_rmap.h> +#include <rdcu_ctrl.h> +#include <rdcu_cmd.h> /* Name of directory were the RMAP packages are stored */ static char tc_folder_dir[MAX_TC_FOLDER_DIR_LEN] = "TC_FILES"; @@ -52,7 +52,6 @@ void set_tc_folder_dir(const char *dir_name) strncpy(tc_folder_dir, dir_name, sizeof(tc_folder_dir)); /* Ensure null-termination. */ tc_folder_dir[sizeof(tc_folder_dir) - 1] = '\0'; - return; } @@ -292,8 +291,7 @@ static int read_rdcu_pkt_mode_cfg(uint8_t *icu_addr, uint8_t *rdcu_addr, if (read_all < 0x7) return -1; - printf("Use ICU_ADDR = %#02X, RDCU_ADDR = %#02X and MTU = %d for the " - "RAMP packets.\n", *icu_addr, *rdcu_addr, *mtu); + printf("Use ICU_ADDR = %#02X, RDCU_ADDR = %#02X and MTU = %d for the RAMP packets.\n", *icu_addr, *rdcu_addr, *mtu); return 0; } @@ -313,8 +311,11 @@ int init_rmap_pkt_to_file(void) uint8_t icu_addr, rdcu_addr; int mtu; - if (read_rdcu_pkt_mode_cfg(&icu_addr, &rdcu_addr, &mtu)) - return -1; + if (read_rdcu_pkt_mode_cfg(&icu_addr, &rdcu_addr, &mtu)) { + icu_addr = DEF_ICU_ADDR; + rdcu_addr = DEF_RDCU_ADDR; + mtu = DEF_MTU; + } rdcu_ctrl_init(); rdcu_set_source_logical_address(icu_addr); rdcu_set_destination_logical_address(rdcu_addr); @@ -325,7 +326,7 @@ int init_rmap_pkt_to_file(void) /** - * @brief generate the rmap packets to set up a RDCU compression + * @brief generate the rmap packets to set up an RDCU compression * @note note that the initialization function init_rmap_pkt_to_file() must be * executed before * @note the configuration of the ICU_ADDR, RDCU_ADDR, MTU settings are in the @@ -365,7 +366,7 @@ int gen_write_rdcu_pkts(const struct cmp_cfg *cfg) /** - * @brief generate the rmap packets to read the result of a RDCU compression + * @brief generate the rmap packets to read the result of an RDCU compression * @note note that the initialization function init_rmap_pkt_to_file() must be * executed before * @note the configuration of the ICU_ADDR, RDCU_ADDR, MTU settings are in the @@ -436,7 +437,7 @@ int gen_read_rdcu_pkts(const struct cmp_info *info) /** - * @brief generate the rmap packets to set up a RDCU compression, read the + * @brief generate the rmap packets to set up an RDCU compression, read the * bitstream and the updated model in parallel to write the data to compressed * and the model and start the compression * @note the compressed data are read from cfg->rdcu_buffer_adr with the length diff --git a/lib/rdcu_rmap.c b/lib/rdcu_rmap.c index f6035cb519815fc287e234dde2039d7c850088df..e4ec4b61952db0049c37d36914d5216c69c6aecf 100644 --- a/lib/rdcu_rmap.c +++ b/lib/rdcu_rmap.c @@ -70,7 +70,7 @@ #include <rmap.h> #include <rdcu_rmap.h> - +#define RDCU_CONFIG_DEBUG 0 static uint8_t rdcu_addr; static uint8_t icu_addr; @@ -116,8 +116,8 @@ static size_t data_mtu; /* maximum data transfer size per unit */ * Every time a slot is retrieved, the "pending" counter is incremented to * have a fast indicator of the synchronisation status, i.e. if "pending" * is not set, the synchronisation procedure is complete and the local data may - * be read, or the remote data has been written and further commands may may - * be issued. + * be read, or the remote data has been written and further commands may be + * issued. * * The local (mirror) start address of the requested remote address is stored * into the same slot in the "local_addr" array, so we'll know where to put the @@ -261,7 +261,7 @@ static int rdcu_process_rx(void) cnt++; - if ((0)) + if (RDCU_CONFIG_DEBUG) rmap_parse_pkt(spw_pckt); /* convert format */ @@ -276,25 +276,20 @@ static int rdcu_process_rx(void) local_addr = trans_log_get_addr(rp->tr_id); if (!local_addr) { - printf("warning: response packet received not in " - "transaction log\n"); + printf("Warning: response packet received not in transaction log\n"); rmap_erase_packet(rp); continue; } - if (rp->data_len & 0x3) { - printf("Error: response packet data size is not a " - "multiple of 4, transaction dropped\n"); + printf("Error: response packet data size is not a multiple of 4, transaction dropped\n"); trans_log_release_slot(rp->tr_id); rmap_erase_packet(rp); return -1; } - if (rp->data_len) { - uint8_t crc8; /* convert endianess if needed */ @@ -308,13 +303,9 @@ static int rdcu_process_rx(void) } #endif /* __BYTE_ORDER__ */ - crc8 = rmap_crc8(rp->data, rp->data_len); - if (crc8 != rp->data_crc) { - - printf("Error: data CRC8 mismatch, data invalid or " - "packet truncated. Transaction dropped\n"); + printf("Error: data CRC8 mismatch, data invalid or packet truncated. Transaction dropped\n"); trans_log_release_slot(rp->tr_id); rmap_erase_packet(rp); @@ -353,7 +344,7 @@ int rdcu_submit_tx(const uint8_t *cmd, int cmd_size, if (!rmap_tx) return -1; - if ((0)) + if (RDCU_CONFIG_DEBUG) printf("Transmitting RMAP command\n"); if (rmap_tx(cmd, cmd_size, dpath_len, data, data_size)) { @@ -413,7 +404,7 @@ int rdcu_gen_cmd(uint16_t trans_id, uint8_t *cmd, return n; } - memset(cmd, 0, n); + memset(cmd, 0, n); /* clear command buffer */ n = rmap_build_hdr(pkt, cmd); @@ -476,8 +467,7 @@ int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd), /* convert endianess if needed */ #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - if (data_len) - { + if (data_len) { int i; uint32_t *tmp_buf = alloca(data_len); uint32_t *p = (uint32_t *) addr; @@ -500,7 +490,7 @@ int rdcu_sync(int (*fn)(uint16_t trans_id, uint8_t *cmd), /** * @brief submit a data sync command * - * @param fn a RDCU data transfer generation function + * @param fn an RDCU data transfer generation function * @param addr the remote address * @param data the local data address * @param data_len the length of the data payload @@ -530,7 +520,7 @@ int rdcu_sync_data(int (*fn)(uint16_t trans_id, uint8_t *cmd, slot = trans_log_grab_slot(data); if (slot < 0) { - if ((0)) + if (RDCU_CONFIG_DEBUG) printf("Error: all slots busy!\n"); return 1; } @@ -782,7 +772,7 @@ int rdcu_rmap_sync_status(void) void rdcu_rmap_reset_log(void) { - memset(trans_log.in_use, 0, TRANS_LOG_SIZE); + memset(trans_log.in_use, 0, sizeof(trans_log.in_use)); /* clear in_use buffer */ trans_log.pending = 0; } diff --git a/lib/rmap.c b/lib/rmap.c index f8b6eb0c4a38226bc4f5cd270332033b97e1eb6f..703add595bb907340be3399759178229afa6db89 100644 --- a/lib/rmap.c +++ b/lib/rmap.c @@ -178,7 +178,7 @@ struct rmap_pkt *rmap_create_packet(void) struct rmap_pkt *pkt; - pkt = (struct rmap_pkt *) calloc(sizeof(struct rmap_pkt), 1); + pkt = (struct rmap_pkt *) calloc(1, sizeof(struct rmap_pkt)); if (pkt) pkt->proto_id = RMAP_PROTOCOL_ID; @@ -206,7 +206,7 @@ void rmap_destroy_packet(struct rmap_pkt *pkt) * @param pkt a struct rmap_pkt * * @note this will attempt to deallocate any pointer references assigned by the - * user + * user * @warning use with care */ @@ -563,7 +563,7 @@ struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len) pkt->src = buf[RMAP_SRC_ADDR + n]; pkt->tr_id = ((uint16_t) buf[RMAP_TRANS_ID_BYTE0 + n] << 8) | - (uint16_t) buf[RMAP_TRANS_ID_BYTE1 + n]; + (uint16_t) buf[RMAP_TRANS_ID_BYTE1 + n]; /* commands have a data address */ if (pkt->ri.cmd_resp) { @@ -576,10 +576,9 @@ struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len) /* all headers have data length unless they are a write reply */ if (!(!pkt->ri.cmd_resp && (pkt->ri.cmd & (RMAP_CMD_BIT_WRITE)))) { - pkt->data_len = ((uint32_t) buf[RMAP_DATALEN_BYTE0 + n] << 16) | ((uint32_t) buf[RMAP_DATALEN_BYTE1 + n] << 8) | - (uint32_t) buf[RMAP_DATALEN_BYTE2 + n]; + (uint32_t) buf[RMAP_DATALEN_BYTE2 + n]; } pkt->hdr_crc = buf[RMAP_HEADER_CRC]; @@ -587,7 +586,7 @@ struct rmap_pkt *rmap_pkt_from_buffer(uint8_t *buf, uint32_t len) if (pkt->data_len) { if (len < RMAP_DATA_START + n + pkt->data_len + 1) { /* +1 for data CRC */ printf("buffer len is smaller than the contained RMAP packet; buf len: %u bytes vs RMAP: %zu bytes needed\n", - len , RMAP_DATA_START + n + pkt->data_len); + len, RMAP_DATA_START + n + pkt->data_len); goto error; } if (len > RMAP_DATA_START + n + pkt->data_len + 1) /* +1 for data CRC */ @@ -702,7 +701,7 @@ static void rmap_process_read_reply(uint8_t *pkt) for (i = 0; i < len; i++) printf("%02x:", pkt[RMAP_DATA_START + i]); - printf("\b \n"); + printf("\b\n"); } diff --git a/meson.build b/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..53603eebf0b0e1af1fb963b45023abc37659c990 --- /dev/null +++ b/meson.build @@ -0,0 +1,31 @@ +project('cmp_tool', 'c', + version : '0.09', + meson_version : '>= 0.56', + license : 'GPL-2.0', + default_options : ['warning_level=3', 'c_std=gnu99'] +) + +add_project_arguments('-DDEBUGLEVEL=1', language : 'c') + +if (host_machine.system() == 'windows' or host_machine.system() == 'cygwin') and meson.get_compiler('c').get_id() == 'gcc' + # by default, MinGW on win32 behaves as if it ignores __attribute__((packed)), + # you need to add -mno-ms-bitfields to make it work as expected. + # See: https://wintermade.it/blog/posts/__attribute__packed-on-windows-is-ignored-with-mingw.html + add_project_arguments('-mno-ms-bitfields', language : 'c') + add_global_link_arguments('-static', language: 'c') +endif + +subdir('include') +subdir('lib') + +main = files('cmp_tool.c') + +cmp_tool_exe = executable('cmp_tool', + sources : main, + include_directories : incdir, + link_with : cmp_lib, + install : 'true' +) + +subdir('test') +subdir('doc/doxygen') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000000000000000000000000000000000000..fe8670ef9356c298fd3cc2fe813aeca7165d35f5 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,2 @@ +option('argument_input_mode', type : 'boolean', value : false, + description : 'If set, the data file is set with the first argument and the model file with the second one') diff --git a/mingw-w64-64.txt b/mingw-w64-64.txt new file mode 100644 index 0000000000000000000000000000000000000000..773be92376afa65261c519bae973fca17e8e3cc9 --- /dev/null +++ b/mingw-w64-64.txt @@ -0,0 +1,24 @@ +[binaries] +c = 'x86_64-w64-mingw32-gcc' +cpp = 'x86_64-w64-mingw32-g++' +objc = 'x86_64-w64-mingw32-gcc' +ar = 'x86_64-w64-mingw32-ar' +strip = 'x86_64-w64-mingw32-strip' +pkgconfig = 'x86_64-w64-mingw32-pkg-config' +windres = 'x86_64-w64-mingw32-windres' +exe_wrapper = 'wine64' +cmake = 'cmake' + +[host_machine] +system = 'windows' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[cmake] + +CMAKE_BUILD_WITH_INSTALL_RPATH = 'ON' +CMAKE_FIND_ROOT_PATH_MODE_PROGRAM = 'NEVER' +CMAKE_FIND_ROOT_PATH_MODE_LIBRARY = 'ONLY' +CMAKE_FIND_ROOT_PATH_MODE_INCLUDE = 'ONLY' +CMAKE_FIND_ROOT_PATH_MODE_PACKAGE = 'ONLY' diff --git a/subprojects/unity.wrap b/subprojects/unity.wrap new file mode 100644 index 0000000000000000000000000000000000000000..8cc488366197ec4f255d93fb4642367c88f5744b --- /dev/null +++ b/subprojects/unity.wrap @@ -0,0 +1,8 @@ +[wrap-file] +directory = Unity-2.5.2 +source_url = https://github.com/ThrowTheSwitch/Unity/archive/refs/tags/v2.5.2.tar.gz +source_filename = Unity-2.5.2.tar.gz +source_hash = 3786de6c8f389be3894feae4f7d8680a02e70ed4dbcce36109c8f8646da2671a + +[provide] +unity = unity_dep diff --git a/test/cmp_data_types/meson.build b/test/cmp_data_types/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..8de2ef86510c269ed1c3888c806c0a630133ec1c --- /dev/null +++ b/test/cmp_data_types/meson.build @@ -0,0 +1,12 @@ +test_case = files('test_cmp_data_types.c') +test_runner = test_runner_generator.process(test_case) + +test_cmp_icu = executable('test_cmp_data_types', + test_case, test_runner, + include_directories : incdir, + link_with : cmp_lib, + dependencies : unity_dep, + build_by_default : false +) + +test('Compression Data Types Unit Tests', test_cmp_icu) diff --git a/test/cmp_data_types/test_cmp_data_types.c b/test/cmp_data_types/test_cmp_data_types.c new file mode 100644 index 0000000000000000000000000000000000000000..881f46a250f904a1fab14a685b7c2b315fc5553b --- /dev/null +++ b/test/cmp_data_types/test_cmp_data_types.c @@ -0,0 +1,26 @@ +#include <stdint.h> + +#include "unity.h" +#include "cmp_data_types.h" + +/** + * @test cmp_cal_size_of_data + */ + +void test_cmp_cal_size_of_data(void) +{ + unsigned int s; + + s = cmp_cal_size_of_data(1, DATA_TYPE_IMAGETTE); + TEST_ASSERT_EQUAL_UINT(sizeof(uint16_t), s); + + s = cmp_cal_size_of_data(1, DATA_TYPE_F_FX); + TEST_ASSERT_EQUAL_UINT(sizeof(struct f_fx)+MULTI_ENTRY_HDR_SIZE, s); + + /* overflow tests */ + s = cmp_cal_size_of_data(0x1999999A, DATA_TYPE_BACKGROUND); + TEST_ASSERT_EQUAL_UINT(0, s); + s = cmp_cal_size_of_data(0x19999999, DATA_TYPE_BACKGROUND); + TEST_ASSERT_EQUAL_UINT(0, s); +} + diff --git a/test/cmp_entity/meson.build b/test/cmp_entity/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..72219124fb502125bbe9482379c81097b9c148b5 --- /dev/null +++ b/test/cmp_entity/meson.build @@ -0,0 +1,12 @@ +test_case = files('test_cmp_entity.c') +test_runner = test_runner_generator.process(test_case) + +test_cmp_entity = executable('test_cmp_data_types', + test_case, test_runner, + include_directories : incdir, + link_with : cmp_lib, + dependencies : unity_dep, + build_by_default : false +) + +test('Compression Entity Unit Tests', test_cmp_entity) diff --git a/test/cmp_entity/test_cmp_entity.c b/test/cmp_entity/test_cmp_entity.c new file mode 100644 index 0000000000000000000000000000000000000000..8493e329333bf928bfe0a0dfd1ad666a28291d11 --- /dev/null +++ b/test/cmp_entity/test_cmp_entity.c @@ -0,0 +1,51 @@ +#include <unity.h> + +#include <cmp_entity.h> +#include <cmp_io.h> + +void test_cmp_ent_get_data_buf(void) +{ + enum cmp_data_type data_type;/*TODO: implement: DATA_TYPE_F_CAM_OFFSET, DATA_TYPE_F_CAM_BACKGROUND */ + struct cmp_entity ent = {0}; + char *adr; + uint32_t s, hdr_size; + + for (data_type = DATA_TYPE_IMAGETTE; + data_type <=DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE; + data_type++) { + s = cmp_ent_create(&ent, data_type, 0, 0); + TEST_ASSERT_NOT_EQUAL_INT(0, s); + + adr = cmp_ent_get_data_buf(&ent); + TEST_ASSERT_NOT_NULL(adr); + + hdr_size = cmp_ent_cal_hdr_size(data_type, 0); + TEST_ASSERT_EQUAL_INT(hdr_size, adr-(char *)&ent); + } + + /* RAW mode test */ + for (data_type = DATA_TYPE_IMAGETTE; + data_type <=DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE; + data_type++) { + s = cmp_ent_create(&ent, data_type, 1, 0); + TEST_ASSERT_NOT_EQUAL_INT(0, s); + + adr = cmp_ent_get_data_buf(&ent); + TEST_ASSERT_NOT_NULL(adr); + + hdr_size = cmp_ent_cal_hdr_size(data_type, 1); + TEST_ASSERT_EQUAL_INT(hdr_size, adr-(char *)&ent); + } + + /* ent = NULL test */ + adr = cmp_ent_get_data_buf(NULL); + TEST_ASSERT_NULL(adr); + + /* compression data type not supported test */ + s = cmp_ent_set_data_type(&ent, DATA_TYPE_UNKNOWN, 0); + TEST_ASSERT_FALSE(s); + + adr = cmp_ent_get_data_buf(&ent); + TEST_ASSERT_NULL(adr); +} + diff --git a/test/cmp_icu/meson.build b/test/cmp_icu/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..7c9b356ed371262c44ba3ef897861ee4c7d25cd2 --- /dev/null +++ b/test/cmp_icu/meson.build @@ -0,0 +1,40 @@ +test_case = files('test_cmp_icu.c') +test_runner = test_runner_generator.process(test_case) + +test_cmp_icu = executable('test_cmp_icu', + test_case, test_runner, + include_directories : incdir, + link_with : cmp_lib, + dependencies : unity_dep, + build_by_default : false +) + +test('cmp_icu Unit Tests', test_cmp_icu) + + +test_case = files('test_cmp_decmp.c') +test_runner = test_runner_generator.process(test_case) + +test_cmp_decmp = executable('test_cmp_decmp', + test_case, test_runner, + include_directories : incdir, + link_with : cmp_lib, + dependencies : unity_dep, + build_by_default : false +) + +test('Compression Decompression Unit Tests', test_cmp_decmp) + + +test_case = files('test_decmp.c') +test_runner = test_runner_generator.process(test_case) + +test_decmp = executable('test_decmp', + test_case, test_runner, + include_directories : incdir, + link_with : cmp_lib, + dependencies : unity_dep, + build_by_default : false +) + +test('Decompression Unit Tests', test_decmp) diff --git a/test/cmp_icu/test_cmp_decmp.c b/test/cmp_icu/test_cmp_decmp.c new file mode 100644 index 0000000000000000000000000000000000000000..9eb587e96c8a34379ac56e8bb5a452ef8a891fe4 --- /dev/null +++ b/test/cmp_icu/test_cmp_decmp.c @@ -0,0 +1,663 @@ +/** + * @file test_cmp_decmp.c + * @author Dominik Loidolt (dominik.loidolt@univie.ac.at), + * @date 2022 + * + * @copyright GPLv2 + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * @brief random compression decompression test + * @detail We generate random data and compress them with random parameters. + * After that we put the data in a compression entity. We decompress the + * compression entity and compare the decompressed data with the original + * data. + */ + + +#include <string.h> +#include <stdlib.h> + +#include <unity.h> + +#include <cmp_icu.h> +#include <decmp.h> +#include <cmp_data_types.h> + +#if defined __has_include +# if __has_include(<time.h>) +# include <time.h> +# include <unistd.h> +# define HAS_TIME_H 1 +# endif +#endif + +#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12)) +#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX) + +#define set_n_bits(n) (n!=32?~(~0UL << (n)):0xFFFFFFFF) + + +/** + * @brief Seeds the pseudo-random number generator used by rand() + */ + +void setUp(void) +{ + unsigned int seed; + static int n; + +#if HAS_TIME_H + seed = time(NULL) * getpid(); +#else + seed = 1; +#endif + + if (!n) { + n = 1; + srand(seed); + printf("seed: %u\n", seed); + } +} + + +/** + * @brief generate a uint32_t random number + * + * @return a "random" uint32_t value + * @see https://stackoverflow.com/a/33021408 + */ + +uint32_t rand32(void) +{ + int i; + uint32_t r = 0; + + for (i = 0; i < 32; i += RAND_MAX_WIDTH) { + r <<= RAND_MAX_WIDTH; + r ^= (unsigned int) rand(); + } + return r; +} + + +/** + * @brief generate a random number in a range + * + * @param min minimum value (inclusive) + * @param max maximum value (inclusive) + * + * @returns "random" numbers in the range [min, max] + * + * @see https://c-faq.com/lib/randrange.html + */ + +uint32_t random_between(unsigned int min, unsigned int max) +{ + TEST_ASSERT(min < max); + if (max-min < RAND_MAX) + return min + rand() / (RAND_MAX / (max - min + 1ULL) + 1); + else + return min + rand32() / (UINT32_MAX / (max - min + 1ULL) + 1); +} + + +static void gen_ima_data(uint16_t *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i] = random_between(0, set_n_bits(max_used_bits.nc_imagette)); + } +} + + +static void gen_offset_data(struct nc_offset *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].mean = random_between(0, set_n_bits(max_used_bits.nc_offset_mean)); + data[i].variance = random_between(0, set_n_bits(max_used_bits.nc_offset_variance)); + } +} + + +static void gen_background_data(struct nc_background *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].mean = random_between(0, set_n_bits(max_used_bits.nc_background_mean)); + data[i].variance = random_between(0, set_n_bits(max_used_bits.nc_background_variance)); + data[i].outlier_pixels = random_between(0, set_n_bits(max_used_bits.nc_background_outlier_pixels)); + } +} + + +static void gen_smearing_data(struct smearing *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].mean = random_between(0, set_n_bits(max_used_bits.smearing_mean)); + data[i].variance_mean = random_between(0, set_n_bits(max_used_bits.smearing_variance_mean)); + data[i].outlier_pixels = random_between(0, set_n_bits(max_used_bits.smearing_outlier_pixels)); + } +} + + +static void gen_s_fx_data(struct s_fx *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx)); + } +} + + +static void gen_s_fx_efx_data(struct s_fx_efx *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx)); + data[i].efx = random_between(0, set_n_bits(max_used_bits.s_efx)); + } +} + + +static void gen_s_fx_ncob_data(struct s_fx_ncob *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx)); + data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.s_ncob)); + data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.s_ncob)); + } +} + + +static void gen_s_fx_efx_ncob_ecob_data(struct s_fx_efx_ncob_ecob *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx)); + data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.s_ncob)); + data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.s_ncob)); + data[i].efx = random_between(0, set_n_bits(max_used_bits.s_efx)); + data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.s_ecob)); + data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.s_ecob)); + } +} + + +static void gen_f_fx_data(struct f_fx *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx)); + } +} + + +static void gen_f_fx_efx_data(struct f_fx_efx *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx)); + data[i].efx = random_between(0, set_n_bits(max_used_bits.f_efx)); + } +} + + +static void gen_f_fx_ncob_data(struct f_fx_ncob *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx)); + data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.f_ncob)); + data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.f_ncob)); + } +} + + +static void gen_f_fx_efx_ncob_ecob_data(struct f_fx_efx_ncob_ecob *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx)); + data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.f_ncob)); + data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.f_ncob)); + data[i].efx = random_between(0, set_n_bits(max_used_bits.f_efx)); + data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.f_ecob)); + data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.f_ecob)); + } +} + + +static void gen_l_fx_data(struct l_fx *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx)); + data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance)); + } +} + + +static void gen_l_fx_efx_data(struct l_fx_efx *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx)); + data[i].efx = random_between(0, set_n_bits(max_used_bits.l_efx)); + data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance)); + } +} + + +static void gen_l_fx_ncob_data(struct l_fx_ncob *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx)); + data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.l_ncob)); + data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.l_ncob)); + data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance)); + data[i].cob_x_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance)); + data[i].cob_y_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance)); + } +} + + +static void gen_l_fx_efx_ncob_ecob_data(struct l_fx_efx_ncob_ecob *data, uint32_t samples) +{ + uint32_t i; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + for (i = 0; i < samples; i++) { + data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags)); + data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx)); + data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.l_ncob)); + data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.l_ncob)); + data[i].efx = random_between(0, set_n_bits(max_used_bits.l_efx)); + data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.l_ecob)); + data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.l_ecob)); + data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance)); + data[i].cob_x_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance)); + data[i].cob_y_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance)); + } +} + + +/** + * @brief generate random test data + * + * @param samples number of random test samples + * @param data_type compression data type of the test data + * + * @returns a pointer to the generated random test data + */ + +void *generate_random_test_data(uint32_t samples, enum cmp_data_type data_type) +{ + size_t data_size = cmp_cal_size_of_data(samples, data_type); + void *data = malloc(data_size); + void *data_cpy = data; + uint8_t *p = data; + + TEST_ASSERT_NOT_EQUAL_INT(data_size, 0); + TEST_ASSERT(data_size < (CMP_ENTITY_MAX_SIZE - NON_IMAGETTE_HEADER_SIZE)); + TEST_ASSERT_NOT_NULL(data); + + if (!rdcu_supported_data_type_is_used(data_type)) { + int i; + TEST_ASSERT(data_size > MULTI_ENTRY_HDR_SIZE); + for (i = 0; i < MULTI_ENTRY_HDR_SIZE; ++i) { + *p++ = random_between(0, UINT8_MAX); + } + data = p; + } + + switch (data_type) { + case DATA_TYPE_IMAGETTE: + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: + gen_ima_data(data, samples); + break; + case DATA_TYPE_OFFSET: + gen_offset_data(data, samples); + break; + case DATA_TYPE_BACKGROUND: + gen_background_data(data, samples); + break; + case DATA_TYPE_SMEARING: + gen_smearing_data(data, samples); + break; + case DATA_TYPE_S_FX: + gen_s_fx_data(data, samples); + break; + case DATA_TYPE_S_FX_EFX: + gen_s_fx_efx_data(data, samples); + break; + case DATA_TYPE_S_FX_NCOB: + gen_s_fx_ncob_data(data, samples); + break; + case DATA_TYPE_S_FX_EFX_NCOB_ECOB: + gen_s_fx_efx_ncob_ecob_data(data, samples); + break; + case DATA_TYPE_L_FX: + gen_l_fx_data(data, samples); + break; + case DATA_TYPE_L_FX_EFX: + gen_l_fx_efx_data(data, samples); + break; + case DATA_TYPE_L_FX_NCOB: + gen_l_fx_ncob_data(data, samples); + break; + case DATA_TYPE_L_FX_EFX_NCOB_ECOB: + gen_l_fx_efx_ncob_ecob_data(data, samples); + break; + case DATA_TYPE_F_FX: + gen_f_fx_data(data, samples); + break; + case DATA_TYPE_F_FX_EFX: + gen_f_fx_efx_data(data, samples); + break; + case DATA_TYPE_F_FX_NCOB: + gen_f_fx_ncob_data(data, samples); + break; + case DATA_TYPE_F_FX_EFX_NCOB_ECOB: + gen_f_fx_efx_ncob_ecob_data(data, samples); + break; + case DATA_TYPE_F_CAM_OFFSET: /* TODO: implement this */ + case DATA_TYPE_F_CAM_BACKGROUND: /* TODO: implement this */ + default: + TEST_FAIL(); + } + + return data_cpy; +} + + +/** + * @brief generate random compression configuration + * + * @param cfg pointer to a compression configuration + * + */ + +void generate_random_cmp_par(struct cmp_cfg *cfg) +{ + cfg->golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg->ap1_golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg->ap2_golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + + cfg->cmp_par_exp_flags = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_fx = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_ncob = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_efx = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_ecob = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_fx_cob_variance = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_mean = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_variance = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg->cmp_par_pixels_error = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + + + cfg->spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->golomb_par)); + cfg->ap1_spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap1_golomb_par)); + cfg->ap2_spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap2_golomb_par)); + + cfg->spill_exp_flags = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_exp_flags)); + cfg->spill_fx = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx)); + cfg->spill_ncob = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_ncob)); + cfg->spill_efx = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_efx)); + cfg->spill_ecob = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_ecob)); + cfg->spill_fx_cob_variance = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx_cob_variance)); + cfg->spill_mean = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_mean)); + cfg->spill_variance = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_variance)); + cfg->spill_pixels_error = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_pixels_error)); +#if 0 + if (cfg->cmp_mode == CMP_MODE_STUFF) { + /* cfg->golomb_par = random_between(16, MAX_STUFF_CMP_PAR); */ + cfg->golomb_par = 16; + cfg->ap1_golomb_par = random_between(0, MAX_STUFF_CMP_PAR); + cfg->ap2_golomb_par = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_exp_flags = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_fx = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_ncob = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_efx = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_ecob = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_fx_cob_variance = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_mean = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_variance = random_between(0, MAX_STUFF_CMP_PAR); + cfg->cmp_par_pixels_error = random_between(0, MAX_STUFF_CMP_PAR); + return; + } +#endif +} + + +/** + * @brief compress the given configuration and decompress it afterwards; finally + * compare the results + * + * @param cfg pointer to a compression configuration + */ + +void compression_decompression(struct cmp_cfg *cfg) +{ + int cmp_size_bits, s, error; + int data_size, cmp_data_size; + struct cmp_entity *ent; + void *decompressed_data; + static void *model_of_data; + void *updated_model = NULL; + + TEST_ASSERT_NOT_NULL(cfg); + + TEST_ASSERT_NULL(cfg->icu_output_buf); + + data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type); + + /* create a compression entity */ + cmp_data_size = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type); + cmp_data_size &= ~0x3; /* the size of the compressed data should be a multiple of 4 */ + TEST_ASSERT_NOT_EQUAL_INT(0, cmp_data_size); + + s = cmp_ent_create(NULL, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size); + TEST_ASSERT_NOT_EQUAL_INT(0, s); + ent = malloc(s); TEST_ASSERT_TRUE(ent); + s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size); + TEST_ASSERT_NOT_EQUAL_INT(0, s); + + /* we put the coompressed data direct into the compression entity */ + cfg->icu_output_buf = cmp_ent_get_data_buf(ent); + TEST_ASSERT_NOT_NULL(cfg->icu_output_buf); + + /* now compress the data */ + cmp_size_bits = icu_compress_data(cfg); + TEST_ASSERT(cmp_size_bits > 0); + + /* put the compression parameters in the entity header */ + error = cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits); + TEST_ASSERT_FALSE(error); + + /* allocate the buffers for decompression */ + TEST_ASSERT_NOT_EQUAL_INT(0, data_size); + s = decompress_cmp_entiy(ent, model_of_data, NULL, NULL); + decompressed_data = malloc(s); TEST_ASSERT_NOT_NULL(decompressed_data); + + if (model_mode_is_used(cfg->cmp_mode)) { + updated_model = malloc(data_size); + TEST_ASSERT_NOT_NULL(updated_model); + } + + /* now we try to decompress the data */ + s = decompress_cmp_entiy(ent, model_of_data, updated_model, decompressed_data); + TEST_ASSERT_EQUAL_INT(data_size, s); + TEST_ASSERT_FALSE(memcmp(decompressed_data, cfg->input_buf, data_size)); + + if (model_mode_is_used(cfg->cmp_mode)) { + TEST_ASSERT_NOT_NULL(updated_model); + TEST_ASSERT_NOT_NULL(model_of_data); + TEST_ASSERT_FALSE(memcmp(updated_model, cfg->icu_new_model_buf, data_size)); + memcpy(model_of_data, updated_model, data_size); + } else { /* non-model mode */ + /* reset model */ + free(model_of_data); + model_of_data = malloc(data_size); + memcpy(model_of_data, decompressed_data, data_size); + } + + cfg->icu_output_buf = NULL; + free(ent); + free(decompressed_data); + free(updated_model); +} + + +#define CMP_BUFFER_FAKTOR 3 /* compression data buffer size / data to compress buffer size */ + +/** + * @brief random compression decompression test + * @detail We generate random data and compress them with random parameters. + * After that we put the data in a compression entity. We decompress the + * compression entity and compare the decompressed data with the original + * data. + * @test icu_compress_data + * @test decompress_cmp_entiy + */ + +void test_random_compression_decompression(void) +{ + enum cmp_data_type data_type; + enum cmp_mode cmp_mode; + struct cmp_cfg cfg; + int cmp_buffer_size; + + /* TODO: extend test for DATA_TYPE_F_CAM_BACKGROUND, DATA_TYPE_F_CAM_OFFSET */ + for (data_type = 1; data_type <= DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE; data_type++) { + /* printf("%s\n", data_type2string(data_type)); */ + /* generate random data*/ + uint32_t samples = random_between(1, 430179/CMP_BUFFER_FAKTOR); + uint32_t model_value = random_between(0, MAX_MODEL_VALUE); + void *data_to_compress1 = generate_random_test_data(samples, data_type); + void *data_to_compress2 = generate_random_test_data(samples, data_type); + void *updated_model = calloc(1, cmp_cal_size_of_data(samples, data_type)); + /* for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_STUFF; cmp_mode++) { */ + for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_DIFF_MULTI; cmp_mode++) { + /* printf("cmp_mode: %i\n", cmp_mode); */ + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, + CMP_LOSSLESS); + TEST_ASSERT_NOT_EQUAL_INT(cfg.data_type, DATA_TYPE_UNKNOWN); + + generate_random_cmp_par(&cfg); + + if (!model_mode_is_used(cmp_mode)) + cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data_to_compress1, + samples, NULL, NULL, NULL, samples*CMP_BUFFER_FAKTOR); + else + cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data_to_compress2, + samples, data_to_compress1, updated_model, NULL, samples*CMP_BUFFER_FAKTOR); + + TEST_ASSERT_EQUAL_INT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*samples, data_type)); + + compression_decompression(&cfg); + } + free(data_to_compress1); + free(data_to_compress2); + free(updated_model); + } +} + +#define N_SAMPLES 5 + +void test_random_compression_decompression2(void) +{ + struct cmp_cfg cfg; + struct cmp_info info = {0}; + uint32_t cmp_buffer_size; + int s, i, cmp_size_bits; + void *compressed_data; + uint16_t *decompressed_data; + uint16_t data[N_SAMPLES] = {0, UINT16_MAX, INT16_MAX, 42, 23}; + + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 8, CMP_LOSSLESS); + TEST_ASSERT_NOT_EQUAL_INT(cfg.data_type, DATA_TYPE_UNKNOWN); + + cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data, N_SAMPLES, NULL, NULL, + NULL, N_SAMPLES*CMP_BUFFER_FAKTOR); + compressed_data = malloc(cmp_buffer_size); + cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data, N_SAMPLES, NULL, NULL, + compressed_data, N_SAMPLES*CMP_BUFFER_FAKTOR); + TEST_ASSERT_EQUAL_INT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*N_SAMPLES, DATA_TYPE_IMAGETTE)); + + cmp_size_bits = icu_compress_data(&cfg); + TEST_ASSERT(cmp_size_bits > 0); + info.cmp_size = cmp_size_bits; + info.cmp_mode_used = (uint8_t)cfg.cmp_mode; + info.model_value_used = (uint8_t)cfg.model_value; + info.round_used = (uint8_t)cfg.round; + info.spill_used = cfg.spill; + info.golomb_par_used = cfg.golomb_par; + info.samples_used = cfg.samples; + info.rdcu_new_model_adr_used = cfg.rdcu_new_model_adr; + info.rdcu_cmp_adr_used = cfg.rdcu_buffer_adr; + + s = decompress_rdcu_data(compressed_data, &info, NULL, NULL, NULL); + TEST_ASSERT(s > 0); + decompressed_data = malloc(s); + s = decompress_rdcu_data(compressed_data, &info, NULL, NULL, decompressed_data); + TEST_ASSERT(s > 0); + + for (i = 0; i < N_SAMPLES; i++) { + TEST_ASSERT_EQUAL_HEX16(data[i], decompressed_data[i]); + } + + + free(compressed_data); + free(decompressed_data); +} diff --git a/test/cmp_icu/test_cmp_icu.c b/test/cmp_icu/test_cmp_icu.c new file mode 100644 index 0000000000000000000000000000000000000000..65ab54581940e79ad902c1c272bd76c51604ab30 --- /dev/null +++ b/test/cmp_icu/test_cmp_icu.c @@ -0,0 +1,4376 @@ +#include <stdlib.h> + +#if defined __has_include +# if __has_include(<time.h>) +# include <time.h> +# include <unistd.h> +# define HAS_TIME_H 1 +# endif +#endif + +#include "unity.h" +#include "cmp_icu.h" +#include "../lib/cmp_icu.c" /* this is a hack to test static functions */ + +/* TODO: test compression with samples = 0 and buffer_length = 0; */ + +/** + * @brief Seeds the pseudo-random number generator used by rand() + */ + +void setUp(void) +{ + unsigned int seed; + static int n; + +#if HAS_TIME_H + seed = time(NULL) * getpid(); +#else + seed = 1; +#endif + + if (!n) { + n = 1; + srand(seed); + printf("seed: %u\n", seed); + } +} + + +/** + * @brief generate a random number + * + * @param min minimum value (inclusive) + * @param max maximum value (inclusive) + * + * @returns "random" numbers in the range [M, N] + * + * @see https://c-faq.com/lib/randrange.html + */ + +int random_between(unsigned int min, unsigned int max) +{ + TEST_ASSERT(min < max); + TEST_ASSERT(max-min <= RAND_MAX); + return min + rand() / (RAND_MAX / (max - min + 1) + 1); +} + + +/** + * @test cmp_cfg_icu_create + */ + +void test_cmp_cfg_icu_create(void) +{ + struct cmp_cfg cfg; + enum cmp_data_type data_type; + enum cmp_mode cmp_mode; + uint32_t model_value, lossy_par; + /* TODO: change that when DATA_TYPE_BACKGROUND and + * DATA_TYPE_F_CAM_BACKGROUND are implemented */ + const enum cmp_data_type biggest_data_type = DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE; + + /* wrong data type tests */ + data_type = DATA_TYPE_UNKNOWN; /* not valid data type */ + cmp_mode = CMP_MODE_RAW; + model_value = 0; + lossy_par = CMP_LOSSLESS; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + memset(&cfg, 0, sizeof(cfg)); + + data_type = biggest_data_type + 1; /* not valid data type */ + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + memset(&cfg, 0, sizeof(cfg)); + + data_type = biggest_data_type; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(biggest_data_type, cfg.data_type); + TEST_ASSERT_EQUAL_INT(CMP_MODE_RAW, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(0, cfg.model_value); + TEST_ASSERT_EQUAL_INT(0, cfg.round); + memset(&cfg, 0, sizeof(cfg)); + + /* this should work */ + data_type = DATA_TYPE_IMAGETTE; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type); + TEST_ASSERT_EQUAL_INT(CMP_MODE_RAW, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(0, cfg.model_value); + TEST_ASSERT_EQUAL_INT(0, cfg.round); + memset(&cfg, 0, sizeof(cfg)); + + /* wrong compression mode tests */ + cmp_mode = CMP_MODE_STUFF + 1; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + memset(&cfg, 0, sizeof(cfg)); + + cmp_mode = -1; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + memset(&cfg, 0, sizeof(cfg)); + + /* this should work */ + cmp_mode = CMP_MODE_STUFF; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type); + TEST_ASSERT_EQUAL_INT(CMP_MODE_STUFF, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(0, cfg.model_value); + TEST_ASSERT_EQUAL_INT(0, cfg.round); + memset(&cfg, 0, sizeof(cfg)); + + /* wrong model_value tests */ + cmp_mode = CMP_MODE_MODEL_MULTI; /* model value checks only active on model mode */ + model_value = MAX_MODEL_VALUE + 1; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + + model_value = -1U; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + + /* this should work */ + model_value = MAX_MODEL_VALUE; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type); + TEST_ASSERT_EQUAL_INT(CMP_MODE_MODEL_MULTI, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(16, cfg.model_value); + TEST_ASSERT_EQUAL_INT(0, cfg.round); + + /* no checks for model mode -> no model cmp_mode */ + cmp_mode = CMP_MODE_STUFF; + model_value = MAX_MODEL_VALUE + 1; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type); + TEST_ASSERT_EQUAL_INT(CMP_MODE_STUFF, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(MAX_MODEL_VALUE + 1, cfg.model_value); + TEST_ASSERT_EQUAL_INT(0, cfg.round); + model_value = MAX_MODEL_VALUE; + + /* wrong lossy_par tests */ + lossy_par = MAX_ICU_ROUND + 1; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + + lossy_par = -1U; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_UNKNOWN, cfg.data_type); + + /* this should work */ + lossy_par = MAX_ICU_ROUND; + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(DATA_TYPE_IMAGETTE, cfg.data_type); + TEST_ASSERT_EQUAL_INT(CMP_MODE_STUFF, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(16, cfg.model_value); + TEST_ASSERT_EQUAL_INT(3, cfg.round); + + /* random test */ + data_type = random_between(DATA_TYPE_IMAGETTE, biggest_data_type); + cmp_mode = random_between(CMP_MODE_RAW, CMP_MODE_STUFF); + model_value = random_between(0, MAX_MODEL_VALUE); + lossy_par = random_between(CMP_LOSSLESS, MAX_ICU_ROUND); + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, lossy_par); + TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type); + TEST_ASSERT_EQUAL_INT(cmp_mode, cfg.cmp_mode); + TEST_ASSERT_EQUAL_INT(model_value, cfg.model_value); + TEST_ASSERT_EQUAL_INT(lossy_par, cfg.round); +} + + +/** + * @test cmp_cfg_icu_buffers + */ + +void test_cmp_cfg_icu_buffers(void) +{ + struct cmp_cfg cfg; + void *data_to_compress; + uint32_t data_samples; + void *model_of_data; + void *updated_model; + uint32_t *compressed_data; + uint32_t compressed_data_len_samples; + size_t s; + uint16_t ima_data[4] = {42, 23, 0, 0xFFFF}; + uint16_t ima_model[4] = {0xC, 0xA, 0xFF, 0xE}; + uint16_t ima_up_model[4] = {0}; + uint32_t cmp_data[2] = {0}; + + /* error case: unknown data_type */ + cfg = cmp_cfg_icu_create(DATA_TYPE_UNKNOWN, CMP_MODE_DIFF_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + data_samples = 4; + model_of_data = NULL; + updated_model = NULL; + compressed_data = cmp_data; + compressed_data_len_samples = 4; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* error case: no data test */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_DIFF_ZERO, 16, CMP_LOSSLESS); + data_to_compress = NULL; /* no data set */ + data_samples = 4; + model_of_data = NULL; + updated_model = NULL; + compressed_data = cmp_data; + compressed_data_len_samples = 4; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* now its should work */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_DIFF_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(8, s); + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(NULL, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.samples); + TEST_ASSERT_EQUAL(NULL, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length); + + /* error case: model mode and no model */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + model_of_data = NULL; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* now its should work */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + model_of_data = ima_model; + updated_model = ima_model; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(8, s); + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.samples); + TEST_ASSERT_EQUAL(ima_model, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length); + + /* error case: data == model */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + model_of_data = ima_data; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* error case: data == compressed_data */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + model_of_data = ima_model; + compressed_data = (void *)ima_data; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* error case: data == updated_model */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + model_of_data = ima_model; + updated_model = ima_data; + compressed_data = (void *)ima_data; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* error case: model == compressed_data */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + model_of_data = ima_model; + compressed_data = (void *)ima_model; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* error case: updated_model == compressed_data */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + model_of_data = ima_model; + updated_model = ima_up_model; + compressed_data = (void *)ima_up_model; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* warning case: samples = 0 */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_to_compress = ima_data; + data_samples = 0; + model_of_data = ima_model; + updated_model = ima_up_model; + compressed_data = cmp_data; + compressed_data_len_samples = 4; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(8, s); + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(0, cfg.samples); + TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length); + memset(&cfg, 0, sizeof(cfg)); + + /* error case: compressed_data_len_samples = 0 */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_samples = 4; + compressed_data_len_samples = 0; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* this should now work */ + /* if data_samples = 0 -> compressed_data_len_samples = 0 is allowed */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_samples = 0; + compressed_data_len_samples = 0; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); /* not an error, it is the size of the compressed data */ + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(0, cfg.samples); + TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(0, cfg.buffer_length); + + /* this should now work */ + /* if compressed_data = NULL -> compressed_data_len_samples = 0 is allowed */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + data_samples = 4; + compressed_data = NULL; + compressed_data_len_samples = 0; + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); /* not an error, it is the size of the compressed data */ + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.samples); + TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(NULL, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(0, cfg.buffer_length); + + /* error case: RAW mode compressed_data smaller than data_samples */ + compressed_data = cmp_data; + compressed_data_len_samples = 3; + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); + + /* this should now work */ + compressed_data = NULL; + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(6, s); + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.samples); + TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(NULL, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(3, cfg.buffer_length); + + /* this should also now work */ + compressed_data = cmp_data; + compressed_data_len_samples = 4; + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(8, s); + TEST_ASSERT_EQUAL(ima_data, cfg.input_buf); + TEST_ASSERT_EQUAL_INT(ima_model, cfg.model_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.samples); + TEST_ASSERT_EQUAL(ima_up_model, cfg.icu_new_model_buf); + TEST_ASSERT_EQUAL(cmp_data, cfg.icu_output_buf); + TEST_ASSERT_EQUAL_INT(4, cfg.buffer_length); + + /* error case: cfg = NULL */ + s = cmp_cfg_icu_buffers(NULL, data_to_compress, data_samples, + model_of_data, updated_model, compressed_data, + compressed_data_len_samples); + TEST_ASSERT_EQUAL_size_t(0, s); +} + + +/** + * @test cmp_cfg_icu_imagette + */ + +void test_cmp_cfg_icu_imagette(void) +{ + struct cmp_cfg cfg = {0}; + uint32_t cmp_par; + uint32_t spillover_par; + enum cmp_data_type data_type; + + int error; + + /* lowest values 1d/model mode */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_ZERO, 0, CMP_LOSSLESS); + cmp_par = MIN_IMA_GOLOMB_PAR; + spillover_par = MIN_IMA_SPILL; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cfg.golomb_par, 1); + TEST_ASSERT_EQUAL_INT(cfg.spill, 2); + + /* highest values 1d/model mode */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_CAM_IMAGETTE, CMP_MODE_DIFF_MULTI, 16, CMP_LOSSLESS); + cmp_par = MAX_IMA_GOLOMB_PAR; + spillover_par = cmp_ima_max_spill(cmp_par); + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cfg.golomb_par, MAX_IMA_GOLOMB_PAR); + TEST_ASSERT_EQUAL_INT(cfg.spill, cmp_ima_max_spill(MAX_IMA_GOLOMB_PAR)); + + /* wrong data type test */ + for (data_type = 0; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) { + cfg = cmp_cfg_icu_create(data_type, CMP_MODE_DIFF_MULTI, 16, CMP_LOSSLESS); + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + if (data_type == DATA_TYPE_IMAGETTE || + data_type == DATA_TYPE_SAT_IMAGETTE || + data_type == DATA_TYPE_F_CAM_IMAGETTE) { + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type); + TEST_ASSERT_EQUAL_INT(cfg.golomb_par, MAX_IMA_GOLOMB_PAR); + TEST_ASSERT_EQUAL_INT(cfg.spill, cmp_ima_max_spill(MAX_IMA_GOLOMB_PAR)); + } else { + TEST_ASSERT_TRUE(error); + } + } + + /* model/1d MODE tests */ + + /* cmp_par to big */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_MULTI, 16, CMP_LOSSLESS); + cmp_par = MAX_IMA_GOLOMB_PAR + 1; + spillover_par = MIN_IMA_SPILL; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); + /* ignore in RAW MODE */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + + /* cmp_par to small */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_MULTI, 16, CMP_LOSSLESS); + cmp_par = MIN_IMA_GOLOMB_PAR - 1; + spillover_par = MIN_IMA_SPILL; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); + /* ignore in RAW MODE */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + + /* spillover_par to big */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_MODEL_MULTI, 16, CMP_LOSSLESS); + cmp_par = MIN_IMA_GOLOMB_PAR; + spillover_par = cmp_ima_max_spill(cmp_par)+1; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); + /* ignore in RAW MODE */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + + /* spillover_par to small */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + cmp_par = MAX_IMA_GOLOMB_PAR; + spillover_par = MIN_IMA_SPILL -1 ; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); + /* ignore in RAW MODE */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 16, CMP_LOSSLESS); + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + + /* CMP_MODE_STUFF tests */ + spillover_par = ~0; /* is ignored */ + + /* highest values STUFF MODE */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_STUFF, ~0, CMP_LOSSLESS); + cmp_par = MAX_STUFF_CMP_PAR; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cfg.golomb_par, 32); + + /* lowest values STUFF MODE */ + cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_STUFF, ~0, CMP_LOSSLESS); + cmp_par = 0; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cfg.golomb_par, 0); + + /* cmp_par to big */ + cfg = cmp_cfg_icu_create(DATA_TYPE_SAT_IMAGETTE, CMP_MODE_STUFF, ~0, CMP_LOSSLESS); + cmp_par = MAX_STUFF_CMP_PAR+1; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); + + /* cfg = NULL test*/ + error = cmp_cfg_icu_imagette(NULL, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); + + /* invalid compression mode test*/ + cfg = cmp_cfg_icu_create(DATA_TYPE_SAT_IMAGETTE, CMP_MODE_STUFF+1, ~0, CMP_LOSSLESS); + cmp_par = MAX_STUFF_CMP_PAR+1; + error = cmp_cfg_icu_imagette(&cfg, cmp_par, spillover_par); + TEST_ASSERT_TRUE(error); +} + + +/** + * @test cmp_cfg_fx_cob + */ + +void test_cmp_cfg_fx_cob(void) +{ + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = 2; + uint32_t spillover_exp_flags = 2; + uint32_t cmp_par_fx = 2; + uint32_t spillover_fx = 2; + uint32_t cmp_par_ncob = 2; + uint32_t spillover_ncob = 2; + uint32_t cmp_par_efx = 2; + uint32_t spillover_efx = 2; + uint32_t cmp_par_ecob = 2; + uint32_t spillover_ecob = 2; + uint32_t cmp_par_fx_cob_variance = 2; + uint32_t spillover_fx_cob_variance = 2; + int error; + enum cmp_data_type data_type; + + + /* wrong data type test */ + for (data_type = 0; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) { + cfg = cmp_cfg_icu_create(data_type, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + if (data_type == DATA_TYPE_S_FX || + data_type == DATA_TYPE_S_FX_EFX || + data_type == DATA_TYPE_S_FX_NCOB || + data_type == DATA_TYPE_S_FX_EFX_NCOB_ECOB || + data_type == DATA_TYPE_L_FX || + data_type == DATA_TYPE_L_FX_EFX || + data_type == DATA_TYPE_L_FX_NCOB || + data_type == DATA_TYPE_L_FX_EFX_NCOB_ECOB || + data_type == DATA_TYPE_F_FX || + data_type == DATA_TYPE_F_FX_EFX || + data_type == DATA_TYPE_F_FX_NCOB || + data_type == DATA_TYPE_F_FX_EFX_NCOB_ECOB) { + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_efx); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_ncob); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_ecob); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_ecob); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_fx_cob_variance); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_fx_cob_variance); + } else { + TEST_ASSERT_TRUE(error); + } + } + + /* cfg == NULL test */ + error = cmp_cfg_fx_cob(NULL, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + /* test DATA_TYPE_S_FX */ + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = ~0; /* invalid parameter */ + spillover_ncob = ~0; /* invalid parameter */ + cmp_par_efx = ~0; /* invalid parameter */ + spillover_efx = ~0; /* invalid parameter */ + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + + /* invalid spillover_exp_flags parameter */ + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags)+1; + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + /* invalid cmp_par_fx parameter */ + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR - 1; + spillover_fx = MIN_ICU_SPILL; + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + + /* test DATA_TYPE_S_FX_EFX */ + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX, CMP_MODE_MODEL_ZERO, 0, 1); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = ~0; /* invalid parameter */ + spillover_ncob = ~0; /* invalid parameter */ + cmp_par_efx = 23; + spillover_efx = 42; + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx); + + /* invalid spillover_efx parameter */ + spillover_efx = 0; + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + + /* test DATA_TYPE_S_FX_NCOB */ + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_NCOB, CMP_MODE_MODEL_ZERO, 0, 1); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = 19; + spillover_ncob = 5; + cmp_par_efx = ~0; /* invalid parameter */ + spillover_efx = ~0; /* invalid parameter */ + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob); + + /* invalid cmp_par_ncob parameter */ + cmp_par_ncob = 0; + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + + /* test DATA_TYPE_S_FX_EFX_NCOB_ECOB */ + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = 19; + spillover_ncob = 5; + cmp_par_efx = 23; + spillover_efx = 42; + cmp_par_ecob = MAX_ICU_GOLOMB_PAR; + spillover_ecob = MIN_ICU_SPILL; + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob); + TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx); + TEST_ASSERT_EQUAL_INT(cmp_par_ecob, cfg.cmp_par_ecob); + TEST_ASSERT_EQUAL_INT(spillover_ecob, cfg.spill_ecob); + + /* invalid cmp_par_ecob parameter */ + cmp_par_ecob = -1U; + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + + /* DATA_TYPE_L_FX */ + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = ~0; /* invalid parameter */ + spillover_ncob = ~0; /* invalid parameter */ + cmp_par_efx = ~0; /* invalid parameter */ + spillover_efx = ~0; /* invalid parameter */ + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = 30; + spillover_fx_cob_variance = 8; + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance); + TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance); + + /* invalid spillover_fx_cob_variance parameter */ + spillover_fx_cob_variance = 1; + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_TRUE(error); + + + /* DATA_TYPE_L_FX_EFX */ + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = ~0; /* invalid parameter */ + spillover_ncob = ~0; /* invalid parameter */ + cmp_par_efx = 23; + spillover_efx = 42; + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = 30; + spillover_fx_cob_variance = 8; + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx); + TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance); + TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance); + + + /* DATA_TYPE_L_FX_NCOB */ + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_NCOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = 19; + spillover_ncob = 5; + cmp_par_efx = ~0; /* invalid parameter */ + spillover_efx = ~0; /* invalid parameter */ + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = 30; + spillover_fx_cob_variance = 8; + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob); + TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance); + TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance); + + + /* DATA_TYPE_L_FX_EFX_NCOB_ECOB */ + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = 19; + spillover_ncob = 5; + cmp_par_efx = 23; + spillover_efx = 42; + cmp_par_ecob = MAX_ICU_GOLOMB_PAR; + spillover_ecob = MIN_ICU_SPILL; + cmp_par_fx_cob_variance = 30; + spillover_fx_cob_variance = 8; + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_exp_flags, cfg.cmp_par_exp_flags); + TEST_ASSERT_EQUAL_INT(spillover_exp_flags, cfg.spill_exp_flags); + TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx); + TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob); + TEST_ASSERT_EQUAL_INT(cmp_par_ecob, cfg.cmp_par_ecob); + TEST_ASSERT_EQUAL_INT(spillover_ecob, cfg.spill_ecob); + TEST_ASSERT_EQUAL_INT(cmp_par_fx_cob_variance, cfg.cmp_par_fx_cob_variance); + TEST_ASSERT_EQUAL_INT(spillover_fx_cob_variance, cfg.spill_fx_cob_variance); + + + /* DATA_TYPE_F_FX */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = ~0; /* invalid parameter */ + spillover_exp_flags = ~0; /* invalid parameter */ + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = ~0; /* invalid parameter */ + spillover_ncob = ~0; /* invalid parameter */ + cmp_par_efx = ~0; /* invalid parameter */ + spillover_efx = ~0; /* invalid parameter */ + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + + + /* DATA_TYPE_F_FX_EFX */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = ~0; /* invalid parameter */ + spillover_exp_flags = ~0; /* invalid parameter */ + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = ~0; /* invalid parameter */ + spillover_ncob = ~0; /* invalid parameter */ + cmp_par_efx = 23; + spillover_efx = 42; + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx); + + + /* DATA_TYPE_F_FX_NCOB */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_NCOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = ~0; /* invalid parameter */ + spillover_exp_flags = ~0; /* invalid parameter */ + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = MIN_ICU_GOLOMB_PAR; + spillover_ncob = cmp_icu_max_spill(cmp_par_ncob); + cmp_par_efx = ~0; /* invalid parameter */ + spillover_efx = ~0; /* invalid parameter */ + cmp_par_ecob = ~0; /* invalid parameter */ + spillover_ecob = ~0; /* invalid parameter */ + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob); + + + /* DATA_TYPE_F_FX_EFX_NCOB_ECOB */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_exp_flags = ~0; /* invalid parameter */ + spillover_exp_flags = ~0; /* invalid parameter */ + cmp_par_fx = MIN_ICU_GOLOMB_PAR; + spillover_fx = MIN_ICU_SPILL; + cmp_par_ncob = MIN_ICU_GOLOMB_PAR; + spillover_ncob = cmp_icu_max_spill(cmp_par_ncob); + cmp_par_efx = 23; + spillover_efx = 42; + cmp_par_ecob = MAX_ICU_GOLOMB_PAR; + spillover_ecob = MIN_ICU_SPILL; + cmp_par_fx_cob_variance = ~0; /* invalid parameter */ + spillover_fx_cob_variance = ~0; /* invalid parameter */ + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(cmp_par_fx, cfg.cmp_par_fx); + TEST_ASSERT_EQUAL_INT(spillover_fx, cfg.spill_fx); + TEST_ASSERT_EQUAL_INT(cmp_par_ncob, cfg.cmp_par_ncob); + TEST_ASSERT_EQUAL_INT(spillover_ncob, cfg.spill_ncob); + TEST_ASSERT_EQUAL_INT(cmp_par_efx, cfg.cmp_par_efx); + TEST_ASSERT_EQUAL_INT(spillover_efx, cfg.spill_efx); + TEST_ASSERT_EQUAL_INT(cmp_par_ecob, cfg.cmp_par_ecob); + TEST_ASSERT_EQUAL_INT(spillover_ecob, cfg.spill_ecob); +} + +/** + * @test cmp_cfg_aux + */ + +void test_cmp_cfg_aux(void) +{ struct cmp_cfg cfg; + uint32_t cmp_par_mean = 2; + uint32_t spillover_mean = 2; + uint32_t cmp_par_variance = 2; + uint32_t spillover_variance = 2; + uint32_t cmp_par_pixels_error = 2; + uint32_t spillover_pixels_error = 2; + int error; + enum cmp_data_type data_type; + + /* wrong data type test */ + for (data_type = 0; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) { + cfg = cmp_cfg_icu_create(data_type, CMP_MODE_MODEL_ZERO, 16, CMP_LOSSLESS); + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + if (data_type == DATA_TYPE_OFFSET || + data_type == DATA_TYPE_BACKGROUND || + data_type == DATA_TYPE_SMEARING + /* data_type == DATA_TYPE_F_CAM_OFFSET || */ + /* data_type == DATA_TYPE_F_CAM_BACKGROUND */ + ) { + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(data_type, cfg.data_type); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_mean); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_mean); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_variance); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_variance); + TEST_ASSERT_EQUAL_INT(2, cfg.cmp_par_pixels_error); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_pixels_error); + } else { + TEST_ASSERT_TRUE(error); + } + } + + /* cfg == NULL test */ + error = cmp_cfg_aux(NULL, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_TRUE(error); + + + /* DATA_TYPE_OFFSET */ + cfg = cmp_cfg_icu_create(DATA_TYPE_OFFSET, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_mean = MIN_ICU_GOLOMB_PAR; + spillover_mean = cmp_icu_max_spill(MIN_ICU_GOLOMB_PAR); + cmp_par_variance = MIN_ICU_GOLOMB_PAR; + spillover_variance = MIN_ICU_SPILL; + cmp_par_pixels_error = ~0; + spillover_pixels_error = ~0; + + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_mean); + TEST_ASSERT_EQUAL_INT(cmp_icu_max_spill(MIN_ICU_GOLOMB_PAR), cfg.spill_mean); + TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_variance); + TEST_ASSERT_EQUAL_INT(2, cfg.spill_variance); + + /* This should fail */ + cmp_par_mean = MIN_ICU_GOLOMB_PAR-1; + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_TRUE(error); + + + /* DATA_TYPE_BACKGROUND */ + cfg = cmp_cfg_icu_create(DATA_TYPE_BACKGROUND, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_mean = MAX_ICU_GOLOMB_PAR; + spillover_mean = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + cmp_par_variance = MIN_ICU_GOLOMB_PAR; + spillover_variance = MIN_ICU_SPILL; + cmp_par_pixels_error = 42; + spillover_pixels_error = 23; + + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(MAX_ICU_GOLOMB_PAR, cfg.cmp_par_mean); + TEST_ASSERT_EQUAL_INT(cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR), cfg.spill_mean); + TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_variance); + TEST_ASSERT_EQUAL_INT(MIN_ICU_SPILL, cfg.spill_variance); + TEST_ASSERT_EQUAL_INT(42, cfg.cmp_par_pixels_error); + TEST_ASSERT_EQUAL_INT(23, cfg.spill_pixels_error); + + /* This should fail */ + cmp_par_variance = MIN_ICU_GOLOMB_PAR-1; + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_TRUE(error); + + + /* DATA_TYPE_SMEARING */ + cfg = cmp_cfg_icu_create(DATA_TYPE_SMEARING, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + cmp_par_mean = MAX_ICU_GOLOMB_PAR; + spillover_mean = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + cmp_par_variance = MIN_ICU_GOLOMB_PAR; + spillover_variance = MIN_ICU_SPILL; + cmp_par_pixels_error = 42; + spillover_pixels_error = 23; + + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL_INT(MAX_ICU_GOLOMB_PAR, cfg.cmp_par_mean); + TEST_ASSERT_EQUAL_INT(cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR), cfg.spill_mean); + TEST_ASSERT_EQUAL_INT(MIN_ICU_GOLOMB_PAR, cfg.cmp_par_variance); + TEST_ASSERT_EQUAL_INT(MIN_ICU_SPILL, cfg.spill_variance); + TEST_ASSERT_EQUAL_INT(42, cfg.cmp_par_pixels_error); + TEST_ASSERT_EQUAL_INT(23, cfg.spill_pixels_error); + + /* This should fail */ + spillover_pixels_error = cmp_icu_max_spill(42)+1; + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_TRUE(error); + +#if 0 +TODO: implemented F_CAM DATA_TYPE_F_CAM_OFFSET and DATA_TYPE_F_CAM_BACKGROUND + /* DATA_TYPE_F_CAM_OFFSET */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_CAM_OFFSET, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); + /* DATA_TYPE_F_CAM_BACKGROUND */ + cfg = cmp_cfg_icu_create(DATA_TYPE_F_CAM_BACKGROUND, CMP_MODE_DIFF_ZERO, 7, CMP_LOSSLESS); +#endif +} + + +/** + * @test map_to_pos + */ + +void test_map_to_pos(void) +{ + uint32_t value_to_map; + uint32_t max_data_bits; + uint32_t mapped_value; + + /* test mapping 32 bits values */ + max_data_bits = 32; + + value_to_map = 0; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(0, mapped_value); + + value_to_map = -1U; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = 1; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(2, mapped_value); + + value_to_map = 42; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(84, mapped_value); + + value_to_map = INT32_MAX; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_HEX(UINT32_MAX-1, mapped_value); + + value_to_map = INT32_MIN; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_HEX(UINT32_MAX, mapped_value); + + /* test mapping 16 bits values */ + max_data_bits = 16; + + value_to_map = -1U; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + /* test mapping 6 bits values */ + max_data_bits = 6; + + value_to_map = 0; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(0, mapped_value); + + value_to_map = -1U; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = UINT32_MAX; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = -1U & 0x3FU; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = 63; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(1, mapped_value); + + value_to_map = 1; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(2, mapped_value); + + value_to_map = 31; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(62, mapped_value); + + value_to_map = -33U; /* aka 31 */ + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(62, mapped_value); + + value_to_map = -32U; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(63, mapped_value); + + value_to_map = 32; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(63, mapped_value); +} + + +/** + * @test put_n_bits32 + */ + +#define SDP_PB_N 3 + + +static void init_PB32_arrays(uint32_t *z, uint32_t *o) +{ + uint32_t i; + + /* init testarray with all 0 and all 1 */ + for (i = 0; i < SDP_PB_N; i++) { + z[i] = 0; + o[i] = 0xffffffff; + } +} + + +void test_put_n_bits32(void) +{ + uint32_t v, n; + int o, rval; /* return value */ + uint32_t testarray0[SDP_PB_N]; + uint32_t testarray1[SDP_PB_N]; + const uint32_t l = sizeof(testarray0) * CHAR_BIT; + + /* hereafter, the value is v, + * the number of bits to write is n, + * the offset of the bit is o, + * the max length the bitstream in bits is l + */ + + init_PB32_arrays(testarray0, testarray1); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + TEST_ASSERT(testarray0[2] == 0); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + TEST_ASSERT(testarray1[2] == 0xffffffff); + + /*** n=0 ***/ + + /* do not write, left border */ + v = 0; n = 0; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(0, rval); + + v = 0xffffffff; n = 0; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(0, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(0, rval); + + /* do not write, right border */ + v = 0; n = 0; o = l; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(l, rval); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(l, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(l, rval); + + /* test value = 0xffffffff; N = 0 */ + v = 0xffffffff; n = 0; o = l; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(l, rval); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(l, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(l, rval); + + /*** n=1 ***/ + + /* left border, write 0 */ + v = 0; n = 1; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(1, rval); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(1, rval); + TEST_ASSERT(testarray1[0] == 0x7fffffff); + + /* left border, write 1 */ + v = 1; n = 1; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(1, rval); + TEST_ASSERT(testarray0[0] == 0x80000000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(1, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + + /* left border, write 32 */ + v = 0xf0f0abcd; n = 32; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 32); + TEST_ASSERT(testarray0[0] == 0xf0f0abcd); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 32); + TEST_ASSERT(testarray1[0] == 0xf0f0abcd); + TEST_ASSERT(testarray1[1] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* middle, write 2 bits */ + v = 3; n = 2; o = 29; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 31); + TEST_ASSERT(testarray0[0] == 0x6); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT_EQUAL_INT(rval, 31); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /*** n=5, unsegmented ***/ + + /* left border, write 0 */ + v = 0; n = 5; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 5); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT(testarray1[0] == 0x07ffffff); + TEST_ASSERT_EQUAL_INT(rval, 5); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* left border, write 11111 */ + v = 0x1f; n = 5; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 5); + TEST_ASSERT(testarray0[0] == 0xf8000000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 5); + TEST_ASSERT(testarray1[0] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* middle, write 0 */ + v = 0; n = 5; o = 7; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 12); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 12); + TEST_ASSERT(testarray1[0] == 0xfe0fffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* middle, write 11111 */ + v = 0x1f; n = 5; o = 7; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 12); + TEST_ASSERT(testarray0[0] == 0x01f00000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 12); + TEST_ASSERT(testarray1[0] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* right, write 0 */ + v = 0; n = 5; o = 91; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 96); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + TEST_ASSERT(testarray0[0] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 96); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + TEST_ASSERT(testarray1[2] == 0xffffffe0); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* right, write 11111 */ + v = 0x1f; n = 5; o = 91; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 96); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + TEST_ASSERT(testarray0[2] == 0x0000001f); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 96); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + TEST_ASSERT(testarray1[2] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* 32 bit, write 0 */ + v = 0; n = 32; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 32); + TEST_ASSERT(testarray0[0] == 0x00000000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 32); + TEST_ASSERT(testarray1[0] == 0x00000000); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* 32 bit, write -1 */ + v = 0xffffffff; n = 32; o = 0; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 32); + TEST_ASSERT(testarray0[0] == 0xffffffff); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 32); + TEST_ASSERT(testarray1[0] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* SEGMENTED cases */ + /* 5 bit, write 0 */ + v = 0; n = 5; o = 62; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 67); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + TEST_ASSERT(testarray0[2] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 67); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xfffffffc); + TEST_ASSERT(testarray1[2] == 0x1fffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* 5 bit, write 1f */ + v = 0x1f; n = 5; o = 62; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 67); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 3); + TEST_ASSERT(testarray0[2] == 0xe0000000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 67); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + TEST_ASSERT(testarray1[2] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* 32 bit, write 0 */ + v = 0; n = 32; o = 1; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 33); + TEST_ASSERT(testarray0[0] == 0x00000000); + TEST_ASSERT(testarray0[1] == 0x00000000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 33); + TEST_ASSERT(testarray1[0] == 0x80000000); + TEST_ASSERT(testarray1[1] == 0x7fffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* 32 bit, write -1 */ + v = 0xffffffff; n = 32; o = 1; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, 33); + TEST_ASSERT(testarray0[0] == 0x7fffffff); + TEST_ASSERT(testarray0[1] == 0x80000000); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(rval, 33); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /* test NULL buffer */ + v = 0; n = 0; o = 0; + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(rval, 0); + + v = 0; n = 1; o = 0; + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(rval, 1); + + v = 0; n = 5; o = 31; + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(rval, 36); + + v = 0; n = 2; o = 95; + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(rval, 97); /* rval can be longer than l */ + + /* value larger than n allows */ + v = 0x7f; n = 6; o = 10; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray0[0] == 0x003f0000); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(16, rval); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + v = 0xffffffff; n = 6; o = 10; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray0[0] == 0x003f0000); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(16, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(16, rval); + /* re-init input arrays after clobbering */ + init_PB32_arrays(testarray0, testarray1); + + /*** error cases ***/ + /* n too large */ + v = 0x0; n = 33; o = 1; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(rval, -1); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(rval, -1); + + /* try to put too much in the bitstream */ + v = 0x1; n = 1; o = 96; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, rval); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + TEST_ASSERT(testarray0[2] == 0); + + /* this should work (if bitstream=NULL no length check) */ + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(97, rval); + + /* offset lager than max_stream_len(l) */ + v = 0x0; n = 32; o = INT32_MAX; + rval = put_n_bits32(v, n, o, testarray1, l); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, rval); + TEST_ASSERT(testarray1[0] == 0xffffffff); + TEST_ASSERT(testarray1[1] == 0xffffffff); + TEST_ASSERT(testarray1[2] == 0xffffffff); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT(rval < 0); + + /* negative offset */ + v = 0x0; n = 0; o = -1; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(-1, rval); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(-1, rval); + + v = 0x0; n = 0; o = -2; + rval = put_n_bits32(v, n, o, testarray0, l); + TEST_ASSERT_EQUAL_INT(-1, rval); + TEST_ASSERT(testarray0[0] == 0); + TEST_ASSERT(testarray0[1] == 0); + + rval = put_n_bits32(v, n, o, NULL, l); + TEST_ASSERT_EQUAL_INT(-1, rval); +} + + +/** + * @test rice_encoder + */ + +void test_rice_encoder(void) +{ + uint32_t value, g_par, log2_g_par, cw, cw_len; + const uint32_t MAX_GOLOMB_PAR = 0x80000000; + + /* test minimum Golomb parameter */ + value = 0; log2_g_par = (uint32_t)ilog_2(MIN_ICU_GOLOMB_PAR); g_par = 1U << log2_g_par; cw = ~0U; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(1, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 31; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, cw); + + /* test some arbitrary values */ + value = 0; log2_g_par = 4; g_par = 1U << log2_g_par; cw = ~0U; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 42; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(7, cw_len); + TEST_ASSERT_EQUAL_HEX(0x6a, cw); + + value = 446; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEE, cw); + + value = 447; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEF, cw); + + /* test maximum Golomb parameter for rice_encoder */ + value = 0; log2_g_par = (uint32_t)ilog_2(MAX_GOLOMB_PAR); g_par = 1U << log2_g_par; cw = ~0U; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 0x7FFFFFFE; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFE, cw); + + value = 0x7FFFFFFF; + cw_len = rice_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, cw); +} + + +/** + * @test golomb_encoder + */ + +void test_golomb_encoder(void) +{ + uint32_t value, g_par, log2_g_par, cw, cw_len; + const uint32_t MAX_GOLOMB_PAR = 0x80000000; + + /* test minimum Golomb parameter */ + value = 0; g_par = MIN_ICU_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(1, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 31; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, cw); + + + /* test some arbitrary values with g_par = 16 */ + value = 0; g_par = 16; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(5, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 42; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(7, cw_len); + TEST_ASSERT_EQUAL_HEX(0x6a, cw); + + value = 446; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEE, cw); + + value = 447; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFEF, cw); + + + /* test some arbitrary values with g_par = 3 */ + value = 0; g_par = 3; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(2, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(3, cw_len); + TEST_ASSERT_EQUAL_HEX(0x2, cw); + + value = 42; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(16, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFC, cw); + + value = 44; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(17, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1FFFB, cw); + + value = 88; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFA, cw); + + value = 89; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFB, cw); + + + /* test maximum Golomb parameter for golomb_encoder */ + value = 0; g_par = MAX_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; g_par = MAX_GOLOMB_PAR; log2_g_par = (uint32_t)ilog_2(g_par); cw = ~0U; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x1, cw); + + value = 0x7FFFFFFE; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFE, cw); + + value = 0x7FFFFFFF; + cw_len = golomb_encoder(value, g_par, log2_g_par, &cw); + TEST_ASSERT_EQUAL_INT(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, cw); +} + + +/** + * @test encode_value_zero + */ + +void test_encode_value_zero(void) +{ + uint32_t data, model; + int stream_len; + struct encoder_setupt setup = {0}; + uint32_t bitstream[3] = {0}; + + /* setup the setup */ + setup.encoder_par1 = 1; + setup.encoder_par2 = (uint32_t)ilog_2(setup.encoder_par1); + setup.spillover_par = 32; + setup.max_data_bits = 32; + setup.generate_cw_f = rice_encoder; + setup.bitstream_adr = bitstream; + setup.max_stream_len = sizeof(bitstream) * CHAR_BIT; + + stream_len = 0; + + data = 0; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(2, stream_len); + TEST_ASSERT_EQUAL_HEX(0x80000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + data = 5; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(14, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFF80000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + data = 2; model = 7; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(25, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + /* zero escape mechanism */ + data = 100; model = 42; + /* (100-42)*2+1=117 -> cw 0 + 0x0000_0000_0000_0075 */ + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(58, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00001D40, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + /* test overflow */ + data = INT32_MIN; model = 0; + /* (INT32_MIN)*-2-1+1=0(overflow) -> cw 0 + 0x0000_0000_0000_0000 */ + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(91, stream_len); + TEST_ASSERT_EQUAL_HEX(0xBFFBFF00, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00001D40, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + + /* small buffer error */ + data = 23; model = 26; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len); + + /* reset bitstream to all bits set */ + bitstream[0] = ~0U; + bitstream[1] = ~0U; + bitstream[2] = ~0U; + stream_len = 0; + + /* we use now values with maximum 6 bits */ + setup.max_data_bits = 6; + + /* lowest value before zero encoding */ + data = 53; model = 38; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(32, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* lowest value with zero encoding */ + data = 0; model = 16; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(39, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x41FFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* maximum positive value to encode */ + data = 31; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(46, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x40FFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* maximum negative value to encode */ + data = 0; model = 32; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(53, stream_len); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFE, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x40FC07FF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[2]); + + /* small buffer error when creating the zero escape symbol*/ + bitstream[0] = 0; + bitstream[1] = 0; + bitstream[2] = 0; + stream_len = 32; + setup.max_stream_len = 32; + data = 31; model = 0; + stream_len = encode_value_zero(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); +} + + +/** + * @test encode_value_multi + */ + +void test_encode_value_multi(void) +{ + uint32_t data, model; + int stream_len; + struct encoder_setupt setup = {0}; + uint32_t bitstream[4] = {0}; + + /* setup the setup */ + setup.encoder_par1 = 1; + setup.encoder_par2 = (uint32_t)ilog_2(setup.encoder_par1); + setup.spillover_par = 16; + setup.max_data_bits = 32; + setup.generate_cw_f = golomb_encoder; + setup.bitstream_adr = bitstream; + setup.max_stream_len = sizeof(bitstream) * CHAR_BIT; + + stream_len = 0; + + data = 0; model = 0; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(1, stream_len); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + data = 0; model = 1; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(3, stream_len); + TEST_ASSERT_EQUAL_HEX(0x40000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + data = 1+23; model = 0+23; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(6, stream_len); + TEST_ASSERT_EQUAL_HEX(0x58000000, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* highest value without multi outlier encoding */ + data = 0+42; model = 8+42; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(22, stream_len); + TEST_ASSERT_EQUAL_HEX(0x5BFFF800, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* lowest value with multi outlier encoding */ + data = 8+42; model = 0+42; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(41, stream_len); + TEST_ASSERT_EQUAL_HEX(0x5BFFFBFF, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFC000000, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* highest value with multi outlier encoding */ + data = INT32_MIN; model = 0; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(105, stream_len); + TEST_ASSERT_EQUAL_HEX(0x5BFFFBFF, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFC7FFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFF7FFFFF, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0xF7800000, bitstream[3]); + + /* small buffer error */ + data = 0; model = 38; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len); + + /* small buffer error when creating the multi escape symbol*/ + bitstream[0] = 0; + bitstream[1] = 0; + setup.max_stream_len = 32; + + stream_len = 32; + data = 31; model = 0; + stream_len = encode_value_multi(data, model, stream_len, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, stream_len); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); +} + + +/** + * @test encode_value + */ + +void test_encode_value(void) +{ + struct encoder_setupt setup = {0}; + uint32_t bitstream[4] = {0}; + uint32_t data, model; + int cmp_size; + + setup.encode_method_f = encode_value_none; + setup.bitstream_adr = bitstream; + setup.max_stream_len = 128; + cmp_size = 0; + + /* test 32 bit input */ + setup.encoder_par1 = 32; + setup.max_data_bits = 32; + setup.lossy_par = 0; + + data = 0; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(32, cmp_size); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[3]); + + data = UINT32_MAX; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(64, cmp_size); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[3]); + + /* test rounding */ + setup.lossy_par = 1; + data = UINT32_MAX; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(96, cmp_size); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[3]); + + setup.lossy_par = 2; + data = 0x3; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(128, cmp_size); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0x7FFFFFFF, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0x00000000, bitstream[3]); + + /* small buffer error bitstream can not hold more data*/ + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size); + + /* reset bitstream */ + bitstream[0] = 0; + bitstream[1] = 0; + bitstream[2] = 0; + bitstream[3] = 0; + cmp_size = 0; + + /* test 31 bit input */ + setup.encoder_par1 = 31; + setup.max_data_bits = 31; + setup.lossy_par = 0; + + data = 0; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(31, cmp_size); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[3]); + + data = 0x7FFFFFFF; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(62, cmp_size); + TEST_ASSERT_EQUAL_HEX(0x00000001, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFC, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[3]); + + /* round = 1 */ + setup.lossy_par = 1; + data = UINT32_MAX; model = UINT32_MAX; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(93, cmp_size); + TEST_ASSERT_EQUAL_HEX(0x00000001, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFFF, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0xFFFFFFF8, bitstream[2]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[3]); + + /* data are bigger than max_data_bits */ + setup.lossy_par = 0; + data = UINT32_MAX; model = 0; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_size); + + /* model are bigger than max_data_bits */ + setup.lossy_par = 0; + cmp_size = 93; + data = 0; model = UINT32_MAX; + cmp_size = encode_value(data, model, cmp_size, &setup); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_size); +} + + +/** + * @test cmp_get_max_used_bits + * TODO: move this test + */ + +void test_cmp_get_max_used_bits(void) +{ + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + TEST_ASSERT_EQUAL_INT(max_used_bits.nc_imagette, MAX_USED_NC_IMAGETTE_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.saturated_imagette, MAX_USED_SATURATED_IMAGETTE_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_imagette, MAX_USED_FC_IMAGETTE_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.f_fx, MAX_USED_F_FX_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.f_efx, MAX_USED_F_EFX_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.f_ncob, MAX_USED_F_NCOB_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.f_ecob, MAX_USED_F_ECOB_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.s_exp_flags, MAX_USED_S_FX_EXPOSURE_FLAGS_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.s_fx, MAX_USED_S_FX_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.s_efx, MAX_USED_S_EFX_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.s_ncob, MAX_USED_S_NCOB_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.s_ecob, MAX_USED_S_ECOB_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.l_fx_variance, MAX_USED_L_FX_VARIANCE_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.l_efx, MAX_USED_L_EFX_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.l_ncob, MAX_USED_L_NCOB_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.l_ecob, MAX_USED_L_ECOB_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.l_cob_variance, MAX_USED_L_COB_VARIANCE_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.nc_offset_mean, MAX_USED_NC_OFFSET_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.nc_offset_variance, MAX_USED_NC_OFFSET_VARIANCE_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.nc_background_mean, MAX_USED_NC_BACKGROUND_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.nc_background_variance, MAX_USED_NC_BACKGROUND_VARIANCE_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.nc_background_outlier_pixels, MAX_USED_NC_BACKGROUND_OUTLIER_PIXELS_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.smearing_mean, MAX_USED_SMEARING_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.smearing_variance_mean, MAX_USED_SMEARING_VARIANCE_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.smearing_outlier_pixels, MAX_USED_SMEARING_OUTLIER_PIXELS_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_offset_mean, MAX_USED_FC_OFFSET_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_offset_variance, MAX_USED_FC_OFFSET_VARIANCE_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_offset_pixel_in_error, MAX_USED_FC_OFFSET_PIXEL_IN_ERROR_BITS); + + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_background_mean, MAX_USED_FC_BACKGROUND_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_background_variance, MAX_USED_FC_BACKGROUND_VARIANCE_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.fc_background_outlier_pixels, MAX_USED_FC_BACKGROUND_OUTLIER_PIXELS_BITS); +} + + +/** + * @test configure_encoder_setup + */ + +void test_configure_encoder_setup(void) +{ + struct encoder_setupt setup; + uint32_t cmp_par; + uint32_t spillover; + uint32_t lossy_par; + uint32_t max_data_bits; + struct cmp_cfg cfg; + int error; + + /* test Golomb encoder zero escape mechanism */ + cmp_par = 42; + spillover = 23; + lossy_par = 0; + max_data_bits = 15; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_MODEL_ZERO; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL(golomb_encoder, setup.generate_cw_f); /* pointer to the code word encoder */ + TEST_ASSERT_EQUAL(encode_value_zero, setup.encode_method_f); /* pointer to the encoding function */ + TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */ + TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */ + TEST_ASSERT_EQUAL_INT(42, setup.encoder_par1); /* encoding parameter 1 */ + TEST_ASSERT_EQUAL_INT(5, setup.encoder_par2); /* encoding parameter 2 */ + TEST_ASSERT_EQUAL_INT(23, setup.spillover_par); /* outlier parameter */ + TEST_ASSERT_EQUAL_INT(0, setup.lossy_par); /* lossy compression parameter */ + TEST_ASSERT_EQUAL_INT(15, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */ + memset(&setup, 0, sizeof(setup)); + + /* test Rice encoder multi escape mechanism */ + cmp_par = 32; + spillover = 23; + lossy_par = 0; + max_data_bits = 32; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_MULTI; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL(rice_encoder, setup.generate_cw_f); /* pointer to the code word encoder */ + TEST_ASSERT_EQUAL(encode_value_multi, setup.encode_method_f); /* pointer to the encoding function */ + TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */ + TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */ + TEST_ASSERT_EQUAL_INT(32, setup.encoder_par1); /* encoding parameter 1 */ + TEST_ASSERT_EQUAL_INT(5, setup.encoder_par2); /* encoding parameter 2 */ + TEST_ASSERT_EQUAL_INT(23, setup.spillover_par); /* outlier parameter */ + TEST_ASSERT_EQUAL_INT(0, setup.lossy_par); /* lossy compression parameter */ + TEST_ASSERT_EQUAL_INT(32, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */ + memset(&setup, 0, sizeof(setup)); + + /* test CMP_MODE_STUFF */ + cmp_par = 32; + spillover = ~0; + lossy_par = 1; + max_data_bits = 32; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_STUFF; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL(NULL, setup.generate_cw_f); /* pointer to the code word encoder */ + TEST_ASSERT_EQUAL(encode_value_none, setup.encode_method_f); /* pointer to the encoding function */ + TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */ + TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */ + TEST_ASSERT_EQUAL_INT(32, setup.encoder_par1); /* encoding parameter 1 */ + TEST_ASSERT_EQUAL_INT(0, setup.encoder_par2); /* encoding parameter 2 */ + TEST_ASSERT_EQUAL_INT(0, setup.spillover_par); /* outlier parameter */ + TEST_ASSERT_EQUAL_INT(1, setup.lossy_par); /* lossy compression parameter */ + TEST_ASSERT_EQUAL_INT(32, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */ + memset(&setup, 0, sizeof(setup)); + + /* test max_used_bits = 33 */ + cmp_par = 32; + spillover = 23; + lossy_par = 0; + max_data_bits = 33; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_MULTI; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_TRUE(error); + memset(&setup, 0, sizeof(setup)); + + /* cmp_par = 0 test */ + cmp_par = 0; + spillover = 23; + lossy_par = 0; + max_data_bits = 32; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_MULTI; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_TRUE(error); + memset(&setup, 0, sizeof(setup)); + + /* cmp_par = 0 test STUFF MODE this should work*/ + cmp_par = 0; + spillover = 23; + lossy_par = 0; + max_data_bits = 32; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_STUFF; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_FALSE(error); + TEST_ASSERT_EQUAL(NULL, setup.generate_cw_f); /* pointer to the code word encoder */ + TEST_ASSERT_EQUAL(encode_value_none, setup.encode_method_f); /* pointer to the encoding function */ + TEST_ASSERT_EQUAL(123, setup.bitstream_adr); /* start address of the compressed data bitstream */ + TEST_ASSERT_EQUAL_INT(32, setup.max_stream_len); /* maximum length of the bitstream/icu_output_buf in bits */ + TEST_ASSERT_EQUAL_INT(0, setup.encoder_par1); /* encoding parameter 1 */ + TEST_ASSERT_EQUAL_INT(0, setup.encoder_par2); /* encoding parameter 2 */ + TEST_ASSERT_EQUAL_INT(0, setup.spillover_par); /* outlier parameter */ + TEST_ASSERT_EQUAL_INT(0, setup.lossy_par); /* lossy compression parameter */ + TEST_ASSERT_EQUAL_INT(0, setup.max_data_bits); /* how many bits are needed to represent the highest possible value */ + memset(&setup, 0, sizeof(setup)); + + /* cmp_mode = STUFF_MODE +1 */ + cmp_par = 32; + spillover = 23; + lossy_par = 0; + max_data_bits = 1; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_STUFF+1; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_TRUE(error); + memset(&setup, 0, sizeof(setup)); + + /* setup = NULL test */ + cmp_par = 42; + spillover = 23; + lossy_par = 0; + max_data_bits = 15; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_MODEL_ZERO; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(NULL, cmp_par, spillover,lossy_par, + max_data_bits, &cfg); + TEST_ASSERT_TRUE(error); + memset(&setup, 0, sizeof(setup)); + + /* cfg = NULL test */ + cmp_par = 42; + spillover = 23; + lossy_par = 0; + max_data_bits = 15; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_MODEL_ZERO; + cfg.icu_output_buf = (void *)123; + cfg.buffer_length = 2; + error = configure_encoder_setup(&setup, cmp_par, spillover,lossy_par, + max_data_bits, NULL); + TEST_ASSERT_TRUE(error); + memset(&setup, 0, sizeof(setup)); +} + + +/** + * @test compress_imagette + */ + +void test_compress_imagette_diff(void) +{ + uint16_t data[] = {0xFFFF, 1, 0, 42, 0x8000, 0x7FFF, 0xFFFF}; + uint32_t output_buf[3] = {0xFFFF, 0xFFFF, 0xFFFF}; + struct cmp_cfg cfg = {0}; + int cmp_size; + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_ZERO; + cfg.input_buf = data; + cfg.samples = 7; + cfg.golomb_par = 1; + cfg.spill = 8; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 7; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(66, cmp_size); + TEST_ASSERT_EQUAL_HEX(0xDF6002AB, be32_to_cpu(output_buf[0])); + TEST_ASSERT_EQUAL_HEX(0xFEB70000, be32_to_cpu(output_buf[1])); + TEST_ASSERT_EQUAL_HEX(0x00000000, be32_to_cpu(output_buf[2])); +} + + +/** + * @test compress_imagette + */ + +void test_compress_imagette_model(void) +{ + uint16_t data[] = {0x0000, 0x0001, 0x0042, 0x8000, 0x7FFF, 0xFFFF, 0xFFFF}; + uint16_t model[] = {0x0000, 0xFFFF, 0xF301, 0x8FFF, 0x0000, 0xFFFF, 0x0000}; + uint16_t model_up[7] = {0}; + uint32_t output_buf[3] = {0xFFFF, 0xFFFF, 0xFFFF}; + struct cmp_cfg cfg = {0}; + int cmp_size; + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_MODEL_MULTI; + cfg.input_buf = data; + cfg.model_buf = model; + cfg.icu_new_model_buf = model_up; + cfg.samples = 7; + cfg.golomb_par = 3; + cfg.spill = 8; + cfg.model_value = 8; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 8; + + cmp_size = icu_compress_data(&cfg); + + TEST_ASSERT_EQUAL_INT(76, cmp_size); + TEST_ASSERT_EQUAL_HEX(0x2BDB4F5E, be32_to_cpu(output_buf[0])); + TEST_ASSERT_EQUAL_HEX(0xDFF5F9FF, be32_to_cpu(output_buf[1])); + TEST_ASSERT_EQUAL_HEX(0xEC200000, be32_to_cpu(output_buf[2])); + + TEST_ASSERT_EQUAL_HEX(0x0000, model_up[0]); + TEST_ASSERT_EQUAL_HEX(0x8000, model_up[1]); + TEST_ASSERT_EQUAL_HEX(0x79A1, model_up[2]); + TEST_ASSERT_EQUAL_HEX(0x87FF, model_up[3]); + TEST_ASSERT_EQUAL_HEX(0x3FFF, model_up[4]); + TEST_ASSERT_EQUAL_HEX(0xFFFF, model_up[5]); + TEST_ASSERT_EQUAL_HEX(0x7FFF, model_up[6]); + + + /* error case: model mode without model data */ + cfg.model_buf = NULL; /* this is the error */ + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL(-1, cmp_size); +} + + +/** + * @test compress_imagette + */ + +void test_compress_imagette_stuff(void) +{ + uint16_t data[] = {0x0, 0x1, 0x23, 0x42, 0x8000, 0x7FFF, 0xFFFF}; + uint32_t output_buf[4] = {0}; + struct cmp_cfg cfg = {0}; + + int cmp_size; + uint8_t output_buf_exp[] = { + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x23, 0x00, 0x42, + 0x80, 0x00, 0x7F, 0xFF, + 0xFF, 0xFF, 0x00, 0x00}; + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_STUFF; + cfg.input_buf = data; + cfg.samples = 7; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 8; + cfg.golomb_par = 16; /* how many used bits has the maximum data value */ + + cmp_size = icu_compress_data(&cfg); + + uint32_t *output_buf_exp_32 = (uint32_t *)output_buf_exp; + TEST_ASSERT_EQUAL_INT(7*16, cmp_size); + TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[0], output_buf[0]); + TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[1], output_buf[1]); + TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[2], output_buf[2]); + TEST_ASSERT_EQUAL_HEX16(output_buf_exp_32[3], output_buf[3]); +} + + +/** + * @test compress_imagette + */ + +void test_compress_imagette_raw(void) +{ + uint16_t data[] = {0x0, 0x1, 0x23, 0x42, INT16_MIN, INT16_MAX, UINT16_MAX}; + uint16_t output_buf[7] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + struct cmp_cfg cfg = {0}; + int cmp_size; + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.model_buf = NULL; + cfg.input_buf = data; + cfg.samples = 7; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 7; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(7*16, cmp_size); + TEST_ASSERT_EQUAL_HEX16(0x0, be16_to_cpu(output_buf[0])); + TEST_ASSERT_EQUAL_HEX16(0x1, be16_to_cpu(output_buf[1])); + TEST_ASSERT_EQUAL_HEX16(0x23, be16_to_cpu(output_buf[2])); + TEST_ASSERT_EQUAL_HEX16(0x42, be16_to_cpu(output_buf[3])); + TEST_ASSERT_EQUAL_HEX16(INT16_MIN, be16_to_cpu(output_buf[4])); + TEST_ASSERT_EQUAL_HEX16(INT16_MAX, be16_to_cpu(output_buf[5])); + TEST_ASSERT_EQUAL_HEX16(UINT16_MAX, be16_to_cpu(output_buf[6])); + + + /* compressed data buf = NULL test */ + memset(&cfg, 0, sizeof(struct cmp_cfg)); + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.input_buf = data; + cfg.samples = 7; + cfg.icu_output_buf = NULL; + cfg.buffer_length = 7; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(7*16, cmp_size); + + + /* error case: input_buf = NULL */ + memset(&cfg, 0, sizeof(struct cmp_cfg)); + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.input_buf = NULL; /* no data to compress */ + cfg.samples = 7; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 7; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_size); + + + /* error case: compressed data buffer to small */ + memset(&cfg, 0, sizeof(struct cmp_cfg)); + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.input_buf = data; + cfg.samples = 7; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 6; /* the buffer is to small */ + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size); +} + + +/** + * @test compress_imagette + */ + +void test_compress_imagette_error_cases(void) +{ + uint16_t data[] = {0xFFFF, 1, 0, 42, 0x8000, 0x7FFF, 0xFFFF}; + uint32_t output_buf[2] = {0xFFFF, 0xFFFF}; + struct cmp_cfg cfg = {0}; + int cmp_size; + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_ZERO; + cfg.input_buf = NULL; + cfg.samples = 0; /* nothing to compress */ + cfg.golomb_par = 1; + cfg.spill = 8; + cfg.icu_output_buf = NULL; + cfg.buffer_length = 0; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(0, cmp_size); + + + /* compressed data buffer to small test */ + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_ZERO; + cfg.input_buf = data; + cfg.samples = 7; + cfg.golomb_par = 1; + cfg.spill = 8; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 4; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size); + + + /* error in setup */ + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + max_used_bits.nc_imagette = 33; + cmp_set_max_used_bits(&max_used_bits); + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_ZERO; + cfg.input_buf = data; + cfg.samples = 2; + cfg.golomb_par = 1; + cfg.spill = 8; + cfg.icu_output_buf = (uint32_t *)output_buf; + cfg.buffer_length = 4; + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_size); +} + + +/** + * @test compress_multi_entry_hdr + */ + +void test_compress_multi_entry_hdr(void) +{ + int stream_len; + uint8_t data[MULTI_ENTRY_HDR_SIZE]; + uint8_t model[MULTI_ENTRY_HDR_SIZE]; + uint8_t up_model[MULTI_ENTRY_HDR_SIZE]; + uint8_t cmp_data[MULTI_ENTRY_HDR_SIZE]; + uint8_t *data_p = NULL; + uint8_t *model_p = NULL; + uint8_t *up_model_p = NULL; + + memset(data, 0x42, sizeof(data)); + + /* no data; no cmp_data no model test */ + /* no data; no model; no up_model; no cmp_data */ + stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p, + (void **)&up_model_p, NULL); + TEST_ASSERT_EQUAL_INT(96, stream_len); + + /* no model; no up_model */ + data_p = data; + stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p, + (void **)&up_model_p, cmp_data); + TEST_ASSERT_EQUAL_INT(96, stream_len); + TEST_ASSERT_FALSE(memcmp(cmp_data, data, MULTI_ENTRY_HDR_SIZE)); + TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE); + + /* no up_model */ + memset(cmp_data, 0, sizeof(cmp_data)); + data_p = data; + model_p = model; + up_model_p = NULL; + stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p, + (void **)&up_model_p, cmp_data); + TEST_ASSERT_EQUAL_INT(96, stream_len); + TEST_ASSERT_FALSE(memcmp(cmp_data, data, MULTI_ENTRY_HDR_SIZE)); + TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE); + TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE); + + /* all buffer test */ + memset(cmp_data, 0, sizeof(cmp_data)); + data_p = data; + model_p = model; + up_model_p = up_model; + stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p, + (void **)&up_model_p, cmp_data); + TEST_ASSERT_EQUAL_INT(96, stream_len); + TEST_ASSERT_FALSE(memcmp(cmp_data, data, MULTI_ENTRY_HDR_SIZE)); + TEST_ASSERT_FALSE(memcmp(up_model, data, MULTI_ENTRY_HDR_SIZE)); + TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE); + TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE); + TEST_ASSERT_EQUAL(up_model_p-up_model, MULTI_ENTRY_HDR_SIZE); + + /* all buffer test; no cmp_data */ + memset(cmp_data, 0, sizeof(cmp_data)); + data_p = data; + model_p = model; + up_model_p = up_model; + stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p, + (void **)&up_model_p, NULL); + TEST_ASSERT_EQUAL_INT(96, stream_len); + TEST_ASSERT_FALSE(memcmp(up_model, data, MULTI_ENTRY_HDR_SIZE)); + TEST_ASSERT_EQUAL(data_p-data, MULTI_ENTRY_HDR_SIZE); + TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE); + TEST_ASSERT_EQUAL(up_model_p-up_model, MULTI_ENTRY_HDR_SIZE); + + /* no data, use up_model test */ + memset(cmp_data, 0, sizeof(cmp_data)); + data_p = NULL; + model_p = model; + up_model_p = up_model; + stream_len = compress_multi_entry_hdr((void **)&data_p, (void **)&model_p, + (void **)&up_model_p, NULL); + TEST_ASSERT_EQUAL_INT(96, stream_len); + TEST_ASSERT_EQUAL(model_p-model, MULTI_ENTRY_HDR_SIZE); + TEST_ASSERT_EQUAL(up_model_p-up_model, MULTI_ENTRY_HDR_SIZE); +} + + +void test_compress_s_fx_raw(void) +{ + struct s_fx data[7]; + struct cmp_cfg cfg = {0}; + int cmp_size, cmp_size_exp; + size_t i; + + cfg.data_type = DATA_TYPE_S_FX; + cfg.model_buf = NULL; + cfg.samples = 7; + cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + cfg.buffer_length = 7; + cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.icu_output_buf); + TEST_ASSERT_NOT_NULL(cfg.input_buf); + + data[0].exp_flags = 0x0; + data[0].fx = 0x0; + data[1].exp_flags = 0x1; + data[1].fx = 0x1; + data[2].exp_flags = 0x2; + data[2].fx = 0x23; + data[3].exp_flags = 0x3; + data[3].fx = 0x42; + data[4].exp_flags = 0x0; + data[4].fx = INT32_MIN; + data[5].exp_flags = 0x3; + data[5].fx = INT32_MAX; + data[6].exp_flags = 0x1; + data[6].fx = UINT32_MAX; + + struct multi_entry_hdr *hdr = cfg.input_buf; + memset(hdr, 0x42, sizeof(struct multi_entry_hdr)); + memcpy(hdr->entry, data, sizeof(data)); + + cmp_size = icu_compress_data(&cfg); + + cmp_size_exp = (sizeof(data) + sizeof(struct multi_entry_hdr)) * CHAR_BIT; + TEST_ASSERT_EQUAL_INT(cmp_size_exp, cmp_size); + + for (i = 0; i < ARRAY_SIZE(data); i++) { + hdr = (struct multi_entry_hdr *)cfg.icu_output_buf; + struct s_fx *p = (struct s_fx *)hdr->entry; + + TEST_ASSERT_EQUAL_HEX(data[i].exp_flags, p[i].exp_flags); + TEST_ASSERT_EQUAL_HEX(data[i].fx, cpu_to_be32(p[i].fx)); + } +} + + +void test_compress_s_fx_staff(void) +{ + struct s_fx data[5]; + struct cmp_cfg cfg = {0}; + int cmp_size, cmp_size_exp; + struct multi_entry_hdr *hdr; + uint32_t *cmp_data; + + /* setup configuration */ + cfg.data_type = DATA_TYPE_S_FX; + cfg.cmp_mode = CMP_MODE_STUFF; + cfg.samples = 5; + cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.input_buf); + cfg.buffer_length = 5; + cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.icu_output_buf); + cfg.cmp_par_exp_flags = 2; + cfg.cmp_par_fx = 21; + + /* generate input data */ + hdr = cfg.input_buf; + /* use dummy data for the header */ + memset(hdr, 0x42, sizeof(struct multi_entry_hdr)); + data[0].exp_flags = 0x0; + data[0].fx = 0x0; + data[1].exp_flags = 0x1; + data[1].fx = 0x1; + data[2].exp_flags = 0x2; + data[2].fx = 0x23; + data[3].exp_flags = 0x3; + data[3].fx = 0x42; + data[4].exp_flags = 0x0; + data[4].fx = 0x001FFFFF; + memcpy(hdr->entry, data, sizeof(data)); + + cmp_size = icu_compress_data(&cfg); + + cmp_size_exp = 5 * (2 + 21) + MULTI_ENTRY_HDR_SIZE * CHAR_BIT; + TEST_ASSERT_EQUAL_INT(cmp_size_exp, cmp_size); + TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE)); + hdr = (void *)cfg.icu_output_buf; + cmp_data = (uint32_t *)hdr->entry; + TEST_ASSERT_EQUAL_HEX(0x00000080, be32_to_cpu(cmp_data[0])); + TEST_ASSERT_EQUAL_HEX(0x00060001, be32_to_cpu(cmp_data[1])); + TEST_ASSERT_EQUAL_HEX(0x1E000423, be32_to_cpu(cmp_data[2])); + TEST_ASSERT_EQUAL_HEX(0xFFFFE000, be32_to_cpu(cmp_data[3])); + + free(cfg.input_buf); + free(cfg.icu_output_buf); +} + + +void test_compress_s_fx_model_multi(void) +{ + struct s_fx data[6], model[6]; + struct s_fx *up_model_buf; + struct cmp_cfg cfg = {0}; + int cmp_size; + struct multi_entry_hdr *hdr; + uint32_t *cmp_data; + struct cmp_max_used_bits max_used_bits; + + /* setup configuration */ + cfg.data_type = DATA_TYPE_S_FX; + cfg.cmp_mode = CMP_MODE_MODEL_MULTI; + cfg.model_value = 11; + cfg.samples = 6; + cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.input_buf); + cfg.model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.model_buf); + cfg.icu_new_model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.icu_new_model_buf); + cfg.buffer_length = 6; + cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.icu_output_buf); + cfg.cmp_par_exp_flags = 1; + cfg.spill_exp_flags = 8; + cfg.cmp_par_fx = 3; + cfg.spill_fx = 35; + + + /* generate input data */ + hdr = cfg.input_buf; + /* use dummy data for the header */ + memset(hdr, 0x42, sizeof(struct multi_entry_hdr)); + data[0].exp_flags = 0x0; + data[0].fx = 0x0; + data[1].exp_flags = 0x1; + data[1].fx = 0x1; + data[2].exp_flags = 0x2; + data[2].fx = 0x23; + data[3].exp_flags = 0x3; + data[3].fx = 0x42; + data[4].exp_flags = 0x0; + data[4].fx = 0x001FFFFF; + data[5].exp_flags = 0x0; + data[5].fx = 0x0; + memcpy(hdr->entry, data, sizeof(data)); + + /* generate model data */ + hdr = cfg.model_buf; + /* use dummy data for the header */ + memset(hdr, 0x41, sizeof(struct multi_entry_hdr)); + model[0].exp_flags = 0x0; + model[0].fx = 0x0; + model[1].exp_flags = 0x3; + model[1].fx = 0x1; + model[2].exp_flags = 0x0; + model[2].fx = 0x42; + model[3].exp_flags = 0x0; + model[3].fx = 0x23; + model[4].exp_flags = 0x3; + model[4].fx = 0x0; + model[5].exp_flags = 0x2; + model[5].fx = 0x001FFFFF; + memcpy(hdr->entry, model, sizeof(model)); + + max_used_bits = cmp_get_max_used_bits(); + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 21; + cmp_set_max_used_bits(&max_used_bits); + + cmp_size = icu_compress_data(&cfg); + + TEST_ASSERT_EQUAL_INT(166, cmp_size); + TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE)); + cmp_data = &cfg.icu_output_buf[MULTI_ENTRY_HDR_SIZE/sizeof(uint32_t)]; + TEST_ASSERT_EQUAL_HEX(0x1C77FFA6, be32_to_cpu(cmp_data[0])); + TEST_ASSERT_EQUAL_HEX(0xAFFF4DE5, be32_to_cpu(cmp_data[1])); + TEST_ASSERT_EQUAL_HEX(0xCC000000, be32_to_cpu(cmp_data[2])); + + hdr = cfg.icu_new_model_buf; + up_model_buf = (struct s_fx *)hdr->entry; + TEST_ASSERT_FALSE(memcmp(hdr, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE)); + TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[0].exp_flags); + TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[0].fx); + TEST_ASSERT_EQUAL_HEX(0x2, up_model_buf[1].exp_flags); + TEST_ASSERT_EQUAL_HEX(0x1, up_model_buf[1].fx); + TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[2].exp_flags); + TEST_ASSERT_EQUAL_HEX(0x38, up_model_buf[2].fx); + TEST_ASSERT_EQUAL_HEX(0x0, up_model_buf[3].exp_flags); + TEST_ASSERT_EQUAL_HEX(0x2C, up_model_buf[3].fx); + TEST_ASSERT_EQUAL_HEX(0x2, up_model_buf[4].exp_flags); + TEST_ASSERT_EQUAL_HEX(0x9FFFF, up_model_buf[4].fx); + TEST_ASSERT_EQUAL_HEX(0x1, up_model_buf[5].exp_flags); + TEST_ASSERT_EQUAL_HEX(0x15FFFF, up_model_buf[5].fx); + + free(cfg.input_buf); + free(cfg.model_buf); + free(cfg.icu_new_model_buf); + free(cfg.icu_output_buf); +} + + +#if 0 +void todo_est_compress_s_fx_efx_model_multi(void) +{ + uint32_t i; + struct s_fx_efx data[6], model[6]; + struct s_fx_efx *up_model_buf; + struct cmp_cfg cfg = {0}; + int cmp_size; + struct multi_entry_hdr *hdr; + uint32_t *cmp_data; + struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits(); + + /* define max_used_bits */ + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 21; + max_used_bits.s_efx = 21; + cmp_set_max_used_bits(&max_used_bits); + + /* setup configuration */ + cfg.data_type = DATA_TYPE_S_FX_EFX; + cfg.cmp_mode = CMP_MODE_MODEL_MULTI; + cfg.model_value = 16; + cfg.samples = 6; + cfg.input_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.input_buf); + cfg.model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.model_buf); + cfg.icu_new_model_buf = malloc(cmp_cal_size_of_data(cfg.samples, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.icu_new_model_buf); + cfg.buffer_length = 6; + cfg.icu_output_buf = malloc(cmp_cal_size_of_data(cfg.buffer_length, cfg.data_type)); + TEST_ASSERT_NOT_NULL(cfg.icu_output_buf); + cfg.cmp_par_exp_flags = 1; + cfg.spill_exp_flags = 8; + cfg.cmp_par_fx = 3; + cfg.spill_fx = 35; + cfg.cmp_par_efx = 4; + cfg.spill_efx = 35; + + + /* generate input data */ + hdr = cfg.input_buf; + /* use dummy data for the header */ + memset(hdr, 0x42, sizeof(struct multi_entry_hdr)); + data[0].exp_flags = 0x0; + data[0].fx = 0x0; + data[0].efx = 0x0; + data[1].exp_flags = 0x1; + data[1].fx = 0x1; + data[1].efx = 0; + data[2].exp_flags = 0x2; + data[2].fx = 0x23; + data[2].efx = 0; + data[3].exp_flags = 0x3; + data[3].fx = 0x42; + data[3].efx = 0; + data[4].exp_flags = 0x0; + data[4].fx = 0x001FFFFF; + data[4].efx = 0; + data[5].exp_flags = 0x0; + data[5].fx = 0x0; + data[5].efx = 0; + memcpy(hdr->entry, data, sizeof(data)); + + /* generate model data */ + hdr = cfg.model_buf; + /* use dummy data for the header */ + memset(hdr, 0x41, sizeof(struct multi_entry_hdr)); + model[0].exp_flags = 0x0; + model[0].fx = 0x0; + model[0].efx = 0x1FFFFF; + model[1].exp_flags = 0x3; + model[1].fx = 0x1; + model[1].efx = 0x1FFFFF; + model[2].exp_flags = 0x0; + model[2].fx = 0x42; + model[2].efx = 0x1FFFFF; + model[3].exp_flags = 0x0; + model[3].fx = 0x23; + model[3].efx = 0x1FFFFF; + model[4].exp_flags = 0x3; + model[4].fx = 0x0; + model[4].efx = 0x1FFFFF; + model[5].exp_flags = 0x2; + model[5].fx = 0x001FFFFF; + model[5].efx = 0x1FFFFF; + memcpy(hdr->entry, model, sizeof(model)); + + cmp_size = icu_compress_data(&cfg); +#if 0 + TEST_ASSERT_EQUAL_INT(166, cmp_size); + TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE)); + cmp_data = &cfg.icu_output_buf[MULTI_ENTRY_HDR_SIZE/sizeof(uint32_t)]; + TEST_ASSERT_EQUAL_HEX(0x1C77FFA6, be32_to_cpu(cmp_data[0])); + TEST_ASSERT_EQUAL_HEX(0xAFFF4DE5, be32_to_cpu(cmp_data[1])); + TEST_ASSERT_EQUAL_HEX(0xCC000000, be32_to_cpu(cmp_data[2])); + +#endif + hdr = cfg.icu_new_model_buf; + up_model_buf = (struct s_fx *)hdr->entry; + TEST_ASSERT_FALSE(memcmp(hdr, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE)); + for (i = 0; i < cfg.samples; i++) { + TEST_ASSERT_EQUAL(model[i].exp_flags, up_model_buf[i].exp_flags); + TEST_ASSERT_EQUAL(model[i].fx, up_model_buf[i].fx); + TEST_ASSERT_EQUAL(model[i].efx, up_model_buf[i].efx); + } + + + free(cfg.input_buf); + free(cfg.model_buf); + free(cfg.icu_new_model_buf); + free(cfg.icu_output_buf); +} +#endif + + +/** + * @test compress_s_fx + */ + +void test_compress_s_fx_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_exp_flags = 6; + uint32_t cmp_par_fx = 2; + uint32_t spillover_fx = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct s_fx *data_p = (struct s_fx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 21; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, + NULL, (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* test if data are higher than max used bits value */ + data_p[0].fx = 0x200000; /* has more than 21 bits (max_used_bits.s_fx) */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + /* compressed data are to small for the compressed_data buffer */ + max_used_bits.s_exp_flags = 8; + max_used_bits.s_fx= 32; + cmp_set_max_used_bits(&max_used_bits); + memset(data_to_compress, 0xff, sizeof(data_to_compress)); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits); + + max_used_bits.s_exp_flags = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.s_exp_flags = 32; + max_used_bits.s_fx= 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_s_fx_efx + */ + +void test_compress_s_fx_efx_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = 2; + uint32_t spillover_exp_flags = 6; + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_efx = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_efx = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+2*sizeof(struct s_fx_efx)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx_efx)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct s_fx_efx *data_p= (struct s_fx_efx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 21; + max_used_bits.s_efx = 16; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, cmp_par_efx, spillover_efx, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 2, NULL, + NULL, (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* test if data are higher than max used bits value */ + data_p[0].exp_flags = 0x4; /* has more than 2 bits (max_used_bits.s_exp_flags) */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].exp_flags = 0x3; + data_p[1].fx = 0x200000; /* has more than 21 bits (max_used_bits.fx) */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].fx = 0x1FFFFF; + data_p[1].efx = 0x100000; /* has more than 16 bits (max_used_bits.efx) */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + /* error case exp_flag setup */ + max_used_bits.s_exp_flags = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + /* error case fx setup */ + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + /* error case efx setup */ + max_used_bits.s_fx = 21; + max_used_bits.s_efx = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_s_fx_ncob + */ + +void test_compress_s_fx_ncob_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = 3; + uint32_t spillover_exp_flags = 6; + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_ncob = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_ncob = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_ncob)] = {0}; + uint8_t model_data[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_ncob)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx_ncob)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct s_fx_ncob *data_p = (struct s_fx_ncob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 21; + max_used_bits.s_ncob = 31; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_NCOB, CMP_MODE_MODEL_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, model_data, + NULL, (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* the compressed_data buffer is to small */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits); + + /* test if data are higher than max used bits value */ + data_p[2].exp_flags = 0x4; /* has more than 2 bits (max_used_bits.s_exp_flags) */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].exp_flags = 0x3; + data_p[1].fx = 0x200000; /* value to high */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].fx = 0x1FFFFF; /* value to high */ + data_p[0].ncob_y = 0x80000000; /* value to high */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + data_p[0].ncob_y = 0x7FFFFFFF; /* value to high */ + + /* error case exp_flag setup */ + max_used_bits.s_exp_flags = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + /* error case fx setup */ + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + /* error case efx setup */ + max_used_bits.s_fx = 21; + max_used_bits.s_ncob = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_s_fx_efx_ncob_ecob + */ + +void test_compress_s_fx_efx_ncob_ecob_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = 3; + uint32_t spillover_exp_flags = 6; + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_ncob = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_ncob = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint32_t cmp_par_efx = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_efx = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint32_t cmp_par_ecob = 23; + uint32_t spillover_ecob = cmp_icu_max_spill(23); + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_efx_ncob_ecob)] = {0}; + uint8_t model_data[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct s_fx_efx_ncob_ecob)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct s_fx_efx_ncob_ecob)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct s_fx_efx_ncob_ecob *data_p = (struct s_fx_efx_ncob_ecob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + + max_used_bits.s_exp_flags = 2; + max_used_bits.s_fx = 21; + max_used_bits.s_ncob = 31; + max_used_bits.s_efx = 23; + max_used_bits.s_ecob = 7; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX_EFX_NCOB_ECOB, CMP_MODE_MODEL_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, + spillover_ncob, cmp_par_efx, spillover_efx, + cmp_par_ecob, spillover_ecob, CMP_PAR_UNUSED, CMP_PAR_UNUSED); + + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, model_data, + NULL, (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* the compressed_data buffer is to small */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits); + + /* test if data are higher than max used bits value */ + data_p[2].exp_flags = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].exp_flags = 0x3; + data_p[2].fx = 0x200000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].fx = 0x1FFFFF; + data_p[1].ncob_x = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].ncob_x = 0x7FFFFFFF; + data_p[1].ncob_y = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].ncob_y = 0x7FFFFFFF; + data_p[1].efx = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].efx = 0x7FFFFF; + data_p[1].ecob_y = 0x80; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + data_p[1].ecob_y = 0x7F; + + /* error case exp_flag setup */ + max_used_bits.s_exp_flags = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + /* error case fx setup */ + max_used_bits.s_exp_flags = 32; + max_used_bits.s_fx = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + /* error case efx setup */ + max_used_bits.s_fx = 32; + max_used_bits.s_ncob = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.s_ncob = 32; + max_used_bits.s_efx = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.s_efx = 32; + max_used_bits.s_ecob = 33; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + max_used_bits.s_ecob = 32; +} + + +/** + * @test compress_f_fx + */ + +void test_compress_f_fx_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_fx = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_fx = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct f_fx)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + + max_used_bits.f_fx = 23; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* compressed data are to small for the compressed_data buffer */ + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits); + + max_used_bits.f_fx= 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_f_fx_efx + */ + +void test_compress_f_fx_efx_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_efx = 1; + uint32_t spillover_efx = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+2*sizeof(struct f_fx_efx)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx_efx)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct f_fx_efx *data_p = (struct f_fx_efx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.f_fx = 23; + max_used_bits.f_efx = 31; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, cmp_par_efx, spillover_efx, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 2, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* compressed data are to small for the compressed_data buffer */ + data_p[0].fx = 42; + data_p[0].efx = 42; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits); + + /* efx value is to big for the max used bits values */ + data_p[0].efx = 0x80000000; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + data_p[0].efx = 0x7FFFFFFF; + + max_used_bits.f_fx= 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.f_fx= 32; + max_used_bits.f_efx= 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_f_fx_ncob + */ + +void test_compress_f_fx_ncob_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_fx = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_fx = 8; + uint32_t cmp_par_ncob = 1; + uint32_t spillover_ncob = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+2*sizeof(struct f_fx_ncob)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx_ncob)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct f_fx_ncob *data_p = (struct f_fx_ncob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.f_fx = 31; + max_used_bits.f_ncob = 23; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_NCOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 2, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* compressed data are to small for the compressed_data buffer */ + data_p[0].fx = 42; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_bits); + + /* value is to big for the max used bits values */ + data_p[0].ncob_x = 0x800000; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + data_p[0].ncob_x = 0x7FFFFF; + data_p[0].ncob_y = 0x800000; + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + data_p[0].ncob_y = 0x7FFFFF; + + max_used_bits.f_fx= 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.f_fx= 32; + max_used_bits.f_ncob= 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_f_fx_efx_ncob_ecob + */ + +void test_compress_f_fx_efx_ncob_ecob(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_ncob = 2; + uint32_t spillover_ncob = 10; + uint32_t cmp_par_efx = 3; + uint32_t spillover_efx = 44; + uint32_t cmp_par_ecob = 5; + uint32_t spillover_ecob = 55; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+4*sizeof(struct f_fx_efx_ncob_ecob)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct f_fx_efx_ncob_ecob)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct f_fx_efx_ncob_ecob *data_p = (struct f_fx_efx_ncob_ecob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.f_fx = 31; + max_used_bits.f_ncob = 3; + max_used_bits.f_efx = 16; + max_used_bits.f_ecob = 8; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_F_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + CMP_PAR_UNUSED, CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 4, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[3].fx = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[3].fx = 0x80000000-1; + data_p[2].ncob_x = 0x8; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].ncob_x = 0x7; + data_p[1].ncob_y = 0x8; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].ncob_y = 0x7; + data_p[0].efx = 0x10000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].efx = 0x10000-1; + data_p[2].ecob_x = 0x100; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].ecob_x = 0x100-1; + data_p[3].ecob_y = 0x100; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + data_p[3].ecob_y = 0x100-1; + + max_used_bits.f_fx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.f_fx = 32; + max_used_bits.f_ncob = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.f_ncob = 32; + max_used_bits.f_efx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.f_efx = 32; + max_used_bits.f_ecob = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_l_fx + */ + +void test_compress_l_fx_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = 3; + uint32_t spillover_exp_flags = 10; + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_fx_cob_variance = 30; + uint32_t spillover_fx_cob_variance = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct l_fx *data_p = (struct l_fx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.l_exp_flags = 23; + max_used_bits.l_fx = 31; + max_used_bits.l_efx = 1; + max_used_bits.l_fx_variance = 23; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[2].exp_flags = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].exp_flags = 0x800000-1; + data_p[2].fx = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].fx = 0x80000000-1; + data_p[0].fx_variance = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].fx_variance = 0x800000-1; + + max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_exp_flags = 32; + max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_fx = 32; + max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_l_fx_efx + */ + +void test_compress_l_fx_efx_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_efx = 3; + uint32_t spillover_efx = 44; + uint32_t cmp_par_fx_cob_variance = 30; + uint32_t spillover_fx_cob_variance = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx_efx)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx_efx)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct l_fx_efx *data_p = (struct l_fx_efx *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.l_exp_flags = 23; + max_used_bits.l_fx = 31; + max_used_bits.l_efx = 1; + max_used_bits.l_fx_variance = 23; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_efx, spillover_efx, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[2].exp_flags = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].exp_flags = 0x800000-1; + data_p[2].fx = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].fx = 0x80000000-1; + data_p[1].efx = 0x2; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].efx = 0x1; + data_p[0].fx_variance = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].fx_variance = 0x800000-1; + + max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_exp_flags = 32; + max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_fx = 32; + max_used_bits.l_efx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_efx = 32; + max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_l_fx_ncob + */ + +void test_compress_l_fx_ncob_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_ncob = 2; + uint32_t spillover_ncob = 10; + uint32_t cmp_par_fx_cob_variance = 30; + uint32_t spillover_fx_cob_variance = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx_ncob)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx_ncob)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct l_fx_ncob *data_p = (struct l_fx_ncob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.l_exp_flags = 23; + max_used_bits.l_fx = 31; + max_used_bits.l_ncob = 2; + max_used_bits.l_fx_variance = 23; + max_used_bits.l_cob_variance = 11; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_NCOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[2].exp_flags = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].exp_flags = 0x800000-1; + data_p[2].fx = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].fx = 0x80000000-1; + data_p[2].ncob_x = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].ncob_x = 0x3; + data_p[2].ncob_y = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].ncob_y = 0x3; + data_p[0].fx_variance = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].fx_variance = 0x800000-1; + data_p[2].cob_x_variance = 0x800; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].cob_x_variance = 0x800-1; + data_p[2].cob_y_variance = 0x800; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].cob_y_variance = 0x800-1; + + max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_exp_flags = 32; + max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_fx = 32; + max_used_bits.l_ncob = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_ncob = 32; + max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_fx_variance = 32; + max_used_bits.l_cob_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_l_fx_efx_ncob_ecob + */ + +void test_compress_l_fx_efx_ncob_ecob_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_exp_flags = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_exp_flags = cmp_icu_max_spill(cmp_par_exp_flags); + uint32_t cmp_par_fx = 1; + uint32_t spillover_fx = 8; + uint32_t cmp_par_ncob = 2; + uint32_t spillover_ncob = 10; + uint32_t cmp_par_efx = 3; + uint32_t spillover_efx = 44; + uint32_t cmp_par_ecob = 5; + uint32_t spillover_ecob = 55; + uint32_t cmp_par_fx_cob_variance = 30; + uint32_t spillover_fx_cob_variance = 8; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct l_fx_efx_ncob_ecob)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct l_fx_efx_ncob_ecob)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct l_fx_efx_ncob_ecob *data_p = (struct l_fx_efx_ncob_ecob *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.l_exp_flags = 23; + max_used_bits.l_fx = 31; + max_used_bits.l_ncob = 2; + max_used_bits.l_efx = 1; + max_used_bits.l_ecob = 3; + max_used_bits.l_fx_variance = 23; + max_used_bits.l_cob_variance = 11; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_L_FX_EFX_NCOB_ECOB, CMP_MODE_DIFF_ZERO, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_fx_cob(&cfg, cmp_par_exp_flags, spillover_exp_flags, + cmp_par_fx, spillover_fx, cmp_par_ncob, spillover_ncob, + cmp_par_efx, spillover_efx, cmp_par_ecob, spillover_ecob, + cmp_par_fx_cob_variance, spillover_fx_cob_variance); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[2].exp_flags = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].exp_flags = 0x800000-1; + data_p[2].fx = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].fx = 0x80000000-1; + data_p[2].ncob_x = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].ncob_x = 0x3; + data_p[2].ncob_y = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].ncob_y = 0x3; + data_p[1].efx = 0x2; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].efx = 0x1; + data_p[1].ecob_x = 0x8; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].ecob_x = 0x7; + data_p[1].ecob_y = 0x8; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].ecob_y = 0x7; + data_p[0].fx_variance = 0x800000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].fx_variance = 0x800000-1; + data_p[2].cob_x_variance = 0x800; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].cob_x_variance = 0x800-1; + data_p[2].cob_y_variance = 0x800; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[2].cob_y_variance = 0x800-1; + + max_used_bits.l_exp_flags = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_exp_flags = 32; + max_used_bits.l_fx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_fx = 32; + max_used_bits.l_ncob = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_ncob = 32; + max_used_bits.l_efx = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_efx = 32; + max_used_bits.l_ecob = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_ecob = 32; + max_used_bits.l_fx_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.l_fx_variance = 32; + max_used_bits.l_cob_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_nc_offset + */ + +void test_compress_nc_offset_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_mean = 1; + uint32_t spillover_mean = 2; + uint32_t cmp_par_variance = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_variance = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct nc_offset)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct nc_offset)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct nc_offset *data_p = (struct nc_offset *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.nc_offset_mean = 1; + max_used_bits.nc_offset_variance = 31; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_OFFSET, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + CMP_PAR_UNUSED, CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[0].mean = 0x2; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].mean = 0x1; + data_p[1].variance = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].variance = 0x80000000-1; + + max_used_bits.nc_offset_mean = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.nc_offset_mean = 32; + max_used_bits.nc_offset_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_nc_background + */ + +void test_compress_nc_background_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_mean = 1; + uint32_t spillover_mean = 2; + uint32_t cmp_par_variance = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_variance = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint32_t cmp_par_pixels_error = 23; + uint32_t spillover_pixels_error = 42; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct nc_background)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct nc_background)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct nc_background *data_p = (struct nc_background *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.nc_background_mean = 1; + max_used_bits.nc_background_variance = 31; + max_used_bits.nc_background_outlier_pixels = 2; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_BACKGROUND, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[0].mean = 0x2; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].mean = 0x1; + data_p[1].variance = 0x80000000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].variance = 0x80000000-1; + data_p[1].outlier_pixels = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].outlier_pixels = 0x3; + + max_used_bits.nc_background_mean = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.nc_background_mean = 32; + max_used_bits.nc_background_variance = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.nc_background_variance = 32; + max_used_bits.nc_background_outlier_pixels = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test compress_smearing + */ + +void test_compress_smearing_error_cases(void) +{ + int error, cmp_bits, compressed_data_size; + struct cmp_cfg cfg = {0}; + uint32_t cmp_par_mean = 1; + uint32_t spillover_mean = 2; + uint32_t cmp_par_variance = MAX_ICU_GOLOMB_PAR; + uint32_t spillover_variance = cmp_icu_max_spill(MAX_ICU_GOLOMB_PAR); + uint32_t cmp_par_pixels_error = 23; + uint32_t spillover_pixels_error = 42; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE+3*sizeof(struct smearing)] = {0}; + uint8_t compressed_data[MULTI_ENTRY_HDR_SIZE+1*sizeof(struct smearing)] = {0}; + struct cmp_max_used_bits max_used_bits = {0}; + struct smearing *data_p = (struct smearing *)&data_to_compress[MULTI_ENTRY_HDR_SIZE]; + + max_used_bits.smearing_mean = 1; + max_used_bits.smearing_variance_mean = 15; + max_used_bits.smearing_outlier_pixels = 2; + cmp_set_max_used_bits(&max_used_bits); + + cfg = cmp_cfg_icu_create(DATA_TYPE_SMEARING, CMP_MODE_DIFF_MULTI, 0, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + error = cmp_cfg_aux(&cfg, cmp_par_mean, spillover_mean, + cmp_par_variance, spillover_variance, + cmp_par_pixels_error, spillover_pixels_error); + TEST_ASSERT_FALSE(error); + + compressed_data_size = cmp_cfg_icu_buffers(&cfg, data_to_compress, 3, NULL, NULL, + (uint32_t *)compressed_data, 1); + TEST_ASSERT_EQUAL_INT(sizeof(compressed_data), compressed_data_size); + + /* value is to big for the max used bits values */ + data_p[0].mean = 0x2; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[0].mean = 0x1; + data_p[1].variance_mean = 0x8000; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].variance_mean = 0x8000-1; + data_p[1].outlier_pixels = 0x4; + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_HIGH_VALUE, cmp_bits); + + data_p[1].outlier_pixels = 0x3; + + max_used_bits.smearing_mean = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.smearing_mean = 32; + max_used_bits.smearing_variance_mean = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); + + max_used_bits.smearing_variance_mean = 32; + max_used_bits.smearing_outlier_pixels = 33; /* more than 32 bits are not allowed */ + cmp_set_max_used_bits(&max_used_bits); + cmp_bits = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(-1, cmp_bits); +} + + +/** + * @test pad_bitstream + */ + +void test_pad_bitstream(void) +{ + struct cmp_cfg cfg = {0}; + int cmp_size; + int cmp_size_return; + uint32_t cmp_data[3]; + const int MAX_BIT_LEN = 96; + + memset(cmp_data, 0xFF, sizeof(cmp_data)); + cfg.icu_output_buf = cmp_data; + cfg.data_type = DATA_TYPE_IMAGETTE; /* 16 bit samples */ + cfg.buffer_length = 6; /* 6 * 16 bit samples -> 3 * 32 bit */ + + /* test negative cmp_size */ + cmp_size = -1; + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(-1, cmp_size_return); + cmp_size = -3; + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(-3, cmp_size_return); + + /* test RAW_MODE */ + cfg.cmp_mode = CMP_MODE_RAW; + cmp_size = MAX_BIT_LEN; + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(MAX_BIT_LEN, cmp_size_return); + TEST_ASSERT_EQUAL_INT(cmp_data[0], 0xFFFFFFFF); + TEST_ASSERT_EQUAL_INT(cmp_data[1], 0xFFFFFFFF); + TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF); + + /* test Normal operation */ + cfg.cmp_mode = CMP_MODE_MODEL_MULTI; + cmp_size = 0; + /* set the first 32 bits zero no change should occur */ + cmp_size = put_n_bits32(0, 32, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN); + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size, cmp_size_return); + TEST_ASSERT_EQUAL_INT(cmp_data[0], 0); + TEST_ASSERT_EQUAL_INT(cmp_data[1], 0xFFFFFFFF); + TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF); + + /* set the first 33 bits zero; and checks the padding */ + cmp_size = put_n_bits32(0, 1, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN); + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size, cmp_size_return); + TEST_ASSERT_EQUAL_INT(cmp_data[0], 0); + TEST_ASSERT_EQUAL_INT(cmp_data[1], 0); + TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF); + + /* set the first 63 bits zero; and checks the padding */ + cmp_data[1] = 0xFFFFFFFF; + cmp_size = 32; + cmp_size = put_n_bits32(0, 31, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN); + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size, cmp_size_return); + TEST_ASSERT_EQUAL_INT(cmp_data[0], 0); + TEST_ASSERT_EQUAL_INT(cmp_data[1], 0); + TEST_ASSERT_EQUAL_INT(cmp_data[2], 0xFFFFFFFF); + + /* error case the rest of the compressed data are to small dor a 32 bit + * access */ + cfg.buffer_length = 5; + cmp_size = 64; + cmp_size = put_n_bits32(0, 1, cmp_size, cfg.icu_output_buf, MAX_BIT_LEN); + cmp_size_return = pad_bitstream(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF, cmp_size_return); +} + + +/** + * @test cmp_data_to_big_endian + */ + +void test_cmp_data_to_big_endian_error_cases(void) +{ + struct cmp_cfg cfg = {0}; + int cmp_size; + int cmp_size_return; + uint16_t cmp_data[3] = {0x0123, 0x4567, 0x89AB}; + uint8_t *p; + + cfg.icu_output_buf = (uint32_t *)cmp_data; + + /* this should work */ + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_RAW; + cmp_size = 48; + cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size_return, 48); + p = (uint8_t *)cfg.icu_output_buf; + TEST_ASSERT_EQUAL(p[0], 0x01); + TEST_ASSERT_EQUAL(p[1], 0x23); + TEST_ASSERT_EQUAL(p[2], 0x45); + TEST_ASSERT_EQUAL(p[3], 0x67); + TEST_ASSERT_EQUAL(p[4], 0x89); + TEST_ASSERT_EQUAL(p[5], 0xAB); + + /* error cases */ + cmp_data[0] = 0x0123; + cmp_data[1] = 0x4567; + cmp_data[2] = 0x89AB; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_RAW; + cmp_size = 47; /* wrong size */ + cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size_return, -1); + + cmp_data[0] = 0x0123; + cmp_data[1] = 0x4567; + cmp_data[2] = 0x89AB; + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_RAW; + cmp_size = 49; /* wrong size */ + cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size_return, -1); + + cmp_data[0] = 0x0123; + cmp_data[1] = 0x4567; + cmp_data[2] = 0x89AB; + cfg.data_type = DATA_TYPE_UNKNOWN; /* wrong data_type */ + cfg.cmp_mode = CMP_MODE_RAW; + cmp_size = 48; + cmp_size_return = cmp_data_to_big_endian(&cfg, cmp_size); + TEST_ASSERT_EQUAL_INT(cmp_size_return, -1); +} + + +/** + * @test icu_compress_data + */ + +void test_icu_compress_data_error_cases(void) +{ + int cmp_size; + struct cmp_cfg cfg = {0}; + + /* cfg = NULL test */ + cmp_size = icu_compress_data(NULL); + TEST_ASSERT_EQUAL(-1, cmp_size); + + /* samples = 0 test */ + cfg.samples = 0; + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL(0, cmp_size); +} + diff --git a/test/cmp_icu/test_decmp.c b/test/cmp_icu/test_decmp.c new file mode 100644 index 0000000000000000000000000000000000000000..6f2fe2df2451f456793b1017b548ce04ed01950c --- /dev/null +++ b/test/cmp_icu/test_decmp.c @@ -0,0 +1,826 @@ +#include <string.h> +#include <stdlib.h> + +#include "unity.h" + +#include "compiler.h" +#include "cmp_debug.h" +#include "cmp_entity.h" +#include "../../lib/cmp_icu.c" /* .c file included to test static functions */ +#include "../../lib/decmp.c" /* .c file included to test static functions */ + + +#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12)) +#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX) + + +/** + * @brief generate a uint32_t random number + * + * @return a "random" uint32_t value + * @see https://stackoverflow.com/a/33021408 + */ + +uint32_t rand32(void) +{ + int i; + uint32_t r = 0; + + for (i = 0; i < 32; i += RAND_MAX_WIDTH) { + r <<= RAND_MAX_WIDTH; + r ^= (unsigned int) rand(); + } + return r; +} + + +/** + * returns the needed size of the compression entry header plus the max size of the + * compressed data if ent == NULL if ent is set the size of the compression + * entry (entity header + compressed data) + */ +size_t icu_compress_data_entity(struct cmp_entity *ent, const struct cmp_cfg *cfg) +{ + size_t s; + struct cmp_cfg cfg_cpy; + int cmp_size_bits; + + if (!cfg) + return 0; + + if (cfg->icu_output_buf) + debug_print("Warning the set buffer for the compressed data is ignored! The compressed data are write to the compression entry."); + + s = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type); + if (!s) + return 0; + /* we round down to the next 4-byte allied address because we access the + * cmp_buffer in uint32_t words + */ + if (cfg->cmp_mode != CMP_MODE_RAW) + s &= ~0x3U; + + s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, s); + + if (!ent || !s) + return s; + + cfg_cpy = *cfg; + cfg_cpy.icu_output_buf = cmp_ent_get_data_buf(ent); + if (!cfg_cpy.icu_output_buf) + return 0; + cmp_size_bits = icu_compress_data(&cfg_cpy); + if (cmp_size_bits < 0) + return 0; + + /* XXX overwrite the size of the compression entity with the size of the actual + * size of the compressed data; not all allocated memory is normally used */ + s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, + cmp_bit_to_4byte(cmp_size_bits)); + + if (cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits)) + return 0; + + + return s; +} + + +void test_cmp_decmp_n_imagette_raw(void) +{ + int cmp_size; + size_t s, i; + struct cmp_cfg cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 0, CMP_LOSSLESS); + uint16_t data[] = {0, 1, 2, 0x42, INT16_MIN, INT16_MAX, UINT16_MAX}; + uint32_t *compressed_data; + uint16_t *decompressed_data; + struct cmp_entity *ent; + + s = cmp_cfg_icu_buffers(&cfg, data, ARRAY_SIZE(data), NULL, NULL, + NULL, ARRAY_SIZE(data)); + TEST_ASSERT_TRUE(s); + compressed_data = malloc(s); + TEST_ASSERT_TRUE(compressed_data); + s = cmp_cfg_icu_buffers(&cfg, data, ARRAY_SIZE(data), NULL, NULL, + compressed_data, ARRAY_SIZE(data)); + TEST_ASSERT_TRUE(s); + + cmp_size = icu_compress_data(&cfg); + TEST_ASSERT_EQUAL_INT(sizeof(data)*CHAR_BIT, cmp_size); + + s = cmp_ent_build(NULL, 0, 0, 0, 0, 0, &cfg, cmp_bit_to_4byte(cmp_size)); + TEST_ASSERT_TRUE(s); + ent = malloc(s); + TEST_ASSERT_TRUE(ent); + s = cmp_ent_build(ent, 0, 0, 0, 0, 0, &cfg, cmp_bit_to_4byte(cmp_size)); + TEST_ASSERT_TRUE(s); + memcpy(cmp_ent_get_data_buf(ent), compressed_data, (cmp_size+7)/8); + + s = decompress_cmp_entiy(ent, NULL, NULL, NULL); + TEST_ASSERT_EQUAL_INT(sizeof(data), s); + decompressed_data = malloc(s); + TEST_ASSERT_TRUE(decompressed_data); + s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data); + TEST_ASSERT_EQUAL_INT(sizeof(data), s); + + for (i = 0; i < ARRAY_SIZE(data); ++i) { + TEST_ASSERT_EQUAL_INT(data[i], decompressed_data[i]); + + } + + free(compressed_data); + free(ent); + free(decompressed_data); +} + + +/** + * @test count_leading_ones + */ + +void test_count_leading_ones(void) +{ + unsigned int n_leading_bit; + uint32_t value; + + value = 0; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(0, n_leading_bit); + + value = 0x7FFFFFFF; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(0, n_leading_bit); + + value = 0x80000000; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(1, n_leading_bit); + + value = 0xBFFFFFFF; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(1, n_leading_bit); + + value = 0xFFFF0000; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(16, n_leading_bit); + + value = 0xFFFF7FFF; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(16, n_leading_bit); + + value = 0xFFFFFFFF; + n_leading_bit = count_leading_ones(value); + TEST_ASSERT_EQUAL_INT(32, n_leading_bit); +} + + +/** + * @test rice_decoder + */ + +void test_rice_decoder(void) +{ + int cw_len; + uint32_t code_word; + unsigned int m = ~0; /* we don't need this value */ + unsigned int log2_m; + unsigned int decoded_cw; + + /* test log_2 to big */ + code_word = 0xE0000000; + log2_m = 33; + cw_len = rice_decoder(code_word, m, log2_m, &decoded_cw); + TEST_ASSERT_EQUAL(0, cw_len); + log2_m = UINT_MAX; + cw_len = rice_decoder(code_word, m, log2_m, &decoded_cw); + TEST_ASSERT_EQUAL(0, cw_len); +} + + +/** + * @test re_map_to_pos + */ + +void test_re_map_to_pos(void) +{ + int j; + uint32_t input, result; + unsigned int max_value_bits; + + input = INT32_MIN; + result = re_map_to_pos(map_to_pos(input, 32)); + TEST_ASSERT_EQUAL_INT32(input, result); + + input = INT32_MAX; + result = re_map_to_pos(map_to_pos(input, 32)); + TEST_ASSERT_EQUAL_INT32(input, result); + + input = -1; + result = re_map_to_pos(map_to_pos(input, 32)); + TEST_ASSERT_EQUAL_INT32(input, result); + + input = 0; + result = re_map_to_pos(map_to_pos(input, 32)); + TEST_ASSERT_EQUAL_INT32(input, result); + + input = 1; max_value_bits = 6; + result = re_map_to_pos(map_to_pos(input, max_value_bits)); + TEST_ASSERT_EQUAL_INT32(input, result); + + for (j = -16; j < 15; j++) { + uint32_t map_val = map_to_pos(j, 16) & 0x3F; + result = re_map_to_pos(map_val); + TEST_ASSERT_EQUAL_INT32(j, result); + } + + for (j = INT16_MIN; j < INT16_MAX; j++) { + uint32_t map_val = map_to_pos(j, 16) & 0xFFFF; + result = re_map_to_pos(map_val); + TEST_ASSERT_EQUAL_INT32(j, result); + } +#if 0 + for (j = INT32_MIN; j < INT32_MAX; j++) { + result = re_map_to_pos(map_to_pos(j, 32)); + TEST_ASSERT_EQUAL_INT32(j, result); + } +#endif +} + + +void test_decode_normal(void) +{ + uint32_t decoded_value = ~0; + int stream_pos, sample; + /* compressed data from 0 to 6; */ + uint32_t cmp_data[] = {0x5BBDF7E0}; + struct decoder_setup setup = {0}; + + cpu_to_be32s(cmp_data); + + setup.decode_cw_f = rice_decoder; + setup.encoder_par1 = 1; + setup.encoder_par2 = ilog_2(setup.encoder_par1); + setup.bitstream_adr = cmp_data; + setup.max_stream_len = 32; + + stream_pos = 0; + for (sample = 0; sample < 7; sample++) { + stream_pos = decode_normal(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(sample, decoded_value); + } + + /* TODO error case: negative stream_pos */ +} + + +void test_decode_zero(void) +{ + uint32_t decoded_value = ~0; + int stream_pos; + uint32_t cmp_data[] = {0x88449FE0}; + struct decoder_setup setup = {0}; + struct cmp_cfg cfg = {0}; + + cpu_to_be32s(cmp_data); + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_ZERO; + cfg.icu_output_buf = cmp_data; + cfg.buffer_length = 4; + + int err = configure_decoder_setup(&setup, 1, 8, CMP_LOSSLESS, 16, &cfg); + TEST_ASSERT_FALSE(err); + + stream_pos = 0; + + stream_pos = decode_zero(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(0, decoded_value); + stream_pos = decode_zero(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(0x4223, decoded_value); + stream_pos = decode_zero(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(7, decoded_value); + TEST_ASSERT_EQUAL_INT(28, stream_pos); + + /* TODO error case: negativ stream_pos */ +} + +void test_decode_multi(void) +{ + uint32_t decoded_value = ~0; + int stream_pos; + uint32_t cmp_data[] = {0x16B66DF8, 0x84360000}; + struct decoder_setup setup = {0}; + struct cmp_cfg cfg = {0}; + + cpu_to_be32s(&cmp_data[0]); + cpu_to_be32s(&cmp_data[1]); + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_DIFF_MULTI; + cfg.icu_output_buf = cmp_data; + cfg.buffer_length = 8; + + int err = configure_decoder_setup(&setup, 3, 8, CMP_LOSSLESS, 16, &cfg); + TEST_ASSERT_FALSE(err); + + stream_pos = 0; + + stream_pos = decode_multi(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(0, decoded_value); + stream_pos = decode_multi(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(1, decoded_value); + stream_pos = decode_multi(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(7, decoded_value); + stream_pos = decode_multi(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(8, decoded_value); + stream_pos = decode_multi(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(9, decoded_value); + stream_pos = decode_multi(&decoded_value, stream_pos, &setup); + TEST_ASSERT_EQUAL_HEX(0x4223, decoded_value); + TEST_ASSERT_EQUAL_INT(47, stream_pos); + +} + + +void test_decompress_imagette_model(void) +{ + uint16_t data[5] = {0}; + uint16_t model[5] = {0, 1, 2, 3, 4}; + uint16_t up_model[5] = {0}; + uint32_t cmp_data[] = {0}; + struct cmp_cfg cfg = {0}; + int stream_pos; + + cmp_data[0] = cpu_to_be32(0x49240000); + + cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.cmp_mode = CMP_MODE_MODEL_MULTI; + cfg.input_buf = data; + cfg.model_buf = model; + cfg.icu_new_model_buf = up_model; + cfg.icu_output_buf = cmp_data; + cfg.buffer_length = 4; + cfg.samples = 5; + cfg.model_value = 16; + cfg.golomb_par = 4; + cfg.spill = 48; + + stream_pos = decompress_imagette(&cfg); + TEST_ASSERT_EQUAL_INT(15, stream_pos); + TEST_ASSERT_EQUAL_HEX(1, data[0]); + TEST_ASSERT_EQUAL_HEX(2, data[1]); + TEST_ASSERT_EQUAL_HEX(3, data[2]); + TEST_ASSERT_EQUAL_HEX(4, data[3]); + TEST_ASSERT_EQUAL_HEX(5, data[4]); + + TEST_ASSERT_EQUAL_HEX(0, up_model[0]); + TEST_ASSERT_EQUAL_HEX(1, up_model[1]); + TEST_ASSERT_EQUAL_HEX(2, up_model[2]); + TEST_ASSERT_EQUAL_HEX(3, up_model[3]); + TEST_ASSERT_EQUAL_HEX(4, up_model[4]); +} + + + +#define DATA_SAMPLES 5 +void test_cmp_decmp_s_fx_diff(void) +{ + size_t s; + int err; + + struct cmp_entity *ent; + const uint32_t MAX_VALUE = ~(~0U << MAX_USED_S_FX_BITS); + struct s_fx data_entry[DATA_SAMPLES] = { + {0,0}, {1,23}, {2,42}, {3,MAX_VALUE}, {3,MAX_VALUE>>1} }; + uint8_t data_to_compress[MULTI_ENTRY_HDR_SIZE + sizeof(data_entry)]; + struct s_fx *decompressed_data = NULL; + /* uint32_t *compressed_data = NULL; */ + uint32_t compressed_data_len_samples = DATA_SAMPLES; + struct cmp_cfg cfg; + + for (s = 0; s < MULTI_ENTRY_HDR_SIZE; s++) + data_to_compress[s] = s; + memcpy(&data_to_compress[MULTI_ENTRY_HDR_SIZE], data_entry, sizeof(data_entry)); + + cfg = cmp_cfg_icu_create(DATA_TYPE_S_FX, CMP_MODE_DIFF_MULTI, + CMP_PAR_UNUSED, CMP_LOSSLESS); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + s = cmp_cfg_icu_buffers(&cfg, data_to_compress, DATA_SAMPLES, NULL, NULL, + NULL, compressed_data_len_samples); + TEST_ASSERT_TRUE(s); + + err = cmp_cfg_fx_cob(&cfg, 2, 6, 4, 14, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED, + CMP_PAR_UNUSED, CMP_PAR_UNUSED, CMP_PAR_UNUSED); + TEST_ASSERT_FALSE(err); + + s = icu_compress_data_entity(NULL, &cfg); + TEST_ASSERT_TRUE(s); + ent = malloc(s); TEST_ASSERT_TRUE(ent); + s = icu_compress_data_entity(ent, &cfg); + TEST_ASSERT_TRUE(s); + + /* now decompress the data */ + s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data); + TEST_ASSERT_EQUAL_INT(cmp_cal_size_of_data(cfg.samples, cfg.data_type), s); + decompressed_data = malloc(s); TEST_ASSERT_TRUE(decompressed_data); + s = decompress_cmp_entiy(ent, NULL, NULL, decompressed_data); + TEST_ASSERT_EQUAL_INT(cmp_cal_size_of_data(cfg.samples, cfg.data_type), s); + + TEST_ASSERT_FALSE(memcmp(data_to_compress, decompressed_data, s)); + /* for (i = 0; i < samples; ++i) { */ + /* printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round); */ + /* uint32_t mask = ~0U << round; */ + /* if ((data[i]&mask) != (decompressed_data[i]&mask)) */ + /* TEST_ASSERT(0); */ + /* if (model_mode_is_used(cmp_mode)) */ + /* if (up_model[i] != de_up_model[i]) */ + /* TEST_ASSERT(0); */ + /* } */ +} +#undef DATA_SAMPLES + + +int my_random(unsigned int min, unsigned int max) +{ + TEST_ASSERT(min < max); + if (max-min < RAND_MAX) + return min + rand() / (RAND_MAX / (max - min + 1ULL) + 1); + else + return min + rand32() / (UINT32_MAX / (max - min + 1ULL) + 1); + +} + +/* #include <cmp_io.h> */ +/* void test_imagette_1(void) */ +/* { */ +/* size_t i; */ + +/* enum cmp_mode cmp_mode = 1; */ +/* uint16_t model_value = 10; */ +/* struct cmp_cfg cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, cmp_mode, model_value, CMP_LOSSLESS); */ +/* unsigned int samples = 1; */ +/* uint16_t data[1] = {0x8000}; */ +/* uint16_t model[1] = {0}; */ +/* uint16_t up_model[1] = {0}; */ +/* uint16_t de_up_model[1] = {0}; */ +/* uint32_t compressed_data[1]; */ + +/* size_t s = cmp_cfg_buffers(&cfg, data, samples, model, up_model, */ +/* compressed_data, 2*samples); */ +/* TEST_ASSERT(s > 0); */ + +/* uint32_t golomb_par = 9; */ +/* uint32_t spill = 44; */ + +/* cfg.spill = spill; */ +/* cfg.golomb_par = golomb_par; */ +/* /1* print_cfg(&cfg, 0); *1/ */ +/* int cmp_size = icu_compress_data(&cfg, NULL); */ +/* TEST_ASSERT(cmp_size > 0); */ + + +/* s = cmp_ent_build(NULL, 0, 0, 0, 0, 0, &cfg, cmp_size); */ +/* TEST_ASSERT_TRUE(s); */ +/* struct cmp_entity *ent = malloc(s); */ +/* TEST_ASSERT_TRUE(ent); */ +/* s = cmp_ent_build(ent, 0, 0, 0, 0, 0, &cfg, cmp_size); */ +/* TEST_ASSERT_TRUE(s); */ +/* memcpy(cmp_ent_get_data_buf(ent), compressed_data, cmp_bit_to_4byte(cmp_size)); */ + +/* s = decompress_cmp_entiy(ent, model, de_up_model, NULL); */ +/* TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s); */ +/* uint16_t *decompressed_data = malloc(s); */ +/* TEST_ASSERT_TRUE(decompressed_data); */ +/* s = decompress_cmp_entiy(ent, model, de_up_model, decompressed_data); */ +/* TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s); */ + +/* for (i = 0; i < samples; ++i) { */ +/* if (data[i] != decompressed_data[i]) */ +/* TEST_ASSERT(0); */ +/* /1* TEST_ASSERT_EQUAL_HEX16(data[i], decompressed_data[i]); *1/ */ +/* /1* TEST_ASSERT_EQUAL_HEX16(up_model[i], de_up_model[i]); *1/ */ +/* } */ + + +/* free(ent); */ +/* free(decompressed_data); */ +/* } */ + +#include <unistd.h> +#include "cmp_io.h" + +void test_imagette_random(void) +{ + unsigned int seed = time(NULL) * getpid(); + size_t i, s, cmp_data_size; + int error; + struct cmp_cfg cfg; + struct cmp_entity *ent; + + enum cmp_mode cmp_mode = my_random(0, 4); + enum cmp_data_type data_type = DATA_TYPE_IMAGETTE; + uint16_t model_value = my_random(0, MAX_MODEL_VALUE); + uint32_t round = my_random(0, 3); + uint32_t samples, compressed_data_len_samples; + uint16_t *data, *model = NULL, *up_model = NULL, *de_up_model = NULL; + + /* Seeds the pseudo-random number generator used by rand() */ + srand(seed); + printf("seed: %u\n", seed); + + /* create random test _data */ + samples = my_random(1, 100000); + s = cmp_cal_size_of_data(samples, data_type); + data = malloc(s); TEST_ASSERT_TRUE(data); + for (i = 0; i < samples; ++i) { + data[i] = my_random(0, UINT16_MAX); + } + if (model_mode_is_used(cmp_mode)) { + model = malloc(s); TEST_ASSERT_TRUE(model); + up_model = malloc(s); TEST_ASSERT_TRUE(up_model); + de_up_model = malloc(s); TEST_ASSERT(de_up_model); + for (i = 0; i < samples; ++i) { + model[i] = my_random(0, UINT16_MAX); + } + } + compressed_data_len_samples = 6*samples; + + /* create a compression configuration */ + cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value, round); + TEST_ASSERT(cfg.data_type != DATA_TYPE_UNKNOWN); + + + cmp_data_size = cmp_cfg_icu_buffers(&cfg, data, samples, model, up_model, + NULL, compressed_data_len_samples); + TEST_ASSERT_TRUE(cmp_data_size); + + uint32_t golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + uint32_t max_spill = cmp_ima_max_spill(golomb_par); + TEST_ASSERT(max_spill > 1); + uint32_t spill = my_random(2, max_spill); + + error = cmp_cfg_icu_imagette(&cfg, golomb_par, spill); + TEST_ASSERT_FALSE(error); + + /* print_cfg(&cfg, 0); */ + s = icu_compress_data_entity(NULL, &cfg); + TEST_ASSERT_TRUE(s); + ent = malloc(s); TEST_ASSERT_TRUE(ent); + s = icu_compress_data_entity(ent, &cfg); + TEST_ASSERT_TRUE(s); + + s = decompress_cmp_entiy(ent, model, de_up_model, NULL); + TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s); + uint16_t *decompressed_data = malloc(s); + TEST_ASSERT_TRUE(decompressed_data); + s = decompress_cmp_entiy(ent, model, de_up_model, decompressed_data); + TEST_ASSERT_EQUAL_INT(samples * sizeof(*data), s); + + for (i = 0; i < samples; ++i) { + /* printf("%u == %u (round: %u)\n", data[i], decompressed_data[i], round); */ + uint32_t mask = ~0U << round; + if ((data[i]&mask) != (decompressed_data[i]&mask)) + TEST_ASSERT(0); + if (model_mode_is_used(cmp_mode)) + if (up_model[i] != de_up_model[i]) + TEST_ASSERT(0); + } + + free(data); + free(model); + free(up_model); + free(de_up_model); + free(ent); + free(decompressed_data); +} + + +void test_s_fx_diff(void) +{ + size_t s, i; + uint8_t cmp_entity[88] = { + 0x80, 0x00, 0x00, 0x09, 0x00, 0x00, 0x58, 0x00, 0x00, 0x20, 0x04, 0xEE, 0x21, 0xBD, 0xB0, 0x1C, 0x04, 0xEE, 0x21, 0xBD, 0xB0, 0x41, 0x00, 0x08, 0x02, 0x08, 0xD0, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0xAE, 0xDE, 0x00, 0x00, 0x00, 0x73, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, + }; + + uint8_t result_data[32] = {0}; + struct multi_entry_hdr *hdr = (struct multi_entry_hdr *)result_data; + struct s_fx *data = (struct s_fx *)hdr->entry; + /* put some dummy data in the header*/ + for (i = 0; i < sizeof(*hdr); ++i) + result_data[i] = i; + data[0].exp_flags = 0; + data[0].fx = 0; + data[1].exp_flags = 1; + data[1].fx = 0xFFFFFF; + data[2].exp_flags = 3; + data[2].fx = 0x7FFFFF; + data[3].exp_flags = 0; + data[3].fx = 0; + + s = decompress_cmp_entiy((void *)cmp_entity, NULL, NULL, NULL); + TEST_ASSERT_EQUAL_INT(sizeof(result_data), s); + uint8_t *decompressed_data = malloc(s); + TEST_ASSERT_TRUE(decompressed_data); + s = decompress_cmp_entiy((void *)cmp_entity, NULL, NULL, decompressed_data); + TEST_ASSERT_EQUAL_INT(sizeof(result_data), s); + for (i = 0; i < s; ++i) { + TEST_ASSERT_EQUAL(result_data[i], decompressed_data[i]); + } +} + + +void test_s_fx_model(void) +{ + size_t s, i; + uint8_t compressed_data_buf[92] = { + 0x80, 0x00, 0x00, 0x09, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x20, 0x04, 0xF0, 0xC2, 0xD3, 0x47, 0xE4, 0x04, 0xF0, 0xC2, 0xD3, 0x48, 0x16, 0x00, 0x08, 0x03, 0x08, 0xD0, 0x10, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x3B, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x5B, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0x5D, 0x80, 0x00, 0x00, + }; + struct cmp_entity * cmp_entity = (struct cmp_entity *)compressed_data_buf; + + uint8_t model_buf[32]; + uint8_t decompressed_data[32]; + uint8_t up_model_buf[32]; + uint8_t exp_data_buf[32] = {0}; /* expected uncompressed data */ + uint8_t exp_up_model_buf[32] = {0}; + + struct multi_entry_hdr *model_collection = (struct multi_entry_hdr *)model_buf; + struct s_fx *model_data = (struct s_fx *)model_collection->entry; + + memset(model_collection, 0xFF, sizeof(*model_collection)); + model_data[0].exp_flags = 0; + model_data[0].fx = 0; + model_data[1].exp_flags = 3; + model_data[1].fx = 0x7FFFFF; + model_data[2].exp_flags = 0; + model_data[2].fx = 0xFFFFFF; + model_data[3].exp_flags = 3; + model_data[3].fx = 0xFFFFFF; + + struct multi_entry_hdr *exp_data_collection = (struct multi_entry_hdr *)exp_data_buf; + struct s_fx *exp_data = (struct s_fx *)exp_data_collection->entry; + /* put some dummy data in the header */ + for (i = 0; i < sizeof(*exp_data_collection); i++) + exp_data_buf[i] = i; + exp_data[0].exp_flags = 0; + exp_data[0].fx = 0; + exp_data[1].exp_flags = 1; + exp_data[1].fx = 0xFFFFFF; + exp_data[2].exp_flags = 3; + exp_data[2].fx = 0x7FFFFF; + exp_data[3].exp_flags = 0; + exp_data[3].fx = 0; + + struct multi_entry_hdr *exp_up_model_collection = (struct multi_entry_hdr *)exp_up_model_buf; + struct s_fx *exp_updated_model_data = (struct s_fx *)exp_up_model_collection->entry; + /* put some dummy data in the header*/ + for (i = 0; i < sizeof(*exp_up_model_collection); i++) + exp_up_model_buf[i] = i; + exp_updated_model_data[0].exp_flags = 0; + exp_updated_model_data[0].fx = 0; + exp_updated_model_data[1].exp_flags = 2; + exp_updated_model_data[1].fx = 0xBFFFFF; + exp_updated_model_data[2].exp_flags = 1; + exp_updated_model_data[2].fx = 0xBFFFFF; + exp_updated_model_data[3].exp_flags = 1; + exp_updated_model_data[3].fx = 0x7FFFFF; + + s = decompress_cmp_entiy(cmp_entity, model_buf, up_model_buf, decompressed_data); + TEST_ASSERT_EQUAL_INT(sizeof(exp_data_buf), s); + + TEST_ASSERT_FALSE(memcmp(exp_data_buf, decompressed_data, s)); + TEST_ASSERT_FALSE(memcmp(exp_up_model_buf, up_model_buf, s)); +} + +/* TODO: implement this! */ +void generate_random_test_data(void *data, int samples, + enum cmp_data_type data_type) +{ + int s = cmp_cal_size_of_data(samples, data_type); + memset(data, 0x0, s); +} + + +void test_random_compression_decompression(void) +{ + size_t s; + struct cmp_cfg cfg = {0}; + struct cmp_entity *cmp_ent; + void *decompressed_data; + void *decompressed_up_model = NULL; + + srand(0); /* TODO:XXX*/ + puts("--------------------------------------------------------------"); + + /* for (cfg.data_type = DATA_TYPE_IMAGETTE; TODO:!! implement this */ + /* cfg.data_type < DATA_TYPE_F_CAM_BACKGROUND+1; cfg.data_type++) { */ + for (cfg.data_type = DATA_TYPE_IMAGETTE; + cfg.data_type < DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE+1; cfg.data_type++) { + cfg.samples = my_random(1,0x30000); + if (cfg.data_type == DATA_TYPE_OFFSET) + puts("FADF"); + + cfg.buffer_length = (CMP_ENTITY_MAX_SIZE - NON_IMAGETTE_HEADER_SIZE - MULTI_ENTRY_HDR_SIZE)/size_of_a_sample(cfg.data_type);; + s = cmp_cal_size_of_data(cfg.samples, cfg.data_type); + printf("%s\n", data_type2string(cfg.data_type)); + TEST_ASSERT_TRUE(s); + cfg.input_buf = calloc(1, s); + TEST_ASSERT_NOT_NULL(cfg.input_buf); + cfg.model_buf = calloc(1, s); + TEST_ASSERT_TRUE(cfg.model_buf); + decompressed_data = calloc(1, s); + TEST_ASSERT_NOT_NULL(decompressed_data); + cfg.icu_new_model_buf = calloc(1, s); + TEST_ASSERT_TRUE(cfg.icu_new_model_buf); + decompressed_up_model = calloc(1, s); + TEST_ASSERT_TRUE(decompressed_up_model); + cmp_ent = calloc(1, CMP_ENTITY_MAX_SIZE); + + generate_random_test_data(cfg.input_buf, cfg.samples, cfg.data_type); + generate_random_test_data(cfg.model_buf, cfg.samples, cfg.data_type); + + cfg.model_value = my_random(0,16); + /* cfg.round = my_random(0,3); /1* XXX *1/ */ + cfg.round = 0; + + cfg.golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg.ap1_golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg.ap2_golomb_par = my_random(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR); + cfg.cmp_par_exp_flags = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_fx = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_ncob = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_efx = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_ecob = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_fx_cob_variance = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_mean = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_variance = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg.cmp_par_pixels_error = my_random(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + + cfg.spill = my_random(MIN_IMA_SPILL, cmp_ima_max_spill(cfg.golomb_par)); + cfg.ap1_spill = my_random(MIN_IMA_SPILL, cmp_ima_max_spill(cfg.ap1_golomb_par)); + cfg.ap2_spill = my_random(MIN_IMA_SPILL, cmp_ima_max_spill(cfg.ap2_golomb_par)); + if (!rdcu_supported_data_type_is_used(cfg.data_type)) { + cfg.spill_exp_flags = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_exp_flags)); + cfg.spill_fx = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_fx)); + cfg.spill_ncob = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_ncob)); + cfg.spill_efx = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_efx)); + cfg.spill_ecob = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_ecob)); + cfg.spill_fx_cob_variance = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_fx_cob_variance)); + cfg.spill_mean = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_mean)); + cfg.spill_variance = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_variance)); + cfg.spill_pixels_error = my_random(MIN_ICU_SPILL, cmp_icu_max_spill(cfg.cmp_par_pixels_error)); + } + + for (cfg.cmp_mode = CMP_MODE_RAW; cfg.cmp_mode < CMP_MODE_STUFF; cfg.cmp_mode++) { + int cmp_size, decompress_size; + + cmp_size = icu_compress_data_entity(cmp_ent, &cfg); + if (cmp_size <= 0) { + printf("cmp_size: %i\n", cmp_size); + print_cfg(&cfg, 0); + } + TEST_ASSERT_GREATER_THAN(0, cmp_size); + + /* now decompress the data */ + decompress_size = decompress_cmp_entiy(cmp_ent, cfg.model_buf, + decompressed_up_model, decompressed_data); + + TEST_ASSERT_EQUAL_INT(s, decompress_size); + if (memcmp(cfg.input_buf, decompressed_data, s)) { + print_cfg(&cfg, 0); + TEST_ASSERT_FALSE(memcmp(cfg.input_buf, decompressed_data, s)); + } + if (model_mode_is_used(cfg.cmp_mode)) + TEST_ASSERT_FALSE(memcmp(cfg.icu_new_model_buf, decompressed_up_model, s)); + + memset(cmp_ent, 0, CMP_ENTITY_MAX_SIZE); + memset(decompressed_data, 0, s); + memset(decompressed_up_model, 0, s); + memset(cfg.icu_new_model_buf, 0, s); + } + + free(cfg.model_buf); + cfg.model_buf = NULL; + free(cfg.input_buf); + cfg.input_buf = NULL; + free(cfg.icu_new_model_buf); + cfg.icu_new_model_buf = NULL; + free(cmp_ent); + cmp_ent = NULL; + free(decompressed_data); + decompressed_data = NULL; + free(decompressed_up_model); + decompressed_up_model = NULL; + + } +} + +void test_decompression_error_cases(void) +{ + /* error cases model decompression without a model Buffer */ + /* error cases wrong cmp parameter; model value; usw */ +} diff --git a/test/cmp_tool/Makefile b/test/cmp_tool/Makefile deleted file mode 100644 index 543ea135a4f15e10d25440b3a7e17c9d3e1b41ff..0000000000000000000000000000000000000000 --- a/test/cmp_tool/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -CC = gcc -SOURCEDIR = -INCLUDES = -I../../include -PATH += -CFLAGS := -O0 -W -Wall -Wextra -std=gnu99 -Werror -pedantic -g3\ - -fprofile-arcs -ftest-coverage -CPPFLAGS := -D__MAIN__ $(INCLUDES) -I$(SOURCEDIR) -LDFLAGS := -lcunit -SOURCES := $(wildcard *.c) ../../lib/cmp_tool_lib.c ../../lib/cmp_guess.c\ - ../../lib/cmp_support.c ../../lib/cmp_icu.c ../../lib/cmp_data_types.c -OBJECTS := $(patsubst %.c, $(BUILDDIR)/%.o, $(subst $(SOURCEDIR)/,, $(SOURCES))) -TARGET := test_cmp_tool - - -all: $(SOURCES) - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ -o $(TARGET) - -coverage: all - ./$(TARGET) - lcov --rc lcov_branch_coverage=1 --capture --directory ./ --output-file coverage.info - genhtml --rc lcov_branch_coverage=1 --branch-coverage coverage.info --output-directory out - #firefox out/index.html - -clean: - rm -r $(TARGET) *.gcno *.gcda coverage.info out/ tmp_stderr.log diff --git a/test/cmp_tool/cmp_tool_integration_test.py b/test/cmp_tool/cmp_tool_integration_test.py old mode 100644 new mode 100755 index f5a022b3538c3e280383eb2af22368bc3201a701..7d58943afab15702f38a6142e43de20de4118b6c --- a/test/cmp_tool/cmp_tool_integration_test.py +++ b/test/cmp_tool/cmp_tool_integration_test.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 +import pytest import subprocess import shlex import sys @@ -12,6 +14,7 @@ PATH_CMP_TOOL = "./cmp_tool" EXIT_FAILURE = 1 EXIT_SUCCESS = 0 +DATA_TYPE_IMAGETTE = 1 GENERIC_HEADER_SIZE = 32 IMAGETTE_HEADER_SIZE = GENERIC_HEADER_SIZE+4 @@ -213,10 +216,7 @@ CMP_START_STR = \ """######################################################### ### PLATO Compression/Decompression Tool Version %s ### ######################################################### -Info: Note that the behaviour of the cmp_tool has changed. From now on, the compressed data will be preceded by a header by default. The old behaviour can be achieved with the --no_header option. - """ % (VERSION) -print(CMP_START_STR) CMP_START_STR_CMP = CMP_START_STR + "## Starting the compression ##\n" CMP_START_STR_DECMP = CMP_START_STR + "## Starting the decompression ##\n" @@ -277,8 +277,8 @@ def test_print_diff_cfg(): args = ['--diff_cfg', '--diff_cfg -a', '--diff_cfg --rdcu_par'] for i, arg in enumerate(args): returncode, stdout, stderr = call_cmp_tool(arg) - assert(returncode == EXIT_SUCCESS) assert(stderr == "") + assert(returncode == EXIT_SUCCESS) cfg = parse_key_value(stdout) assert(cfg['cmp_mode'] == '2') @@ -368,8 +368,8 @@ def test_compression_diff(): # generate test configuration with open(cfg_file_name, 'w', encoding='utf-8') as f: returncode, stdout, stderr = call_cmp_tool("--diff_cfg") - assert(returncode == EXIT_SUCCESS) assert(stderr == "") + assert(returncode == EXIT_SUCCESS) f.write(stdout) add_args = [" --no_header", ""] @@ -379,8 +379,8 @@ def test_compression_diff(): " -c "+cfg_file_name+" -d "+data_file_name + " -o "+output_prefix+add_arg) # check compression results - assert(returncode == EXIT_SUCCESS) assert(stderr == "") + assert(returncode == EXIT_SUCCESS) assert(stdout == CMP_START_STR_CMP + "Importing configuration file %s ... DONE\n" % (cfg_file_name) + "Importing data file %s ... \n" % (data_file_name) + @@ -410,14 +410,13 @@ def test_compression_diff(): assert(info['cmp_size'] == '20') assert(info['cmp_err'] == '0') else: - # import pdb; pdb.set_trace() header = read_in_cmp_header(f.read()) assert(header['asw_version_id']['value'] == VERSION) assert(header['cmp_ent_size']['value'] == IMAGETTE_HEADER_SIZE+4) assert(header['original_size']['value'] == 10) # todo assert(header['start_time']['value'] < cuc_timestamp(datetime.utcnow())) - #todo + # todo assert(header['end_timestamp']['value'] < cuc_timestamp(datetime.utcnow())) assert(header['data_type']['value'] == 1) assert(header['cmp_mode_used']['value'] == 2) @@ -429,7 +428,7 @@ def test_compression_diff(): assert(header['golomb_par_used']['value'] == 7) assert(header['compressed_data']['value'] == "44444000") - # decompression + # decompression if add_arg == " --no_header": returncode, stdout, stderr = call_cmp_tool( " -i "+output_prefix+".info -d "+output_prefix+".cmp -o "+output_prefix) @@ -442,8 +441,8 @@ def test_compression_diff(): "%s" % ((lambda arg : "Importing decompression information file %s.info ... DONE\n" % (output_prefix) if "--no_header" in arg else "")(add_arg)) + "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix) + - "%s" % ((lambda arg : "Parse the compression entity header ... DONE\n" - if not "--no_header" in arg else "")(add_arg)) + + # "%s" % ((lambda arg : "Parse the compression entity header ... DONE\n" + # if not "--no_header" in arg else "")(add_arg)) + "Decompress data ... DONE\n" + "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix)) @@ -460,7 +459,7 @@ def test_compression_diff(): del_file(output_prefix+'.dat') -def test_model_compression_no_header(): +def test_model_compression(): # generate test data data = '00 01 00 02 00 03 00 04 00 05 \n' model = '00 00 00 01 00 02 00 03 00 04 \n' @@ -482,62 +481,93 @@ def test_model_compression_no_header(): assert(stderr == "") cfg = parse_key_value(stdout) cfg['cmp_mode'] = 'MODE_MODEL_MULTI' + cfg['model_value'] = '0' cfg["samples"] = '5' cfg["buffer_length"] = '2' for key, value in cfg.items(): f.write(key + ' = ' + str(value) + '\n') - # compression - returncode, stdout, stderr = call_cmp_tool( - " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix1+" --no_header") + add_args = [" --no_header", ""] + for add_arg in add_args: + print("Remove this", add_arg) + # compression + returncode, stdout, stderr = call_cmp_tool( + " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix1+ add_arg) - # check compression results - assert(returncode == EXIT_SUCCESS) - assert(stderr == "") - assert(stdout == CMP_START_STR_CMP + - "Importing configuration file %s ... DONE\n" % (cfg_file_name) + - "Importing data file %s ... DONE\n" % (data_file_name) + - "Importing model file %s ... DONE\n" % (model_file_name) + - "Compress data ... DONE\n" + - "Write compressed data to file %s.cmp ... DONE\n" % (output_prefix1) + - "Write decompression information to file %s.info ... DONE\n" % (output_prefix1) + - "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix1)) - # check compressed data - with open(output_prefix1+".cmp", encoding='utf-8') as f: - assert(f.read() == "49 24 00 00 \n") - # check info file - with open(output_prefix1+".info", encoding='utf-8') as f: - info = parse_key_value(f.read()) - assert(info['cmp_mode_used'] == '3') - assert(info['model_value_used'] == cfg['model_value']) - assert(info['round_used'] == cfg['round']) - assert(info['spill_used'] == cfg['spill']) - assert(info['golomb_par_used'] == cfg['golomb_par']) - assert(info['samples_used'] == cfg['samples']) - assert(info['cmp_size'] == '15') - assert(info['cmp_err'] == '0') - - # decompression - returncode, stdout, stderr = call_cmp_tool( - " -i "+output_prefix1+".info -d "+output_prefix1+".cmp -m "+model_file_name+" -o "+output_prefix2) - assert(returncode == EXIT_SUCCESS) - assert(stdout == CMP_START_STR_DECMP + - "Importing decompression information file %s.info ... DONE\n" % (output_prefix1) + - "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix1) + - "Importing model file %s ... DONE\n" % (model_file_name) + - "Decompress data ... DONE\n" + - "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix2) + - "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix2)) - assert(stderr == "") - # check compressed data + # check compression results + assert(stderr == "") + assert(stdout == CMP_START_STR_CMP + + "Importing configuration file %s ... DONE\n" % (cfg_file_name) + + "Importing data file %s ... DONE\n" % (data_file_name) + + "Importing model file %s ... DONE\n" % (model_file_name) + + "Compress data ... DONE\n" + + "Write compressed data to file %s.cmp ... DONE\n" % (output_prefix1) + + "%s" % ((lambda arg : "Write decompression information to file %s.info ... DONE\n" % (output_prefix1) + if arg == " --no_header" else "")(add_arg)) + + "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix1) + ) + assert(returncode == EXIT_SUCCESS) + + if add_arg == " --no_header": + # check compressed data + with open(output_prefix1+".cmp", encoding='utf-8') as f: + assert(f.read() == "49 24 00 00 \n") + # check info file + with open(output_prefix1+".info", encoding='utf-8') as f: + info = parse_key_value(f.read()) + assert(info['cmp_mode_used'] == '3') + assert(info['model_value_used'] == cfg['model_value']) + assert(info['round_used'] == cfg['round']) + assert(info['spill_used'] == cfg['spill']) + assert(info['golomb_par_used'] == cfg['golomb_par']) + assert(info['samples_used'] == cfg['samples']) + assert(info['cmp_size'] == '15') + assert(info['cmp_err'] == '0') + else: + with open(output_prefix1+".cmp", encoding='utf-8') as f: + header = read_in_cmp_header(f.read()) + assert(header['asw_version_id']['value'] == VERSION) + assert(header['cmp_ent_size']['value'] == IMAGETTE_HEADER_SIZE+4) + assert(header['original_size']['value'] == 10) + # todo + assert(header['start_time']['value'] < cuc_timestamp(datetime.utcnow())) + #todo + assert(header['end_timestamp']['value'] < cuc_timestamp(datetime.utcnow())) + assert(header['data_type']['value'] == DATA_TYPE_IMAGETTE) + assert(header['cmp_mode_used']['value'] == 3) + assert(header['model_value_used']['value'] == int(cfg['model_value'])) + assert(header['model_id']['value'] == 53264) + assert(header['model_counter']['value'] == 1) + assert(header['lossy_cmp_par_used']['value'] == int(cfg['round'])) + assert(header['spill_used']['value'] == int(cfg['spill'])) + assert(header['golomb_par_used']['value'] == int(cfg['golomb_par'])) + assert(header['compressed_data']['value'] == "49240000") - with open(output_prefix2+".dat", encoding='utf-8') as f: - assert(f.read() == data) + # decompression + if add_arg == " --no_header": + returncode, stdout, stderr = call_cmp_tool( + " -i "+output_prefix1+".info -d "+output_prefix1+".cmp -m "+model_file_name+" -o "+output_prefix2) + else: + returncode, stdout, stderr = call_cmp_tool("-d "+output_prefix1+".cmp -m "+model_file_name+" -o "+output_prefix2) + assert(stderr == "") + assert(stdout == CMP_START_STR_DECMP + + "%s" % ((lambda arg : "Importing decompression information file %s.info ... DONE\n" % (output_prefix1) + if "--no_header" in arg else "")(add_arg)) + + "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix1) + + "Importing model file %s ... DONE\n" % (model_file_name) + + "Decompress data ... DONE\n" + + "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix2) + + "Write updated model to file %s_upmodel.dat ... DONE\n" % (output_prefix2)) + assert(returncode == EXIT_SUCCESS) + # check compressed data + + with open(output_prefix2+".dat", encoding='utf-8') as f: + assert(f.read() == data) - with open(output_prefix1+"_upmodel.dat", encoding='utf-8') as f1: - with open(output_prefix2+"_upmodel.dat", encoding='utf-8') as f2: - assert(f1.read() == f2.read() == - '00 00 00 01 00 02 00 03 00 04 \n') + with open(output_prefix1+"_upmodel.dat", encoding='utf-8') as f1: + with open(output_prefix2+"_upmodel.dat", encoding='utf-8') as f2: + assert(f1.read() == f2.read() == data) # upmodel == data -> model_value = 0 + # '00 00 00 01 00 02 00 03 00 04 \n') # clean up finally: del_file(data_file_name) @@ -583,7 +613,7 @@ def test_raw_mode_compression(): with open(output_prefix+".cmp", encoding='utf-8') as f: if "--no_header" in arg: # check compressed data file - assert(f.read() == data[:-1]+"00 00 \n") + assert(f.read() == data)#[:-1]+"00 00 \n") # check info file with open(output_prefix+".info", encoding='utf-8') as f: info = parse_key_value(f.read()) @@ -628,8 +658,6 @@ def test_raw_mode_compression(): "%s" % ((lambda arg : "Importing decompression information file %s.info ... DONE\n" % (output_prefix) if "--no_header" in arg else "")(arg)) + "Importing compressed data file %s.cmp ... DONE\n" % (output_prefix) + - "%s" % ((lambda arg : "Parse the compression entity header ... DONE\n" - if not "--no_header" in arg else "")(arg)) + "Decompress data ... DONE\n" + "Write decompressed data to file %s.dat ... DONE\n" % (output_prefix)) assert(returncode == EXIT_SUCCESS) @@ -803,9 +831,7 @@ def test_small_buf_err(): assert(stdout == CMP_START_STR_CMP + "Importing configuration file %s ... DONE\n" % (cfg_file_name) + "Importing data file %s ... DONE\n" % (data_file_name) + - "Compress data ... \n" - "Compression error 0x01\n" - "... FAILED\n") + "Compress data ... FAILED\n") # assert(stderr == "cmp_tool: the buffer for the compressed data is too small. Try a larger buffer_length parameter.\n") assert(stderr == "Error: The buffer for the compressed data is too small to hold the compressed data. Try a larger buffer_length parameter.\n") assert(returncode == EXIT_FAILURE) @@ -980,11 +1006,9 @@ def test_sample_used_is_to_big(): else: assert(stdout == CMP_START_STR_DECMP + "Importing compressed data file %s ... DONE\n" % (cmp_file_name) + - "Parse the compression entity header ... DONE\n" + "Decompress data ... FAILED\n") - assert(stderr == "Error: Buffer overflow detected.\n" + - "Error: Compressed values could not be decoded.\n") + assert(stderr == "Error: Buffer overflow detected.\n") assert(returncode == EXIT_FAILURE) finally: @@ -1010,6 +1034,7 @@ def test_header_wrong_formatted(): finally: del_file(cmp_file_name) + def test_header_read_in(): cmp_file_name = 'test_header_read_in.cmp' @@ -1082,7 +1107,7 @@ def test_header_read_in(): assert(returncode == EXIT_FAILURE) assert(stdout == CMP_START_STR_DECMP + "Importing compressed data file %s ... DONE\n" % (cmp_file_name) + - "Parse the compression entity header ... FAILED\n" ) + "Decompress data ... FAILED\n" ) assert(stderr == "Error: Compression mode not supported.\n") finally: @@ -1107,25 +1132,27 @@ def test_model_fiel_erros(): f.write(cfg) # no -m option in model mode - returncode, stdout, stderr = call_cmp_tool( - " -c "+cfg_file_name+" -d "+data_file_name + " -o "+output_prefix+" --no_header") - assert(returncode == EXIT_FAILURE) - assert(stdout == CMP_START_STR_CMP + - "Importing configuration file %s ... DONE\n" % (cfg_file_name) + - "Importing data file %s ... DONE\n" % (data_file_name) + - "Importing model file ... FAILED\n" ) - assert(stderr == "cmp_tool: No model file (-m option) specified.\n") + add_args = [" --no_header", ""] + for add_arg in add_args: + returncode, stdout, stderr = call_cmp_tool( + " -c "+cfg_file_name+" -d "+data_file_name + " -o "+output_prefix+add_arg) + assert(returncode == EXIT_FAILURE) + assert(stdout == CMP_START_STR_CMP + + "Importing configuration file %s ... DONE\n" % (cfg_file_name) + + "Importing data file %s ... DONE\n" % (data_file_name) + + "Importing model file ... FAILED\n" ) + assert(stderr == "cmp_tool: No model file (-m option) specified.\n") - # model file to small - with open(model_file_name, 'w', encoding='utf-8') as f: - f.write(model) - returncode, stdout, stderr = call_cmp_tool( - " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix) - assert(returncode == EXIT_FAILURE) - assert(stdout == CMP_START_STR_CMP + - "Importing configuration file %s ... DONE\n" % (cfg_file_name) + - "Importing data file %s ... DONE\n" % (data_file_name) + - "Importing model file %s ... FAILED\n" % (model_file_name) ) + # model file to small + with open(model_file_name, 'w', encoding='utf-8') as f: + f.write(model) + returncode, stdout, stderr = call_cmp_tool( + " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix) + assert(returncode == EXIT_FAILURE) + assert(stdout == CMP_START_STR_CMP + + "Importing configuration file %s ... DONE\n" % (cfg_file_name) + + "Importing data file %s ... DONE\n" % (data_file_name) + + "Importing model file %s ... FAILED\n" % (model_file_name) ) assert(stderr == "cmp_tool: %s: Error: The files do not contain enough data as requested.\n" % (model_file_name)) # updated model can not write @@ -1137,6 +1164,11 @@ def test_model_fiel_erros(): "longlonglonglonglonglonglonglonglonglonglonglonglong" "longlonglonglonglonglonglonglonglonglonglonglonglong" "longlonglonglonglonglonglonglonglonglong") + if sys.platform == 'win32' or sys.platform == 'cygwin': + output_prefix = ("longlonglonglonglonglonglonglonglonglonglonglonglong" + "longlonglonglonglonglonglonglonglonglonglonglonglong" + "longlonglonglonglonglonglonglonglonglonglonglonglong" + "longlonglonglonglonglonglonglonglonglonglong") returncode, stdout, stderr = call_cmp_tool( " -c "+cfg_file_name+" -d "+data_file_name + " -m "+model_file_name+" -o "+output_prefix) assert(returncode == EXIT_FAILURE) @@ -1148,8 +1180,10 @@ def test_model_fiel_erros(): "Compress data ... DONE\n" + "Write compressed data to file %s.cmp ... DONE\n" %(output_prefix) + "Write updated model to file %s_upmodel.dat ... FAILED\n" %(output_prefix)) - assert(stderr == "cmp_tool: %s_upmodel.dat: File name too long\n" % (output_prefix)) - # + if sys.platform == 'win32' or sys.platform == 'cygwin': + assert(stderr == "cmp_tool: %s_upmodel.dat: No such file or directory\n" % (output_prefix)) + else: + assert(stderr == "cmp_tool: %s_upmodel.dat: File name too long\n" % (output_prefix)) finally: del_file(data_file_name) diff --git a/test/cmp_tool/meson.build b/test/cmp_tool/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..065cc4557853043de6dbd6a861fd620f603da24a --- /dev/null +++ b/test/cmp_tool/meson.build @@ -0,0 +1,12 @@ +int_test_file = files('cmp_tool_integration_test.py') + +pytest = find_program('pytest', required : false) +if pytest.found() + test('cmp_tool Interface Test', + pytest, + args : ['--color=yes', '-vvv', int_test_file], + depends : cmp_tool_exe, + workdir : meson.project_build_root()) +else + message('Pytest framework not found! Skipping integration tests. Run pip install pytest.') +endif diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..36fee6ce08454a4e3db2b9cf0092bbdb9274a460 --- /dev/null +++ b/test/meson.build @@ -0,0 +1,41 @@ +# add checkpatch syntax-check target +checkpatch = find_program('checkpatch.pl', 'checkpatch', required : false) +if checkpatch.found() + checkpatch_args = [ + '--no-tree', '-f', + '--show-types', + '--color=always', + '--ignore', 'SPDX_LICENSE_TAG,PREFER_DEFINED_ATTRIBUTE_MACRO,EMBEDDED_FILENAME,BLOCK_COMMENT_STYLE,EMBEDDED_FUNCTION_NAME', + ] + run_target('syntax-check', + command : [checkpatch, checkpatch_args, main, cmplib_sources]) +endif + +# add cppcheck inspector target +cppcheck = find_program('cppcheck', required : false) +if cppcheck.found() + cppcheck_args = [ + main, cmplib_sources, + '--clang', + '--cppcheck-build-dir='+meson.current_build_dir(), + '-I', 'include', + '--std=c89', + # '--addon=misra.py', + '--bug-hunting', + '--enable=all', + '--inconclusive' + ] + run_target('inspector', + command : [cppcheck, cppcheck_args] + ) +endif + +subdir('tools') + +subdir('cmp_tool') + +unity_dep = dependency('unity', fallback : ['unity', 'unity_dep']) + +subdir('cmp_icu') +subdir('cmp_data_types') +subdir('cmp_entity') diff --git a/test/tools/generate_test_runner.rb b/test/tools/generate_test_runner.rb new file mode 100755 index 0000000000000000000000000000000000000000..1c0ec3450435f7c8cf95219afd6f9226b7389a0f --- /dev/null +++ b/test/tools/generate_test_runner.rb @@ -0,0 +1,512 @@ +#!/usr/bin/env ruby +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +class UnityTestRunnerGenerator + def initialize(options = nil) + @options = UnityTestRunnerGenerator.default_options + case options + when NilClass + @options + when String + @options.merge!(UnityTestRunnerGenerator.grab_config(options)) + when Hash + # Check if some of these have been specified + @options[:has_setup] = !options[:setup_name].nil? + @options[:has_teardown] = !options[:teardown_name].nil? + @options[:has_suite_setup] = !options[:suite_setup].nil? + @options[:has_suite_teardown] = !options[:suite_teardown].nil? + @options.merge!(options) + else + raise 'If you specify arguments, it should be a filename or a hash of options' + end + require_relative 'type_sanitizer' + end + + def self.default_options + { + includes: [], + defines: [], + plugins: [], + framework: :unity, + test_prefix: 'test|spec|should', + mock_prefix: 'Mock', + mock_suffix: '', + setup_name: 'setUp', + teardown_name: 'tearDown', + test_reset_name: 'resetTest', + test_verify_name: 'verifyTest', + main_name: 'main', # set to :auto to automatically generate each time + main_export_decl: '', + cmdline_args: false, + omit_begin_end: false, + use_param_tests: false, + include_extensions: '(?:hpp|hh|H|h)', + source_extensions: '(?:cpp|cc|ino|C|c)' + } + end + + def self.grab_config(config_file) + options = default_options + unless config_file.nil? || config_file.empty? + require 'yaml' + yaml_guts = YAML.load_file(config_file) + options.merge!(yaml_guts[:unity] || yaml_guts[:cmock]) + raise "No :unity or :cmock section found in #{config_file}" unless options + end + options + end + + def run(input_file, output_file, options = nil) + @options.merge!(options) unless options.nil? + + # pull required data from source file + source = File.read(input_file) + source = source.force_encoding('ISO-8859-1').encode('utf-8', replace: nil) + tests = find_tests(source) + headers = find_includes(source) + testfile_includes = (headers[:local] + headers[:system]) + used_mocks = find_mocks(testfile_includes) + testfile_includes = (testfile_includes - used_mocks) + testfile_includes.delete_if { |inc| inc =~ /(unity|cmock)/ } + find_setup_and_teardown(source) + + # build runner file + generate(input_file, output_file, tests, used_mocks, testfile_includes) + + # determine which files were used to return them + all_files_used = [input_file, output_file] + all_files_used += testfile_includes.map { |filename| filename + '.c' } unless testfile_includes.empty? + all_files_used += @options[:includes] unless @options[:includes].empty? + all_files_used += headers[:linkonly] unless headers[:linkonly].empty? + all_files_used.uniq + end + + def generate(input_file, output_file, tests, used_mocks, testfile_includes) + File.open(output_file, 'w') do |output| + create_header(output, used_mocks, testfile_includes) + create_externs(output, tests, used_mocks) + create_mock_management(output, used_mocks) + create_setup(output) + create_teardown(output) + create_suite_setup(output) + create_suite_teardown(output) + create_reset(output) + create_run_test(output) unless tests.empty? + create_args_wrappers(output, tests) + create_main(output, input_file, tests, used_mocks) + end + + return unless @options[:header_file] && !@options[:header_file].empty? + + File.open(@options[:header_file], 'w') do |output| + create_h_file(output, @options[:header_file], tests, testfile_includes, used_mocks) + end + end + + def find_tests(source) + tests_and_line_numbers = [] + + # contains characters which will be substituted from within strings, doing + # this prevents these characters from interfering with scrubbers + # @ is not a valid C character, so there should be no clashes with files genuinely containing these markers + substring_subs = { '{' => '@co@', '}' => '@cc@', ';' => '@ss@', '/' => '@fs@' } + substring_re = Regexp.union(substring_subs.keys) + substring_unsubs = substring_subs.invert # the inverse map will be used to fix the strings afterwords + substring_unsubs['@quote@'] = '\\"' + substring_unsubs['@apos@'] = '\\\'' + substring_unre = Regexp.union(substring_unsubs.keys) + source_scrubbed = source.clone + source_scrubbed = source_scrubbed.gsub(/\\"/, '@quote@') # hide escaped quotes to allow capture of the full string/char + source_scrubbed = source_scrubbed.gsub(/\\'/, '@apos@') # hide escaped apostrophes to allow capture of the full string/char + source_scrubbed = source_scrubbed.gsub(/("[^"\n]*")|('[^'\n]*')/) { |s| s.gsub(substring_re, substring_subs) } # temporarily hide problematic characters within strings + source_scrubbed = source_scrubbed.gsub(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks + source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments + source_scrubbed = source_scrubbed.gsub(/\/\/.*$/, '') # remove line comments (all that remain) + lines = source_scrubbed.split(/(^\s*\#.*$) | (;|\{|\}) /x) # Treat preprocessor directives as a logical line. Match ;, {, and } as end of lines + .map { |line| line.gsub(substring_unre, substring_unsubs) } # unhide the problematic characters previously removed + + lines.each_with_index do |line, _index| + # find tests + next unless line =~ /^((?:\s*(?:TEST_CASE|TEST_RANGE)\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/m + + arguments = Regexp.last_match(1) + name = Regexp.last_match(2) + call = Regexp.last_match(3) + params = Regexp.last_match(4) + args = nil + + if @options[:use_param_tests] && !arguments.empty? + args = [] + arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) { |a| args << a[0] } + + arguments.scan(/\s*TEST_RANGE\s*\((.*)\)\s*$/).flatten.each do |range_str| + args += range_str.scan(/\[(-?\d+.?\d*), *(-?\d+.?\d*), *(-?\d+.?\d*)\]/).map do |arg_values_str| + arg_values_str.map do |arg_value_str| + arg_value_str.include?('.') ? arg_value_str.to_f : arg_value_str.to_i + end + end.map do |arg_values| + (arg_values[0]..arg_values[1]).step(arg_values[2]).to_a + end.reduce do |result, arg_range_expanded| + result.product(arg_range_expanded) + end.map do |arg_combinations| + arg_combinations.flatten.join(', ') + end + end + end + + tests_and_line_numbers << { test: name, args: args, call: call, params: params, line_number: 0 } + end + + tests_and_line_numbers.uniq! { |v| v[:test] } + + # determine line numbers and create tests to run + source_lines = source.split("\n") + source_index = 0 + tests_and_line_numbers.size.times do |i| + source_lines[source_index..-1].each_with_index do |line, index| + next unless line =~ /\s+#{tests_and_line_numbers[i][:test]}(?:\s|\()/ + + source_index += index + tests_and_line_numbers[i][:line_number] = source_index + 1 + break + end + end + + tests_and_line_numbers + end + + def find_includes(source) + # remove comments (block and line, in three steps to ensure correct precedence) + source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks + source.gsub!(/\/\*.*?\*\//m, '') # remove block comments + source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) + + # parse out includes + includes = { + local: source.scan(/^\s*#include\s+\"\s*(.+\.#{@options[:include_extensions]})\s*\"/).flatten, + system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" }, + linkonly: source.scan(/^TEST_FILE\(\s*\"\s*(.+\.#{@options[:source_extensions]})\s*\"/).flatten + } + includes + end + + def find_mocks(includes) + mock_headers = [] + includes.each do |include_path| + include_file = File.basename(include_path) + mock_headers << include_path if include_file =~ /^#{@options[:mock_prefix]}.*#{@options[:mock_suffix]}\.h$/i + end + mock_headers + end + + def find_setup_and_teardown(source) + @options[:has_setup] = source =~ /void\s+#{@options[:setup_name]}\s*\(/ + @options[:has_teardown] = source =~ /void\s+#{@options[:teardown_name]}\s*\(/ + @options[:has_suite_setup] ||= (source =~ /void\s+suiteSetUp\s*\(/) + @options[:has_suite_teardown] ||= (source =~ /int\s+suiteTearDown\s*\(int\s+([a-zA-Z0-9_])+\s*\)/) + end + + def create_header(output, mocks, testfile_includes = []) + output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') + output.puts("\n/*=======Automagically Detected Files To Include=====*/") + output.puts("#include \"#{@options[:framework]}.h\"") + output.puts('#include "cmock.h"') unless mocks.empty? + if @options[:defines] && !@options[:defines].empty? + @options[:defines].each { |d| output.puts("#ifndef #{d}\n#define #{d}\n#endif /* #{d} */") } + end + if @options[:header_file] && !@options[:header_file].empty? + output.puts("#include \"#{File.basename(@options[:header_file])}\"") + else + @options[:includes].flatten.uniq.compact.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") + end + testfile_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") + end + end + mocks.each do |mock| + output.puts("#include \"#{mock}\"") + end + output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) + + return unless @options[:enforce_strict_ordering] + + output.puts('') + output.puts('int GlobalExpectCount;') + output.puts('int GlobalVerifyOrder;') + output.puts('char* GlobalOrderError;') + end + + def create_externs(output, tests, _mocks) + output.puts("\n/*=======External Functions This Runner Calls=====*/") + output.puts("extern void #{@options[:setup_name]}(void);") + output.puts("extern void #{@options[:teardown_name]}(void);") + output.puts("\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif") if @options[:externc] + tests.each do |test| + output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") + end + output.puts("#ifdef __cplusplus\n}\n#endif") if @options[:externc] + output.puts('') + end + + def create_mock_management(output, mock_headers) + output.puts("\n/*=======Mock Management=====*/") + output.puts('static void CMock_Init(void)') + output.puts('{') + + if @options[:enforce_strict_ordering] + output.puts(' GlobalExpectCount = 0;') + output.puts(' GlobalVerifyOrder = 0;') + output.puts(' GlobalOrderError = NULL;') + end + + mocks = mock_headers.map { |mock| File.basename(mock, '.*') } + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Init();") + end + output.puts("}\n") + + output.puts('static void CMock_Verify(void)') + output.puts('{') + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Verify();") + end + output.puts("}\n") + + output.puts('static void CMock_Destroy(void)') + output.puts('{') + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Destroy();") + end + output.puts("}\n") + end + + def create_setup(output) + return if @options[:has_setup] + + output.puts("\n/*=======Setup (stub)=====*/") + output.puts("void #{@options[:setup_name]}(void) {}") + end + + def create_teardown(output) + return if @options[:has_teardown] + + output.puts("\n/*=======Teardown (stub)=====*/") + output.puts("void #{@options[:teardown_name]}(void) {}") + end + + def create_suite_setup(output) + return if @options[:suite_setup].nil? + + output.puts("\n/*=======Suite Setup=====*/") + output.puts('void suiteSetUp(void)') + output.puts('{') + output.puts(@options[:suite_setup]) + output.puts('}') + end + + def create_suite_teardown(output) + return if @options[:suite_teardown].nil? + + output.puts("\n/*=======Suite Teardown=====*/") + output.puts('int suiteTearDown(int num_failures)') + output.puts('{') + output.puts(@options[:suite_teardown]) + output.puts('}') + end + + def create_reset(output) + output.puts("\n/*=======Test Reset Options=====*/") + output.puts("void #{@options[:test_reset_name]}(void);") + output.puts("void #{@options[:test_reset_name]}(void)") + output.puts('{') + output.puts(" #{@options[:teardown_name]}();") + output.puts(' CMock_Verify();') + output.puts(' CMock_Destroy();') + output.puts(' CMock_Init();') + output.puts(" #{@options[:setup_name]}();") + output.puts('}') + output.puts("void #{@options[:test_verify_name]}(void);") + output.puts("void #{@options[:test_verify_name]}(void)") + output.puts('{') + output.puts(' CMock_Verify();') + output.puts('}') + end + + def create_run_test(output) + require 'erb' + template = ERB.new(File.read(File.join(__dir__, 'run_test.erb')), nil, '<>') + output.puts("\n" + template.result(binding)) + end + + def create_args_wrappers(output, tests) + return unless @options[:use_param_tests] + + output.puts("\n/*=======Parameterized Test Wrappers=====*/") + tests.each do |test| + next if test[:args].nil? || test[:args].empty? + + test[:args].each.with_index(1) do |args, idx| + output.puts("static void runner_args#{idx}_#{test[:test]}(void)") + output.puts('{') + output.puts(" #{test[:test]}(#{args});") + output.puts("}\n") + end + end + end + + def create_main(output, filename, tests, used_mocks) + output.puts("\n/*=======MAIN=====*/") + main_name = @options[:main_name].to_sym == :auto ? "main_#{filename.gsub('.c', '')}" : (@options[:main_name]).to_s + if @options[:cmdline_args] + if main_name != 'main' + output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv);") + end + output.puts("#{@options[:main_export_decl]} int #{main_name}(int argc, char** argv)") + output.puts('{') + output.puts(' int parse_status = UnityParseOptions(argc, argv);') + output.puts(' if (parse_status != 0)') + output.puts(' {') + output.puts(' if (parse_status < 0)') + output.puts(' {') + output.puts(" UnityPrint(\"#{filename.gsub('.c', '')}.\");") + output.puts(' UNITY_PRINT_EOL();') + tests.each do |test| + if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? + output.puts(" UnityPrint(\" #{test[:test]}\");") + output.puts(' UNITY_PRINT_EOL();') + else + test[:args].each do |args| + output.puts(" UnityPrint(\" #{test[:test]}(#{args})\");") + output.puts(' UNITY_PRINT_EOL();') + end + end + end + output.puts(' return 0;') + output.puts(' }') + output.puts(' return parse_status;') + output.puts(' }') + else + main_return = @options[:omit_begin_end] ? 'void' : 'int' + if main_name != 'main' + output.puts("#{@options[:main_export_decl]} #{main_return} #{main_name}(void);") + end + output.puts("#{main_return} #{main_name}(void)") + output.puts('{') + end + output.puts(' suiteSetUp();') if @options[:has_suite_setup] + if @options[:omit_begin_end] + output.puts(" UnitySetTestFile(\"#{filename.gsub(/\\/, '\\\\\\')}\");") + else + output.puts(" UnityBegin(\"#{filename.gsub(/\\/, '\\\\\\')}\");") + end + tests.each do |test| + if (!@options[:use_param_tests]) || test[:args].nil? || test[:args].empty? + output.puts(" run_test(#{test[:test]}, \"#{test[:test]}\", #{test[:line_number]});") + else + test[:args].each.with_index(1) do |args, idx| + wrapper = "runner_args#{idx}_#{test[:test]}" + testname = "#{test[:test]}(#{args})".dump + output.puts(" run_test(#{wrapper}, #{testname}, #{test[:line_number]});") + end + end + end + output.puts + output.puts(' CMock_Guts_MemFreeFinal();') unless used_mocks.empty? + if @options[:has_suite_teardown] + if @options[:omit_begin_end] + output.puts(' (void) suite_teardown(0);') + else + output.puts(' return suiteTearDown(UnityEnd());') + end + else + output.puts(' return UnityEnd();') unless @options[:omit_begin_end] + end + output.puts('}') + end + + def create_h_file(output, filename, tests, testfile_includes, used_mocks) + filename = File.basename(filename).gsub(/[-\/\\\.\,\s]/, '_').upcase + output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') + output.puts("#ifndef _#{filename}") + output.puts("#define _#{filename}\n\n") + output.puts("#include \"#{@options[:framework]}.h\"") + output.puts('#include "cmock.h"') unless used_mocks.empty? + @options[:includes].flatten.uniq.compact.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") + end + testfile_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc}\""}") + end + output.puts "\n" + tests.each do |test| + if test[:params].nil? || test[:params].empty? + output.puts("void #{test[:test]}(void);") + else + output.puts("void #{test[:test]}(#{test[:params]});") + end + end + output.puts("#endif\n\n") + end +end + +if $0 == __FILE__ + options = { includes: [] } + + # parse out all the options first (these will all be removed as we go) + ARGV.reject! do |arg| + case arg + when '-cexception' + options[:plugins] = [:cexception] + true + when /\.*\.ya?ml$/ + options = UnityTestRunnerGenerator.grab_config(arg) + true + when /--(\w+)=\"?(.*)\"?/ + options[Regexp.last_match(1).to_sym] = Regexp.last_match(2) + true + when /\.*\.(?:hpp|hh|H|h)$/ + options[:includes] << arg + true + else false + end + end + + # make sure there is at least one parameter left (the input file) + unless ARGV[0] + puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)", + "\n input_test_file - this is the C file you want to create a runner for", + ' output - this is the name of the runner file to generate', + ' defaults to (input_test_file)_Runner', + ' files:', + ' *.yml / *.yaml - loads configuration from here in :unity or :cmock', + ' *.h - header files are added as #includes in runner', + ' options:', + ' -cexception - include cexception support', + ' -externc - add extern "C" for cpp support', + ' --setup_name="" - redefine setUp func name to something else', + ' --teardown_name="" - redefine tearDown func name to something else', + ' --main_name="" - redefine main func name to something else', + ' --test_prefix="" - redefine test prefix from default test|spec|should', + ' --test_reset_name="" - redefine resetTest func name to something else', + ' --test_verify_name="" - redefine verifyTest func name to something else', + ' --suite_setup="" - code to execute for setup of entire suite', + ' --suite_teardown="" - code to execute for teardown of entire suite', + ' --use_param_tests=1 - enable parameterized tests (disabled by default)', + ' --omit_begin_end=1 - omit calls to UnityBegin and UnityEnd (disabled by default)', + ' --header_file="" - path/name of test header file to generate too'].join("\n") + exit 1 + end + + # create the default test runner name if not specified + ARGV[1] = ARGV[0].gsub('.c', '_Runner.c') unless ARGV[1] + + UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1]) +end diff --git a/test/tools/meson.build b/test/tools/meson.build new file mode 100644 index 0000000000000000000000000000000000000000..7e9b12294e366202a2a9f41d06af8173b156b206 --- /dev/null +++ b/test/tools/meson.build @@ -0,0 +1,6 @@ +generate_test_runner = find_program('generate_test_runner.rb') +test_runner_generator = generator( + generate_test_runner, + output: ['@BASENAME@_Runner.c'], + arguments: ['@INPUT@', '@OUTPUT@'] +) diff --git a/test/tools/run_test.erb b/test/tools/run_test.erb new file mode 100644 index 0000000000000000000000000000000000000000..f91b566915b10cff86d3d4da119ffe1c5863a6f4 --- /dev/null +++ b/test/tools/run_test.erb @@ -0,0 +1,37 @@ +/*=======Test Runner Used To Run Each Test=====*/ +static void run_test(UnityTestFunction func, const char* name, UNITY_LINE_TYPE line_num) +{ + Unity.CurrentTestName = name; + Unity.CurrentTestLineNumber = line_num; +#ifdef UNITY_USE_COMMAND_LINE_ARGS + if (!UnityTestMatches()) + return; +#endif + Unity.NumberOfTests++; + UNITY_CLR_DETAILS(); + UNITY_EXEC_TIME_START(); + CMock_Init(); + if (TEST_PROTECT()) + { +<% if @options[:plugins].include?(:cexception) %> + CEXCEPTION_T e; + Try { + <%= @options[:setup_name] %>(); + func(); + } Catch(e) { + TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, "Unhandled Exception!"); + } +<% else %> + <%= @options[:setup_name] %>(); + func(); +<% end %> + } + if (TEST_PROTECT()) + { + <%= @options[:teardown_name] %>(); + CMock_Verify(); + } + CMock_Destroy(); + UNITY_EXEC_TIME_STOP(); + UnityConcludeTest(); +} diff --git a/test/tools/type_sanitizer.rb b/test/tools/type_sanitizer.rb new file mode 100644 index 0000000000000000000000000000000000000000..dafb8826e71ceb74afa2c4a1563ce66e659b230a --- /dev/null +++ b/test/tools/type_sanitizer.rb @@ -0,0 +1,6 @@ +module TypeSanitizer + def self.sanitize_c_identifier(unsanitized) + # convert filename to valid C identifier by replacing invalid chars with '_' + unsanitized.gsub(/[-\/\\\.\,\s]/, '_') + end +end