From 721a8263099862b2927c9c0c12bc31dd46a0ed01 Mon Sep 17 00:00:00 2001 From: Dominik Loidolt <dominik.loidolt@univie.ac.at> Date: Tue, 31 May 2022 15:19:12 +0200 Subject: [PATCH] add compression of non-imagette data --- cmp_tool.c | 411 +-- include/cmp_data_types.h | 350 ++- include/cmp_entity.h | 65 +- include/cmp_guess.h | 10 +- include/cmp_icu.h | 43 +- include/cmp_io.h | 10 +- include/cmp_rdcu.h | 28 +- include/cmp_support.h | 248 +- include/decmp.h | 8 +- lib/cmp_data_types.c | 936 ++---- lib/cmp_entity.c | 679 +++-- lib/cmp_guess.c | 127 +- lib/cmp_icu.c | 3207 ++++++++++++-------- lib/cmp_icu_new.c | 422 --- lib/cmp_io.c | 295 +- lib/cmp_rdcu.c | 586 ++-- lib/cmp_support.c | 919 +++--- lib/decmp.c | 1599 ++-------- lib/meson.build | 4 +- lib/rdcu_pkt_to_file.c | 14 +- meson.build | 2 + test/cmp_icu/meson.build | 26 +- test/cmp_icu/test_cmp_icu.c | 1454 ++++++++- test/cmp_icu/test_cmp_icu_new.c | 894 ------ test/cmp_icu/test_decmp.c | 442 +++ test/cmp_tool/cmp_tool_integration_test.py | 188 +- test/meson.build | 4 - 27 files changed, 6847 insertions(+), 6124 deletions(-) mode change 100755 => 100644 cmp_tool.c delete mode 100644 lib/cmp_icu_new.c delete mode 100644 test/cmp_icu/test_cmp_icu_new.c create mode 100644 test/cmp_icu/test_decmp.c diff --git a/cmp_tool.c b/cmp_tool.c old mode 100755 new mode 100644 index e3b2716..c30ae6e --- a/cmp_tool.c +++ b/cmp_tool.c @@ -28,6 +28,7 @@ #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" @@ -37,11 +38,21 @@ #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. @@ -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); @@ -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, print_rdcu_cfg); 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, print_rdcu_cfg); 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; - cfg.samples = size/size_of_a_sample(cfg.cmp_mode); + samples = cmp_input_size_to_samples(size, cfg.data_type); + if (samples < 0) + goto fail; + 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,63 +366,58 @@ 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 <= 0) + 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 <= 0) + 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"); } } @@ -406,10 +426,11 @@ int main(int argc, char **argv) /* 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,19 +438,22 @@ 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"); @@ -446,7 +470,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 +478,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_UNKOWN; + 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 +508,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 (print_rdcu_cfg) + 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,7 +552,7 @@ 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"); @@ -550,7 +562,7 @@ static int guess_cmp_pars(struct cmp_cfg *cfg, const char *guess_cmp_mode, 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; @@ -594,48 +606,58 @@ 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_err 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->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; + + if (cmp_size_bit == CMP_ERROR_SAMLL_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; + else + info->cmp_size = (uint32_t)cmp_size_bit; } + return 0; } @@ -643,12 +665,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 +690,65 @@ 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); + cmp_size = icu_compress_data(cfg); + cmp_gernate_rdcu_info(cfg, cmp_size, info); + if (cmp_size < 0 || info->cmp_err != 0) { + if (info->cmp_err) + 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); */ 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); + 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 +762,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; @@ -724,52 +783,56 @@ static int compression(struct cmp_cfg *cfg, struct 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/include/cmp_data_types.h b/include/cmp_data_types.h index 2ec635e..75b69be 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 */ @@ -34,173 +37,240 @@ #include <stdint.h> #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 { + unsigned int 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 smeating_mean; + unsigned int smeating_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; +}; + + +/* 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); + +/* for internal use only! */ +extern struct cmp_max_used_bits max_used_bits; -#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); +/* 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); -void cmp_input_big_to_cpu_endiannessy(void *data, u_int32_t data_size_byte, - uint32_t cmp_mode); +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); -/* @see for packed definition: PLATO-LESIA-PL-RP-0031 Issue: 1.9 (N-DPU->ICU data rate) */ -#define N_DPU_ICU_MULTI_ENTRY_HDR_SIZE 12 -struct n_dpu_icu_multi_entry_hdr { - uint64_t ncxx_timestamp:48; - uint16_t ncxx_configuration_id; - uint16_t ncxx_collection_id; - uint16_t ncxx_collection_length; +struct s_fx { + uint8_t exp_flags; /* selected exposure flags (2 flags + 6 spare bits) */ + uint32_t fx; /* normal light flux */ } __attribute__((packed)); -compile_time_assert(sizeof(struct n_dpu_icu_multi_entry_hdr) == N_DPU_ICU_MULTI_ENTRY_HDR_SIZE, N_DPU_ICU_MULTI_ENTRY_HDR_SIZE_IS_NOT_CORRECT); -struct S_FX { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; +struct s_fx_efx { + uint8_t exp_flags; + uint32_t fx; + uint32_t efx; } __attribute__((packed)); -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_ncob { + uint8_t exp_flags; + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; +} __attribute__((packed)); -struct S_FX_EFX { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; - uint32_t EFX; +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 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 f_fx { + uint32_t fx; +} __attribute__((packed)); -struct S_FX_NCOB { - uint8_t EXPOSURE_FLAGS; - uint32_t FX; - uint32_t NCOB_X; - uint32_t NCOB_Y; + +struct f_fx_efx { + uint32_t fx; + uint32_t efx; } __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 f_fx_ncob { + uint32_t fx; + uint32_t ncob_x; + uint32_t ncob_y; +} __attribute__((packed)); -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; +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)); -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; +struct l_fx { + uint32_t exp_flags:24; /* selected exposure flags (24 flags) */ + uint32_t fx; + uint32_t fx_variance; } __attribute__((packed)); -struct F_FX_EFX { - uint32_t FX; - uint32_t EFX; +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)); -struct F_FX_NCOB { - uint32_t FX; - uint32_t NCOB_X; - uint32_t NCOB_Y; +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)); -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; +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, u_int32_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 2d6bf54..a06715f 100644 --- a/include/cmp_entity.h +++ b/include/cmp_entity.h @@ -33,34 +33,6 @@ #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, -}; - #define GENERIC_HEADER_SIZE 32 #define SPECIFIC_IMAGETTE_HEADER_SIZE 4 #define SPECIFIC_IMAGETTE_ADAPTIVE_HEADER_SIZE 12 @@ -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,8 +169,7 @@ 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); @@ -247,7 +228,7 @@ 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); @@ -301,7 +282,7 @@ 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>) diff --git a/include/cmp_guess.h b/include/cmp_guess.h index fe2ed09..9d3ac42 100644 --- a/include/cmp_guess.h +++ b/include/cmp_guess.h @@ -22,17 +22,23 @@ #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 cd7f193..81a1160 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,45 @@ #ifndef _CMP_ICU_H_ #define _CMP_ICU_H_ -#include "../include/cmp_support.h" +#include "cmp_support.h" + + +/* return code if the bitstream buffer is too small to store the whole bitstream */ +#define CMP_ERROR_SAMLL_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 + + +/* 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); + +size_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 39cfe59..f807825 100644 --- a/include/cmp_io.h +++ b/include/cmp_io.h @@ -31,8 +31,10 @@ 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_file_data(const char *file_name, unsigned int cmp_mode, void *buf, - uint32_t buf_size, int verbose_en); +ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, + 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); ssize_t read_file32(const char *file_name, uint32_t *buf, uint32_t buf_size, @@ -42,8 +44,8 @@ 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, diff --git a/include/cmp_rdcu.h b/include/cmp_rdcu.h index ee5cffb..14e0af9 100644 --- a/include/cmp_rdcu.h +++ b/include/cmp_rdcu.h @@ -21,10 +21,34 @@ #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_cmp_cfg_is_invalid(const struct cmp_cfg *cfg); + int rdcu_compress_data(const struct cmp_cfg *cfg); int rdcu_read_cmp_status(struct cmp_status *status); diff --git a/include/cmp_support.h b/include/cmp_support.h index cfe4bbd..850f0a7 100644 --- a/include/cmp_support.h +++ b/include/cmp_support.h @@ -23,97 +23,165 @@ #include <stddef.h> -#define GOLOMB_PAR_EXPOSURE_FLAGS 1 - -/* Compression Error Register bits definition, see RDCU-FRS-FN-0952 */ -#define SMALL_BUFFER_ERR_BIT 0x00 /* The length for the compressed data buffer is too small */ -#define CMP_MODE_ERR_BIT 0x01 /* The cmp_mode parameter is not set correctly */ -#define MODEL_VALUE_ERR_BIT 0x02 /* The model_value parameter is not set correctly */ -#define CMP_PAR_ERR_BIT 0x03 /* The spill, golomb_par combination is not set correctly */ -#define AP1_CMP_PAR_ERR_BIT 0x04 /* The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression) */ -#define AP2_CMP_PAR_ERR_BIT 0x05 /* The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression) */ -#define MB_ERR_BIT 0x06 /* Multi bit error detected by the memory controller (only HW compression) */ -#define SLAVE_BUSY_ERR_BIT 0x07 /* The bus master has received the "slave busy" status (only HW compression) */ - -#define MODE_RAW 0 -#define MODE_MODEL_ZERO 1 -#define MODE_DIFF_ZERO 2 -#define MODE_MODEL_MULTI 3 -#define MODE_DIFF_MULTI 4 +#define 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 +#define MAX_RDCU_CMP_MODE 4U +#define MIN_RDCU_GOLOMB_PAR 1U +#define MAX_RDCU_GOLOMB_PAR 63U +#define MIN_RDCU_SPILL 2U +#define MAX_RDCU_ROUND 2U /* for maximum spill value look at get_max_spill function */ /* valid compression parameter ranges for ICU compression */ -#define MIN_ICU_GOLOMB_PAR 1UL -#define MAX_ICU_GOLOMB_PAR UINT32_MAX -#define MIN_ICU_SPILL 2UL +#define MIN_ICU_GOLOMB_PAR 1U +#define MAX_ICU_GOLOMB_PAR 0x80000000U +#define MIN_ICU_SPILL 2U /* for maximum spill value look at get_max_spill function */ -#define MAX_ICU_ROUND 3UL +#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 + + +/* defined compression data product types */ +enum cmp_data_type { + DATA_TYPE_UNKOWN, + 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_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, +}; -#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 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 { + 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 */ uint32_t cmp_mode; /* 0: raw mode * 1: model mode with zero escape symbol mechanism * 2: 1d differencing mode without input model with zero escape symbol mechanism * 3: model mode with multi escape symbol mechanism * 4: 1d differencing mode without input model multi escape symbol mechanism */ - uint32_t golomb_par; /* Golomb parameter for dictionary selection */ - uint32_t spill; /* Spillover threshold for encoding outliers */ uint32_t model_value; /* Model weighting parameter */ - uint32_t round; /* Number of noise bits to be rounded */ - uint32_t ap1_golomb_par; /* Adaptive 1 spillover threshold; HW only */ - uint32_t ap1_spill; /* Adaptive 1 Golomb parameter; HW only */ - uint32_t ap2_golomb_par; /* Adaptive 2 spillover threshold; HW only */ + uint32_t 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 +193,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 +207,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,33 +219,43 @@ 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 cmp_cfg_is_valid(const struct cmp_cfg *cfg); +int cmp_cfg_icu_gen_par_is_valid(const struct cmp_cfg *cfg); +int cmp_cfg_icu_buffers_is_valid(const struct cmp_cfg *cfg); +int cmp_cfg_imagette_is_valid(const struct cmp_cfg *cfg); +int cmp_cfg_fx_cob_is_valid(const struct cmp_cfg *cfg); +int cmp_cfg_aux_is_valid(const struct cmp_cfg *cfg); +uint32_t get_max_spill(unsigned int golomb_par, enum cmp_data_type); + +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); -int zero_escape_mech_is_used(unsigned int cmp_mode); -int multi_escape_mech_is_used(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); unsigned int round_fwd(unsigned int value, unsigned int round); unsigned int round_inv(unsigned int value, unsigned int round); -unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int - model_value); - -uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode); -uint32_t cmp_get_good_spill(unsigned int golomb_par, unsigned int cmp_mode); - -size_t size_of_a_sample(unsigned int cmp_mode); -int cmp_input_size_to_samples(unsigned int size, 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 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 139273f..2f8478c 100644 --- a/include/decmp.h +++ b/include/decmp.h @@ -19,13 +19,17 @@ #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_data(const void *compressed_data, void *de_model_buf, +int decompress_data(uint32_t *compressed_data, void *de_model_buf, const struct cmp_info *info, void *decompressed_data); +int decompress_cmp_entiy(struct cmp_entity *ent, void *model_buf, + void *up_model_buf, void *decompressed_data); + double get_compression_ratio(const struct cmp_info *info); #endif /* DECMP_H_ */ diff --git a/lib/cmp_data_types.c b/lib/cmp_data_types.c index cf8c08c..749964d 100644 --- a/lib/cmp_data_types.c +++ b/lib/cmp_data_types.c @@ -17,770 +17,504 @@ */ -#include "../include/cmp_data_types.h" -#include "../include/cmp_support.h" -#include "../include/cmp_debug.h" -#include "../include/byteorder.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, /* smeating_mean */ + MAX_USED_SMEARING_VARIANCE_MEAN_BITS, /* smeating_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; - - /* 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 (set_max_used_bits) + max_used_bits = *set_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 maximum length of the different data products types * - * @returns 0 on success, error otherwise + * @returns a structure with the used maximum length of the different data + * products types in bits */ -int de_lossy_rounding_16(uint16_t *data_buf, uint32_t samples_used, uint32_t - round_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - /* round 0 means loss less compression, no further processing is necessary */ - if (round_used == 0) - return 0; - - for (i = 0; i < samples_used; i++) { - /* check if data are not to big for a overflow */ - uint16_t mask = (uint16_t)(~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); - } - return 0; -} - - -static void be_to_cpus_16(uint16_t *a, uint32_t samples) +struct cmp_max_used_bits cmp_get_max_used_bits(void) { - size_t i; - - for (i = 0; i < samples; ++i) - be16_to_cpus(&a[i]); + return max_used_bits; } /** - * @brief rounding down the least significant digits of a uint32_t data buffer - * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place + * @brief calculate the size of a sample for the different 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 + * @param data_type compression data_type * - * @returns 0 on success, error otherwise + * @returns the size of a data sample in bytes for the selected compression + * data type; zero on unknown data type */ -int lossy_rounding_32(uint32_t *data_buf, unsigned int samples, unsigned int - round) +size_t size_of_a_sample(enum cmp_data_type data_type) { - size_t i; - - if (!samples) - return 0; - - if (!data_buf) - return -1; - - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; - - for (i = 0; i < samples; i++) - data_buf[i] = round_fwd(data_buf[i], round); /* this is the lossy step */ - - return 0; -} - - -int de_lossy_rounding_32(uint32_t *data_buf, uint32_t samples_used, uint32_t - round_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - /* round 0 means loss less compression, no further processing is necessary */ - if (round_used == 0) - return 0; - - for (i = 0; i < samples_used; i++) { - /* check if data are not to big for a overflow */ - uint32_t mask = (uint32_t)(~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); + 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: + 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_DFX: + 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_DFX_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_DFX: + 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_DFX_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_DFX: + 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_DFX_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_UNKOWN: + default: + debug_print("Error: Compression data type is not supported.\n"); + break; } - 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 sample_size; } /** - * @brief rounding down the least significant digits of a S_FX 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 - * @note the exposure_flags are not rounded + * @param samples number of data samples + * @param data_type compression data_type * - * @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 + * @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 */ -int lossy_rounding_S_FX(struct S_FX *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; + unsigned int s = size_of_a_sample(data_type); - if (!samples) + if (!s) return 0; - if (!data_buf) - return -1; + 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].FX = round_fwd(data_buf[i].FX, round); + if (!rdcu_supported_data_type_is_used(data_type)) + s += MULTI_ENTRY_HDR_SIZE; - return 0; + return s; } -int de_lossy_rounding_S_FX(struct S_FX *data_buf, unsigned int samples_used, - unsigned int round_used) -{ - size_t i; +/** + * @brief calculates the number of samples for a given data size for the + * different compression modes + * + * @param size size of the data in bytes + * @param data_type compression data type + * + * @returns the number samples for the given compression mode; negative on error + */ - if (!samples_used) - return 0; +int cmp_input_size_to_samples(unsigned int size, enum cmp_data_type data_type) +{ + int samples_size = (int)size_of_a_sample(data_type); - if (!data_buf) + if (!samples_size) return -1; - if (round_used == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; - - for (i = 0; i < samples_used; i++) { - uint32_t mask = (~0U << (32-round_used)); - - if (data_buf[i].FX & mask) { - debug_print("Errolr: de_lossy_rounding_S_FX failed\n"); + if (!rdcu_supported_data_type_is_used(data_type)) { + if (size < MULTI_ENTRY_HDR_SIZE) return -1; - } - - data_buf[i].FX = round_inv(data_buf[i].FX, round_used); + size -= MULTI_ENTRY_HDR_SIZE; } - return 0; -} - - -struct S_FX cal_up_model_S_FX(struct S_FX data_buf, struct S_FX model_buf, - unsigned int model_value) -{ - struct S_FX result; - result.EXPOSURE_FLAGS = (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS, - model_buf.EXPOSURE_FLAGS, - model_value); - result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value); + if (size % samples_size) + return -1; - return result; + return size/samples_size; } -void be_to_cpus_S_FX(struct S_FX *a, uint32_t samples) +static uint32_t be24_to_cpu(uint32_t a) { - size_t i; - - for (i = 0; i < samples; ++i) - a[i].FX = be32_to_cpu(a[i].FX); + return be32_to_cpu(a) >> 8; } -struct S_FX_EFX sub_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b) +static void be_to_cpus_16(uint16_t *a, int samples) { - struct S_FX_EFX result; + int i; - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - result.EFX = a.EFX - b.EFX; - - return result; + for (i = 0; i < samples; ++i) + be16_to_cpus(&a[i]); } -struct S_FX_EFX add_S_FX_EFX(struct S_FX_EFX a, struct S_FX_EFX b) +static void be_to_cpus_nc_offset(struct nc_offset *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 = be32_to_cpu(a[i].variance); + } } -/** - * @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_nc_background(struct nc_background *a, int samples) { - size_t i; + int i; - if (!samples) - return 0; - - if (!data) - return -1; - - /* round 0 means loss less compression, no further processing is - * necessary */ - if (round == 0) - return 0; - - for (i = 0; i < samples; i++) { - data[i].FX = round_fwd(data[i].FX, round); - data[i].EFX = round_fwd(data[i].EFX, round); + 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); } - 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_smearing(struct smearing *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 failed!\n"); - return -1; - } - if (data_buf[i].EFX & mask) { - debug_print("de_lossy_rounding_S_FX failed!\n"); - return -1; - } + int i; - 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].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); } - 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(struct s_fx *a, int samples) { - struct S_FX_EFX result; + int i; - 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; + for (i = 0; i < samples; ++i) + a[i].fx = be32_to_cpu(a[i].fx); } -void be_to_cpus_S_FX_EFX(struct S_FX_EFX *a, uint32_t samples) +static void be_to_cpus_s_fx_efx(struct s_fx_efx *a, int samples) { - size_t i; + int i; for (i = 0; i < samples; ++i) { - a[i].FX = be32_to_cpu(a[i].FX); - a[i].EFX = be32_to_cpu(a[i].EFX); + a[i].fx = be32_to_cpu(a[i].fx); + a[i].efx = be32_to_cpu(a[i].efx); } } -struct S_FX_NCOB sub_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b) +static void be_to_cpus_s_fx_ncob(struct s_fx_ncob *a, int samples) { - struct S_FX_NCOB result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - result.NCOB_X = a.NCOB_X - b.NCOB_X; - result.NCOB_Y = a.NCOB_Y - b.NCOB_Y; - - return result; -} - + int i; -struct S_FX_NCOB add_S_FX_NCOB(struct S_FX_NCOB a, struct S_FX_NCOB b) -{ - struct S_FX_NCOB result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS; - result.FX = a.FX + b.FX; - result.NCOB_X = a.NCOB_X + b.NCOB_X; - result.NCOB_Y = a.NCOB_Y + b.NCOB_Y; - - return result; + 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); + } } -/** - * @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_s_fx_efx_ncob_ecob(struct s_fx_efx_ncob_ecob *a, int samples) { - size_t i; - - if (!samples) - return 0; - - if (!data_buf) - return -1; + int i; - /* 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); + 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); } - 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(struct l_fx *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; - } + int i; - 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); + 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); } - 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_l_fx_efx(struct l_fx_efx *a, int samples) { - struct S_FX_NCOB result; + int i; - result.EXPOSURE_FLAGS = - (uint8_t)cal_up_model(data_buf.EXPOSURE_FLAGS, - model_buf.EXPOSURE_FLAGS, model_value); - result.FX = cal_up_model(data_buf.FX, model_buf.FX, model_value); - result.NCOB_X = cal_up_model(data_buf.NCOB_X, model_buf.NCOB_X, model_value); - result.NCOB_Y = cal_up_model(data_buf.NCOB_Y, model_buf.NCOB_Y, model_value); - - return result; + 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); + } } -void be_to_cpus_S_FX_NCOB(struct S_FX_NCOB *a, uint32_t samples) +static void be_to_cpus_l_fx_ncob(struct l_fx_ncob *a, int samples) { - size_t i; + 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].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); } } -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_l_fx_efx_ncob_ecob(struct l_fx_efx_ncob_ecob *a, int samples) { - struct S_FX_EFX_NCOB_ECOB result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS - b.EXPOSURE_FLAGS; - result.FX = a.FX - b.FX; - result.NCOB_X = a.NCOB_X - b.NCOB_X; - result.NCOB_Y = a.NCOB_Y - b.NCOB_Y; - result.EFX = a.EFX - b.EFX; - result.ECOB_X = a.ECOB_X - b.ECOB_X; - result.ECOB_Y = a.ECOB_Y - b.ECOB_Y; + int i; - 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].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); + } } -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(struct f_fx *a, int samples) { - struct S_FX_EFX_NCOB_ECOB result; - - result.EXPOSURE_FLAGS = a.EXPOSURE_FLAGS + b.EXPOSURE_FLAGS; - result.FX = a.FX + b.FX; - result.NCOB_X = a.NCOB_X + b.NCOB_X; - result.NCOB_Y = a.NCOB_Y + b.NCOB_Y; - result.EFX = a.EFX + b.EFX; - result.ECOB_X = a.ECOB_X + b.ECOB_X; - result.ECOB_Y = a.ECOB_Y + b.ECOB_Y; + 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_NCOB_ECOB data - * buffer - * - * @note this step involves data loss (if round > 0) - * @note change the data buffer in-place - * @note the exposure_flags are not rounded - * - * @param data_buf a S_FX_EFX_NCOB_ECOB formatted data buffer - * @param samples the size of the data buffer measured in - * S_FX_EFX_NCOB_ECOB samples - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise - */ - -int lossy_rounding_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - unsigned int samples, unsigned int round) +static void be_to_cpus_f_fx_efx(struct f_fx_efx *a, int samples) { - size_t i; - - if (!samples) - return 0; - - if (!data_buf) - return -1; - - if (round == 0) /* round 0 means loss less compression, no further processing is necessary */ - return 0; + int i; - 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); + 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_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - unsigned int samples_used, - unsigned int round_used) +static void be_to_cpus_f_fx_ncob(struct f_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_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); + 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_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; } -void be_to_cpus_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *a, uint32_t samples) +static void be_to_cpus_f_fx_efx_ncob_ecob(struct f_fx_efx_ncob_ecob *a, int samples) { - size_t i; + 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); + 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 swap the endianness of science products form big endian to the cpu - * endianness in place + * @brief swap the endianness of uncompressed data form big endian to the cpu + * endianness (or the other way around) in place * - * @param data pointer to a data sample - * @param cmp_mode compression mode + * @param data pointer to a data sample + * @param data_size_byte size of the data in bytes + * @param data_type compression data type + * + * @returns 0 on success; non-zero on failure */ -void cmp_input_big_to_cpu_endiannessy(void *data, u_int32_t data_size_byte, - uint32_t cmp_mode) +int cmp_input_big_to_cpu_endianness(void *data, uint32_t data_size_byte, + enum cmp_data_type data_type) { - int samples = cmp_input_size_to_samples(data_size_byte, cmp_mode); + int samples = cmp_input_size_to_samples(data_size_byte, data_type); - if (!data) - return; + if (!data) /* nothing to do */ + return 0; if (samples < 0) { debug_print("Error: Can not convert data size in samples.\n"); - return; + return -1; } - if (!rdcu_supported_mode_is_used(cmp_mode)) - data = (uint8_t *)data + N_DPU_ICU_MULTI_ENTRY_HDR_SIZE; - - switch (cmp_mode) { - case MODE_RAW: - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: + /* 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 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: - be_to_cpus_S_FX(data, samples); - 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: - be_to_cpus_S_FX_EFX(data, samples); - 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: - be_to_cpus_S_FX_EFX_NCOB_ECOB(data, samples); - 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: - /* be_to_cpus_F_FX(data, samples); */ - /* 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: - /* be_to_cpus_F_FX_EFX(data, samples); */ - /* 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: - /* be_to_cpus_F_FX_NCOB(data, samples); */ - /* 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: - /* be_to_cpus_F_FX_EFX_NCOB_ECOB(data, samples); */ - /* 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: - /* be32_to_cpus(data); */ - /* break; */ - default: - debug_print("Error: Compression mode not supported.\n"); + 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_DFX: + 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_DFX_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_DFX: + 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_DFX_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_DFX: + 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_DFX_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_UNKOWN: + default: + debug_print("Error: Can not swap endianness for this compression data type.\n"); + return -1; } + + return 0; } diff --git a/lib/cmp_entity.c b/lib/cmp_entity.c index 99aa3bd..d058b17 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_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: + size = NON_IMAGETTE_HEADER_SIZE; + break; + case DATA_TYPE_UNKOWN: + 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; @@ -932,7 +934,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 +951,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 +972,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 +993,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 +1014,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 +1031,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 +1048,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 +1069,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 +1086,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 +1103,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, + * @returns the data_type NOT including the uncompressed data bit on success, * DATA_TYPE_UNKOWN 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; - 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_UNKOWN; + + 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 +1181,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 +1215,7 @@ 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 used lossy compression parameter from the compression entity header * * @param ent pointer to a compression entity * @@ -1227,7 +1232,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 +1250,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 +1268,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 +1286,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 +1304,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 +1322,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 +1340,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 +1362,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 +1380,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 +1402,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 +1420,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 +1442,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 +1460,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 +1482,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 +1500,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 +1522,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 +1540,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 +1562,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,7 +1593,7 @@ 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; @@ -1634,7 +1639,7 @@ 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 @@ -1699,7 +1704,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)); } @@ -1727,108 +1733,67 @@ uint32_t cmp_ent_get_cmp_data_size(struct cmp_entity *ent) /** - * @brief set the parameters in the non-imagette specific compression - * entity header + * @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 * - * @param ent pointer to a compression entity - * @param info decompression information structure - * - * @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; - - 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->)) - return -1; - - if (cmp_ent_set_non_ima_spill2(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par2(ent, info->)) - return -1; - - if (cmp_ent_set_non_ima_spill3(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par3(ent, info->)) - return -1; - - if (cmp_ent_set_non_ima_spill4(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par4(ent, info->)) - return -1; + uint32_t ent_cmp_data_size; - if (cmp_ent_set_non_ima_spill5(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par5(ent, info->)) + if (!cfg) return -1; - if (cmp_ent_set_non_ima_spill6(ent, info->)) - return -1; - if (cmp_ent_set_non_ima_cmp_par6(ent, info->)) + if (cmp_size_bits < 0) 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 - * - * @param ent pointer to a compression entity - * @param info decompression information structure - * @param cfg compression configuration structure for adaptive compression - * parameters (can be NULL) - * - * @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) -{ - uint32_t ent_cmp_data_size; - - if (!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(info->cmp_size)) + 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; + } /* 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(cfg->samples, + cfg->data_type))) return -1; - if (cmp_ent_set_cmp_mode(ent, info->cmp_mode_used)) + if (cmp_ent_set_cmp_mode(ent, cfg->cmp_mode)) return -1; - if (cmp_ent_set_model_value(ent, info->model_value_used)) + if (cmp_ent_set_model_value(ent, cfg->model_value)) return -1; - if (cmp_ent_set_lossy_cmp_par(ent, info->round_used)) + if (cmp_ent_set_lossy_cmp_par(ent, cfg->round)) return -1; - if (cmp_ent_get_data_type_raw_bit(ent)) + 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 (!cfg) - 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)) @@ -1841,14 +1806,44 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, 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)) + if (cmp_ent_set_ima_spill(ent, cfg->spill)) return -1; - if (cmp_ent_set_ima_golomb_par(ent, info->golomb_par_used)) + 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_spill2(ent, cfg->cmp_par_variance)) + return -1; + if (cmp_ent_set_non_ima_cmp_par2(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_DFX: case DATA_TYPE_S_FX_NCOB: @@ -1861,12 +1856,43 @@ static int cmp_ent_write_cmp_pars(struct cmp_entity *ent, struct cmp_info *info, case DATA_TYPE_F_FX_DFX: case DATA_TYPE_F_FX_NCOB: case DATA_TYPE_F_FX_DFX_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: - if (cmp_ent_write_non_ima_parameters(ent, info)) + /* TODO: fix this*/ return -1; break; - case DATA_TYPE_UNKOWN: /* fall through */ + case DATA_TYPE_UNKOWN: default: return -1; } @@ -1876,12 +1902,94 @@ 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 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 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 + */ + +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; + + 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)) { + 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, DATA_TYPE_IMAGETTE))) + return -1; + if (cmp_ent_set_cmp_mode(ent, info->cmp_mode_used)) + return -1; + if (cmp_ent_set_model_value(ent, info->model_value_used)) + return -1; + if (cmp_ent_set_lossy_cmp_par(ent, info->round_used)) + return -1; + + 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; + + 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)) + 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; + } + + return 0; +} + + +/** + * @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 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 * * @note if the entity size is smaller than the largest header, the function @@ -1890,12 +1998,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) @@ -1904,6 +2012,9 @@ 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; + if (ent_size < sizeof(struct cmp_entity)) ent_size = sizeof(struct cmp_entity); @@ -1916,7 +2027,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; @@ -1927,35 +2038,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; - ent_size = cmp_ent_create(ent, data_type, cmp_bit_to_4byte(info->cmp_size)); + if (cmp_size_bits < 0) + return 0; + + 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; @@ -1970,7 +2083,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; } @@ -1979,82 +2092,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; + int samples; - if (!ent) - return -1; - - if (!info) - return -1; - - 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; + 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; } - 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->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); + + 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; } - info->samples_used = original_size / sample_size; + cfg->samples = samples; - 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"); + 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; } - return 0; -} - -#if 0 -int cmp_ent_read_adaptive_imagette_header(struct cmp_entity *ent, struct cmp_info *info) -{ - if (!ent) - return -1; + cfg->icu_output_buf = cmp_ent_get_data_buf(ent); - if (!info) - return -1; - - 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_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: + 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_UNKOWN: /* 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 * @@ -2067,9 +2214,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; @@ -2086,14 +2233,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 */ @@ -2186,7 +2333,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 */ @@ -2197,13 +2344,14 @@ static void cmp_ent_parse_generic_header(struct cmp_entity *ent) model_value_used, model_id, model_counter, 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); @@ -2226,10 +2374,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 @@ -2319,17 +2468,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; } } @@ -2347,3 +2505,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 265b9c5..c173814 100644 --- a/lib/cmp_guess.c +++ b/lib/cmp_guess.c @@ -17,12 +17,14 @@ * dataset */ +#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 +69,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_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, DATA_TYPE_IMAGETTE); + + if (cmp_mode == CMP_MODE_MODEL_MULTI) { + if (golomb_par > MAX_RDCU_GOLOMB_PAR) + return 0; + else + return LUT_RDCU_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 +118,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); + 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 +158,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; @@ -134,12 +171,12 @@ static uint32_t brute_force(struct cmp_cfg *cfg) 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 (s = MIN_RDCU_SPILL; s < get_max_spill(g, cfg->data_type); 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; @@ -185,19 +222,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 +257,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 +264,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 +293,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 +312,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 +319,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 5409045..057ee64 100644 --- a/lib/cmp_icu.c +++ b/lib/cmp_icu.c @@ -15,1761 +15,2396 @@ * * @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" + + +/* 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 generation function */ + 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 a 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 types + * @param cmp_mode compression mode + * @param model_value model weighting parameter (only need 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 compression configuration containing the chosen parameters; + * on error the data_type record is set to DATA_TYPE_UNKOWN */ -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; - - if (!cfg) { - debug_print("Error: compression configuration structure is NULL.\n"); - return -1; - } + int cfg_valid; + struct cmp_cfg cfg = {0}; - 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 (cfg->input_buf == NULL) { - debug_print("Error: The input_buf buffer for the data to be compressed is NULL.\n"); - cfg_invalid++; - } + cfg_valid = cmp_cfg_icu_gen_par_is_valid(&cfg); + if (!cfg_valid) + cfg.data_type = DATA_TYPE_UNKOWN; - if (cfg->samples == 0) - debug_print("Warning: The samples parameter is 0. No data are compressed. This behavior may not be intended.\n"); + return cfg; +} - /* icu_output_buf can be NULL if rdcu compression is used */ - if (cfg->icu_output_buf == NULL) { - debug_print("Error: The icu_output_buf buffer for the compressed data is NULL.\n"); - cfg_invalid++; - } - if (cfg->buffer_length == 0 && cfg->samples != 0) { - debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data.\n"); - cfg_invalid++; - } +/** + * @brief setup of 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 (multi entity 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->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++; +size_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) +{ + 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++; - } - - if (cfg->icu_new_model_buf == cfg->input_buf) { - debug_print("Error: The icu_new_model_buf buffer is the same as the input_buf buffer.\n"); - cfg_invalid++; - } - - if (cfg->icu_new_model_buf == cfg->icu_output_buf) { - debug_print("Error: The icu_output_buf buffer is the same as the icu_output_buf buffer.\n"); - cfg_invalid++; - } - } + 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 (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 (!cmp_cfg_icu_buffers_is_valid(cfg)) + return 0; + return cmp_cal_size_of_data(compressed_data_len_samples, cfg->data_type); +} - 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 + * with 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_valid(cfg)) + 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 of 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 + * with 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_valid(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 of 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 types + * + * @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_valid(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_SAMLL_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_SAMLL_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; -/** - * @brief 1d-differentiating pre-processing and round of a S_FX data buffer - * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index - * - * @param data pointer to a S_FX data buffer - * @param samples amount of data samples in the data buffer - * @param round number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise - */ + /* 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; -static int diff_S_FX(struct S_FX *data, unsigned int samples, unsigned int - round) -{ - size_t i; - int err; + /* Calculate the bitsRight for the unsegmented case. If bitsRight is + * negative we need to split the value over two words + */ + bitsRight = shiftRight - bitsLeft; - if (!data) - return -1; + 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 + */ - err = lossy_rounding_S_FX(data, samples, round); - if (err) - return err; + 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; - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data[i] = sub_S_FX(data[i], data[i-1]); + /* clear the destination */ + *(local_adr) &= mask; + + /* assign the value part 2 */ + *(local_adr) |= (value << shiftLeft); } - return 0; + return stream_len; } /** - * @brief 1d-differentiating pre-processing and rounding of a S_FX_EFX data buffer - * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index + * @brief forms the codeword according to the Rice code * - * @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, 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_EFX(struct S_FX_EFX *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_EFX(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_EFX(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_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 forms a codeword according to the Golomb code * - * @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 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_NCOB(struct S_FX_NCOB *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_NCOB(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_NCOB(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_EFX_NCOB_ECOB data buffer - * - * @note change the data_buf in-place - * @note output is I_0 = I_0, I_i = I_i - I_i-1, where i is the array index + * @brief generate a code word without an outlier mechanism and put in the + * bitstream * - * @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 + * @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_SAMLL_BUF if the bitstream buffer + * is too small to put the value in the bitstream */ -static int diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *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_EFX_NCOB_ECOB(data, samples, round); - if (err) - return err; - - for (i = samples - 1; i > 0; i--) { - /* possible underflow is intended */ - data[i] = sub_S_FX_EFX_NCOB_ECOB(data[i], data[i-1]); - } + cw_len = setup->generate_cw_f(value, setup->encoder_par1, + setup->encoder_par2, &code_word); - return 0; + return put_n_bits32(code_word, cw_len, stream_len, setup->bitstream_adr, + setup->max_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 zero 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_SAMLL_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_zero(uint32_t data, uint32_t model, int stream_len, + const struct encoder_setupt *setup) { - size_t i; + data -= model; /* possible underflow is intended */ - if (!data_buf) - return -1; + data = map_to_pos(data, setup->max_data_bits); - if (!model_buf) - return -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); + } - if (model_value > MAX_MODEL_VALUE) - return -1; + data++; /* add 1 to every value so we can use 0 as escape symbol */ - if (!up_model_buf) - up_model_buf = model_buf; + /* use zero as escape symbol */ + stream_len = encode_normal(0, stream_len, setup); + if (stream_len <= 0) + return stream_len; - 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; + /* 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 round_input of a uint32_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 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 encoded value on + * success; negative on error, CMP_ERROR_SAMLL_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_32(uint32_t *data_buf, uint32_t *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); - for (i = 0; i < samples; i++) { - uint32_t round_input = round_fwd(data_buf[i], round); - uint32_t round_model = round_fwd(model_buf[i], round); - /* possible underflow is intended */ - data_buf[i] = round_input - round_model; - /* round back input because for decompression the accurate data - * are not available - */ - model_buf[i] = cal_up_model(round_inv(round_input, round), - model_buf[i], model_value); - } - return 0; + /* + * 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 (!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; + + 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 S_FX 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 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 the bit length of the bitstream with the added unencoded value on + * success; negative on error, CMP_ERROR_SAMLL_BUF if the bitstream buffer + * is too small to put the value in the bitstream * - * @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 int encode_value_none(uint32_t value, uint32_t unused, int stream_len, + const struct encoder_setupt *setup) { - size_t i; - - if (!samples) - return 0; + (void)(unused); - if (!model_buf) - return -1; + return put_n_bits32(value, setup->encoder_par1, stream_len, + setup->bitstream_adr, setup->max_stream_len); +} - if (model_value > MAX_MODEL_VALUE) - return -1; - if (!up_model_buf) /* overwrite the model buffer if no up_model_buf is set */ - up_model_buf = model_buf; +/** + * @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_SAMLL_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 + */ +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)); - for (i = 0; i < samples; i++) { - struct S_FX round_data = data_buf[i]; - struct S_FX round_model = model_buf[i]; - int err; + /* lossy rounding of the data if lossy_par > 0 */ + data = round_fwd(data, setup->lossy_par); + model = round_fwd(model, setup->lossy_par); - err = lossy_rounding_S_FX(&round_data, 1, round); - if (err) - return err; + 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; + } - err = lossy_rounding_S_FX(&round_model, 1, round); - if (err) - return err; + return setup->encode_method_f(data, model, stream_len, setup); +} - /* possible underflow is intended */ - data_buf[i] = sub_S_FX(round_data, round_model); - /* round back input because for decompression the accurate data - * are not available - */ - err = de_lossy_rounding_S_FX(&round_data, 1, round); - if (err) - return err; - up_model_buf[i] = cal_up_model_S_FX(round_data, model_buf[i], - model_value); - } +/** + * @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 + * + * @param buffer_length length of the icu_output_buf in samples + * @param data_type used compression data type + * + * @returns buffer size in bits + * + */ - return 0; +static uint32_t cmp_buffer_length_to_bits(uint32_t buffer_length, enum cmp_data_type data_type) +{ + return (cmp_cal_size_of_data(buffer_length, data_type) & ~0x3U) * CHAR_BIT; } /** - * @brief data pre-processing to decorrelate the data + * @brief configure an encoder setup structure to have a setup to encode a vale * - * @param cfg configuration contains all parameters required for compression + * @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, error otherwise + * @returns 0 on success; otherwise error */ -int cmp_pre_process(struct cmp_cfg *cfg) +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 (!cfg) + if (!setup) return -1; - if (cfg->samples == 0) - return 0; + if (!cfg) + return -1; - if (!cfg->input_buf) + setup->encoder_par1 = cmp_par; + setup->spillover_par = spillover; + if (max_data_bits > 32) { + debug_print("Error: max_data_bits parameter is bigger than 32 bits.\n"); return -1; + } + setup->max_data_bits = max_data_bits; + setup->lossy_par = lossy_par; 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); + case CMP_MODE_MODEL_ZERO: + case CMP_MODE_DIFF_ZERO: + setup->encode_method_f = &encode_value_zero; + if (ilog_2(cmp_par) < 0) + return -1; + setup->encoder_par2 = (uint32_t)ilog_2(cmp_par); 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); + case CMP_MODE_MODEL_MULTI: + case CMP_MODE_DIFF_MULTI: + setup->encode_method_f = &encode_value_multi; + if (ilog_2(cmp_par) < 0) + return -1; + setup->encoder_par2 = (uint32_t)ilog_2(cmp_par); 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); + case CMP_MODE_STUFF: + setup->encode_method_f = &encode_value_none; + setup->max_data_bits = cmp_par; break; default: - debug_print("Error: Compression mode not supported.\n"); + return -1; } - return -1; -} - - -static uint8_t map_to_pos_alg_8(int8_t value_to_map) -{ - if (value_to_map < 0) - /* NOTE: possible integer overflow is intended */ - return (uint8_t)((-value_to_map) * 2 - 1); - else - /* NOTE: possible integer overflow is intended */ - return (uint8_t)(value_to_map * 2); -} - - -static uint16_t map_to_pos_alg_16(int16_t value_to_map) -{ - if (value_to_map < 0) - /* NOTE: possible integer overflow is intended */ - return (uint16_t)((-value_to_map) * 2 - 1); + /* 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 - /* NOTE: possible integer overflow is intended */ - return (uint16_t)(value_to_map * 2); -} + setup->generate_cw_f = &golomb_encoder; + setup->bitstream_adr = cfg->icu_output_buf; + setup->max_stream_len = cmp_buffer_length_to_bits(cfg->buffer_length, cfg->data_type); -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 0; } /** - * @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 imagette 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_SAMLL_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 */ -static int map_to_pos_16(uint16_t *data_buf, uint32_t samples, int zero_mode_used) +static int compress_imagette(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; + struct encoder_setupt setup; + + 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->samples == 0) + return 0; + + 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; + } - if (!data_buf) + err = configure_encoder_setup(&setup, cfg->golomb_par, cfg->spill, + cfg->round, max_used_bits.nc_imagette, 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], 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; + + 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 + * @brief compress the multi-entry packet header structure and sets the data, + * model and up_model pointers to the data after the header * - * @note overwrite the data_buf in-place with the result + * @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 uint32_t data buffer to process - * @param samples amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used + * @returns the bit length of the bitstream on success; negative on error, * - * @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 map_to_pos_32(uint32_t *data_buf, uint32_t samples, int - zero_mode_used) +static int compress_multi_entry_hdr(void **data, void **model, void **up_model, + const struct cmp_cfg *cfg) { - size_t i; - - if (!data_buf) + if (cfg->buffer_length < 1) 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; + if (*data) { + if (cfg->icu_output_buf) + memcpy(cfg->icu_output_buf, *data, MULTI_ENTRY_HDR_SIZE); + *data = (uint8_t *)*data + MULTI_ENTRY_HDR_SIZE; } - return 0; + + if (*model) + *model = (uint8_t *)*model + MULTI_ENTRY_HDR_SIZE; + + if (*up_model) { + if (*data) + memcpy(*up_model, *data, MULTI_ENTRY_HDR_SIZE); + *up_model = (uint8_t *)*up_model + MULTI_ENTRY_HDR_SIZE; + } + + return MULTI_ENTRY_HDR_SIZE * CHAR_BIT; } /** - * @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 short normal light flux (S_FX) 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_SAMLL_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(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) - return -1; + 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); - for (i = 0; i < samples; i++) { - data_buf[i].EXPOSURE_FLAGS = - map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX); + if (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; - 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; + + 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 S_FX_EFX buffer - * - * @note overwrite the data_buf in-place with the result + * @brief compress S_FX_EFX 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_SAMLL_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(const struct cmp_cfg *cfg) { + int err; + int stream_len = 0; size_t i; - if (!data_buf) - return -1; + 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); - 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_efx, cfg->cmp_par_efx, cfg->spill_efx, + cfg->round, max_used_bits.s_efx, 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].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_NCOB 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_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_SAMLL_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_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; - for (i = 0; i < samples; i++) { - data_buf[i].EXPOSURE_FLAGS = - map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = map_to_pos_alg_32(data_buf[i].NCOB_Y); + if (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); + + 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; - 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_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_NCOB_ECOB 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_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 + * @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_SAMLL_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_s_fx_efx_ncob_ecob(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 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); + + 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; + + 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 + * @brief compress F_FX data * - * @note change the data_buf in-place + * @param cfg pointer to the compression configuration structure * - * @param cfg configuration contains all parameters required for compression - * - * @returns 0 on success, error otherwise + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SAMLL_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(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 *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 (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); + + 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; - 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; - 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 (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; - return -1; + model = next_model_p[i]; + } + return stream_len; } /** - * @brief forms the codeword accurate to the Rice code and returns its length + * @brief compress F_FX_EFX 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_SAMLL_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(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 *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; - 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); + + 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 stream_len; } /** - * @brief forms the codeword accurate to the Golomb code and returns its length + * @brief compress F_FX_NCOB 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_SAMLL_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_f_fx_ncob(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 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 (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); + + 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_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; -typedef unsigned int (*encoder_ptr)(unsigned int, unsigned int, unsigned int, - unsigned int*); + 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); + } -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 F_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_SAMLL_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_f_fx_efx_ncob_ecob(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 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; - /* 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; - /* leave in case of erroneous input */ - if (nBits == 0) - return 0; - if (nBits > 32) - return 0; + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); - /* separate the bitOffset into word offset (set localAddr pointer) and local bit offset (bitsLeft) */ - localAddr = destAddr + (bitOffset >> 5); - bitsLeft = bitOffset & 0x1f; + 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; + } - /* (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; + 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; - /* to see if we need to split the value over two words we need the right end position */ - localEndPos = bitsLeft + nBits; + 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 (localEndPos <= 32) { - /* UNSEGMENTED - * - *|-----------|XXXXX|----------------| - * bitsLeft n bitsRight - * - * -> to get the mask: - * shiftRight = bitsLeft + bitsRight = 32 - n - * shiftLeft = bitsRight - * - */ + if (i >= cfg->samples-1) + break; - /* shiftRight = 32 - nBits; */ /* see (M) above! */ - shiftLeft = shiftRight - bitsLeft; + model = next_model_p[i]; + } + return stream_len; +} - /* generate the mask, the bits for the values will be true */ - /* mask = (0xffffffff >> shiftRight) << shiftLeft; */ /* see (M) above! */ - mask <<= shiftLeft; - /* clear the destination with inverse mask */ - *(localAddr) &= ~mask; +/** + * @brief compress L_FX data + * + * @param cfg pointer to the compression configuration structure + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SAMLL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ - /* assign the value */ - *(localAddr) |= (value << (32 - localEndPos)); /* NOTE: 32-localEndPos = shiftLeft can be simplified */ +static int compress_l_fx(const struct cmp_cfg *cfg) +{ + int err; + int stream_len = 0; + size_t i; - } 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 - * - */ + 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; - unsigned int n2 = bitsLeft + nBits - 32; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - /* part 1: */ - shiftRight = bitsLeft; - mask = 0xffffffff >> shiftRight; + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); - /* clear the destination with inverse mask */ - *(localAddr) &= ~mask; + 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; + } - /* assign the value part 1 */ - *(localAddr) |= (value >> n2); + 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; - /* part 2: */ - /* adjust address */ - localAddr += 1; - shiftLeft = 64 - bitsLeft - nBits; - mask = 0xffffffff << shiftLeft; + 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); + } - /* clear the destination with inverse mask */ - *(localAddr) &= ~mask; + if (i >= cfg->samples-1) + break; - /* assign the value part 2 */ - *(localAddr) |= (value << (32 - n2)); + model = next_model_p[i]; } - return nBits; + return stream_len; } -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 */ -}; - +/** + * @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_SAMLL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ -static int encode_raw(struct cmp_cfg *cfg, struct encoder_struct *enc) +static int compress_l_fx_efx(const struct cmp_cfg *cfg) { - size_t cmp_size_in_bytes; - - if (!cfg) - return -1; + int err; + int stream_len = 0; + size_t i; - if (!cfg->icu_output_buf) - return -1; + 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; - if (!cfg->input_buf) - return -1; + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - cmp_size_in_bytes = cfg->samples * size_of_a_sample(cfg->cmp_mode); + stream_len = compress_multi_entry_hdr((void **)&data_buf, (void **)&model_buf, + (void **)&up_model_buf, cfg); - enc->cmp_size = cmp_size_in_bytes * CHAR_BIT; /* cmp_size is measured in bits */ + 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 (cmp_size_in_bytes > cfg->buffer_length * sizeof(uint16_t)) + 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; - memcpy(cfg->icu_output_buf, cfg->input_buf, cmp_size_in_bytes); + 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); + } - return 0; + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; + } + return stream_len; } -static int encode_raw_16(struct cmp_cfg *cfg, struct encoder_struct *enc) +/** + * @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_SAMLL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ + +static int compress_l_fx_ncob(const struct cmp_cfg *cfg) { int err; + int stream_len = 0; size_t i; - enc->cmp_size = 0; + 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; - 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; - } + if (model_mode_is_used(cfg->cmp_mode)) + up_model_buf = cfg->icu_new_model_buf; - return 0; -} + stream_len = compress_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 encode_raw_S_FX(struct cmp_cfg *cfg, struct encoder_struct *enc) -{ - int err; - - err = encode_raw(cfg, enc); + 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 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_ncob, cfg->cmp_par_ncob, cfg->spill_ncob, + cfg->round, max_used_bits.l_ncob, 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; -#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); + 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); } + + if (i >= cfg->samples-1) + break; + + model = next_model_p[i]; } -#endif - return 0; + return stream_len; } -static int encode_normal(uint32_t value_to_encode, struct cmp_cfg *cfg, - struct encoder_struct *enc) +/** + * @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_SAMLL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ + +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); - - err = put_n_bits32(code_word, enc->cmp_size, cw_len, - cfg->icu_output_buf, cfg->buffer_length); - if (err <= 0) - return err; - - enc->cmp_size += cw_len; + 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; - 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); -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_SAMLL_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); -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_SAMLL_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); - 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_SAMLL_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); - 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.smeating_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.smeating_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; - - err = encode_value(data_to_encode[i].FX, 32, 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_SAMLL_BUF if the bitstream buffer is too small to put the + * value in the bitstream + */ - err = encode_value(data_to_encode[i].NCOB_X, 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_Y, 32, cfg, enc); - if (err) - return err; + if (cmp_size < 0) + return cmp_size; - err = encode_value(data_to_encode[i].EFX, 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_X, 32, cfg, enc); - if (err) - return err; + /* no padding in RAW mode*/ + if (cfg->cmp_mode == CMP_MODE_RAW) + return cmp_size; - 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; +/** + * @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 + */ - enc.encoder = select_encoder(cfg->golomb_par); - enc.log2_golomb_par = ilog_2(cfg->golomb_par); - enc.cmp_size = 0; +static int cmp_data_to_big_endian(const struct cmp_cfg *cfg, unsigned int cmp_size) +{ +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + size_t i; + uint32_t *p; - 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; + if (cfg->cmp_mode == CMP_MODE_RAW) { + int err = cmp_input_big_to_cpu_endianness(cfg->icu_output_buf, + cmp_size/CHAR_BIT, cfg->data_type); + return err; } - n_bits = pad_bitstream(cfg, enc.cmp_size); - if (n_bits < 0) - return n_bits; - -#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) - { - size_t i; - uint32_t *p = (uint32_t *)cfg->icu_output_buf; - - if (p) { - for (i = 0; i < cmp_bit_to_4byte(enc.cmp_size)/sizeof(uint32_t); i++) - cpu_to_be32s(&p[i]); - } + 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)]; + cmp_size -= MULTI_ENTRY_HDR_SIZE * CHAR_BIT; } -#endif /*__BYTE_ORDER__ */ - if (err) - return err; - else - return enc.cmp_size; + for (i = 0; i < cmp_bit_to_4byte(cmp_size)/sizeof(uint32_t); i++) + cpu_to_be32s(&p[i]); +#else + /* do nothing data are already in big-endian */ + (void)cfg; +#endif /*__BYTE_ORDER__ */ + return 0; } /** * @brief compress data on the ICU * - * @param cfg compressor configuration contains all parameters required for - * compression - * @param info compressor information contains information of the executed - * compression + * @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_SAMLL_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 (!cmp_cfg_is_valid(cfg)) + return -1; - err = cmp_map_to_pos(cfg); - if (err) - return err; + if (model_mode_is_used(cfg->cmp_mode) && !cfg->model_buf) + 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)) { + if (cfg->samples > cfg->buffer_length) { + cmp_size = CMP_ERROR_SAMLL_BUF; + } else { + 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 { + 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_DFX: + 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_DFX_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_DFX: + 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_DFX_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_DFX: + 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_DFX_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: + case DATA_TYPE_UNKOWN: + default: + debug_print("Error: Data type not supported.\n"); + cmp_size = -1; + } + } - return 0; + if (cfg->icu_output_buf && cmp_size > 0) { + cmp_size = pad_bitstream(cfg, cmp_size); + cmp_data_to_big_endian(cfg, (unsigned int)cmp_size); + } + + return cmp_size; } diff --git a/lib/cmp_icu_new.c b/lib/cmp_icu_new.c deleted file mode 100644 index d69ab0f..0000000 --- a/lib/cmp_icu_new.c +++ /dev/null @@ -1,422 +0,0 @@ -/** - * @file icu_cmp.c - * @author Dominik Loidolt (dominik.loidolt@univie.ac.at), - * @date 2020 - * - * @copyright GPLv2 - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * @brief software compression library - * @see Data Compression User Manual PLATO-UVIE-PL-UM-0001 - */ - - -#include <stdint.h> - -#include "cmp_debug.h" - - -/* return code if the bitstream buffer is too small to store the whole bitstream */ -#define CMP_ERROR_SAMLL_BUF -2 - -/* pointer to a code word generation function */ -typedef uint32_t (*generate_cw_pt)(uint32_t value, uint32_t encoder_par1, - uint32_t encoder_par2, uint32_t *cw); - -/* typedef uint32_t (*next_model_f_pt)(uint32_t model_mode_val, uint32_t diff_model_var); */ - -struct encoder_setupt { - /* unsigned int lossy_par; */ - /* next_model_f_pt *next_model_f; */ - generate_cw_pt generate_cw; /* pointer to the code word generation function */ - /* uint32_t updated_model; */ - uint32_t encoder_par1; - uint32_t encoder_par2; - uint32_t outlier_par; - uint32_t model_value; - uint32_t max_value_bits; /* how many bits are needed to represent the highest possible value */ - uint32_t max_bit_len; /* maximum length of the bitstream/icu_output_buf in bits */ - uint32_t *bitstream_adr; -}; - - -/** - * @brief map a signed value into a positive value range - * - * @param value_to_map signed value to map - * @param max_value_bits how many bits are needed to represent the - * highest possible value - * - * @returns the positive mapped value - */ - -static uint32_t map_to_pos(uint32_t value_to_map, unsigned int max_value_bits) -{ - uint32_t mask = (~0U >> (32 - max_value_bits)); /* mask the used bits */ - - value_to_map &= mask; - if (value_to_map >> (max_value_bits - 1)) { /* check the leading signed bit */ - value_to_map |= ~mask; /* convert to 32-bit signed integer */ - /* map negative values to uneven numbers */ - return (-value_to_map) * 2 - 1; /* possible integer overflow is intended */ - } else { - /* map positive values to even numbers */ - return value_to_map * 2; /* possible integer overflow is intended */ - } -} - - -/** - * @brief 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 - * @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_bit_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_SAMLL_BUF if - * the bitstream buffer is too small to put the value in the bitstream - */ - -static int put_n_bits32(uint32_t value, unsigned int n_bits, int bit_offset, - uint32_t *bitstream_adr, unsigned int max_bit_len) -{ - 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 */ - - /* leave in case of erroneous input */ - if (bit_offset < 0) - return -1; - - if (n_bits == 0) - return stream_len; - - 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_bit_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_SAMLL_BUF; - } - - /* (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 << shiftLeft; - - /* clear the destination with inverse mask */ - *(local_adr) &= ~mask; - - /* assign the value part 2 */ - *(local_adr) |= (value << shiftLeft); - } - return stream_len; -} - - -/** - * @brief forms the codeword according to the Rice code - * - * @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 the length of the formed code word in bits - * @note no check if the generated code word is not longer than 32 bits. - */ - -static uint32_t Rice_encoder(uint32_t value, uint32_t m, uint32_t log2_m, - uint32_t *cw) -{ - 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 */ - - g = value >> log2_m; /* quotient, number of leading bits */ - q = (1U << g) - 1; /* prepare the quotient code without ending zero */ - - r = value & (m-1); /* calculate the remainder */ - rl = log2_m + 1; /* length of the remainder (+1 for the 0 in the quotient code) */ - *cw = (q << rl) | r; /* put the quotient and remainder code together */ - /* - * 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. - */ - - return rl + g; /* calculate the length of the code word */ -} - - -/** - * @brief forms a codeword according to the Golomb code - * - * @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 the length of the formed code word in bits - */ - -static uint32_t Golomb_encoder(uint32_t value, uint32_t m, uint32_t log2_m, - uint32_t *cw) -{ - uint32_t len0, b, g, q, lg; - uint32_t len; - uint32_t cutoff; - - len0 = log2_m + 1; /* codeword length in group 0 */ - cutoff = (1U << (log2_m + 1)) - m; /* members in group 0 */ - - 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 len; -} - - -/** - * @brief generate a code word without a outlier mechanism and put in the - * bitstream - * - * @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 the bit length of the bitstream with the added encoded value on - * success; negative on error - */ - -static int encode_normal(uint32_t value, int stream_len, - struct encoder_setupt *setup) -{ - uint32_t code_word, cw_len; - - cw_len = setup->generate_cw(value, setup->encoder_par1, - setup->encoder_par2, &code_word); - - return put_n_bits32(code_word, cw_len, stream_len, setup->bitstream_adr, - setup->max_bit_len); -} - - -/** - * @brief subtract the model from the data, encode the result and put it into - * bitstream, for encodeing outlier use the zero escape symbol mechanism - * - * @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_SAMLL_BUF if the bitstream buffer - * is too small to put the value in the bitstream - * - * @note no check if data or model are in the allowed range - * @note no check if the setup->outlier_par is in the allowed range - */ - -static int encode_value_zero(uint32_t data, uint32_t model, int stream_len, - struct encoder_setupt *setup) -{ - data -= model; - - data = map_to_pos(data, setup->max_value_bits); - - /* 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->outlier_par && data != 0) - * return ... - */ - if (data < (setup->outlier_par - 1)) { /* detect r */ - data++; /* add 1 to every value so we can use 0 as escape symbol */ - return encode_normal(data, stream_len, setup); - } - - 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_value_bits, stream_len, - setup->bitstream_adr, setup->max_bit_len); - - return stream_len; - -} - - -/** - * @brief subtract the model from the data, encode the result and put it into - * bitstream, for encoding outlier use the multi escape symbol mechanism - * - * @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_SAMLL_BUF if the bitstream buffer - * is too small to put the value in the bitstream - * - * @note no check if data or model are in the allowed range - * @note no check if the setup->outlier_par is in the allowed ragne - */ - -static int encode_value_multi(uint32_t data, uint32_t model, int stream_len, - struct encoder_setupt *setup) -{ - uint32_t unencoded_data; - unsigned int unencoded_data_len; - uint32_t escape_sym, escape_sym_offset; - - data -= model; /* possible underflow is intended */ - - data = map_to_pos(data, setup->max_value_bits); - - if (data < setup->outlier_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 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 outlier_par + 0 - * 3, 4 bits needed for unencoded data -> escape symbol is outlier_par + 1 - * 5, 6 bits needed for unencoded data -> escape symbol is outlier_par + 2 - * and so on - */ - unencoded_data = data - setup->outlier_par; - - 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; - - escape_sym = setup->outlier_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_bit_len); - - return stream_len; -} diff --git a/lib/cmp_io.c b/lib/cmp_io.c index 7c00d56..99e80c6 100644 --- a/lib/cmp_io.c +++ b/lib/cmp_io.c @@ -32,6 +32,38 @@ #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_DFX, "DATA_TYPE_S_FX_DFX"}, + {DATA_TYPE_S_FX_NCOB, "DATA_TYPE_S_FX_NCOB"}, + {DATA_TYPE_S_FX_DFX_NCOB_ECOB, "DATA_TYPE_S_FX_DFX_NCOB_ECOB"}, + {DATA_TYPE_L_FX, "DATA_TYPE_L_FX"}, + {DATA_TYPE_L_FX_DFX, "DATA_TYPE_L_FX_DFX"}, + {DATA_TYPE_L_FX_NCOB, "DATA_TYPE_L_FX_NCOB"}, + {DATA_TYPE_L_FX_DFX_NCOB_ECOB, "DATA_TYPE_L_FX_DFX_NCOB_ECOB"}, + {DATA_TYPE_F_FX, "DATA_TYPE_F_FX"}, + {DATA_TYPE_F_FX_DFX, "DATA_TYPE_F_FX_DFX"}, + {DATA_TYPE_F_FX_NCOB, "DATA_TYPE_F_FX_NCOB"}, + {DATA_TYPE_F_FX_DFX_NCOB_ECOB, "DATA_TYPE_F_FX_DFX_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_UNKOWN, "DATA_TYPE_UNKOWN"} +}; + + /** * @brief print help information * @@ -114,31 +146,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, @@ -146,8 +181,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 @@ -159,8 +198,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 @@ -170,6 +209,7 @@ int write_to_file16(const uint16_t *buf, uint32_t buf_len, const char printf("\n\n"); } + free(tmp_buf); return 0; } @@ -356,6 +396,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_UNKOWN on error + */ + +enum cmp_data_type string2data_type(const char *data_type_str) +{ + enum cmp_data_type data_type = DATA_TYPE_UNKOWN; + + 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_UNKOWN; + } + } + } + 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_UNKOWN on error + */ + +const char *data_type2string(enum cmp_data_type data_type) +{ + size_t j; + const char *string = "DATA_TYPE_UNKOWN"; + + 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 @@ -373,11 +474,16 @@ int cmp_mode_parse(const char *cmp_mode_str, 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) @@ -398,7 +504,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; @@ -450,9 +556,16 @@ 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_UNKOWN) + 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*/ + /* TODO: use conversion function for this: */ if (!strcmp(token2, "MODE_RAW")) { cfg->cmp_mode = 0; continue; @@ -645,12 +758,6 @@ 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; } @@ -705,6 +812,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; @@ -1013,7 +1121,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 @@ -1026,14 +1134,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; @@ -1043,12 +1151,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; @@ -1118,8 +1226,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 @@ -1132,13 +1239,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; @@ -1165,6 +1272,10 @@ ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t n_word, int ver fclose(fp); return 0; } + if (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; @@ -1188,7 +1299,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; @@ -1206,75 +1317,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; } @@ -1292,7 +1366,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; @@ -1307,9 +1381,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_UNKOWN) { fprintf(stderr, "%s: %s: Error: Compression data type is not supported.\n", PROGRAM_NAME, file_name); return -1; @@ -1328,6 +1402,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 @@ -1371,7 +1480,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; } @@ -1389,6 +1498,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 = %u\n", 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 c24ebed..34606f4 100644 --- a/lib/cmp_rdcu.c +++ b/lib/cmp_rdcu.c @@ -15,21 +15,36 @@ * * @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 "../include/rdcu_cmd.h" -#include "../include/cmp_support.h" -#include "../include/rdcu_ctrl.h" -#include "../include/rdcu_rmap.h" +#include "rdcu_cmd.h" +#include "cmp_support.h" +#include "cmp_data_types.h" +#include "rdcu_ctrl.h" +#include "rdcu_rmap.h" +#include "cmp_debug.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 +63,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 +79,84 @@ static void sync(void) } +/** + * @brief check if the compression data product type, compression mode, model + * value and the lossy rounding parameters are valid for a 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 a 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 a RDCU compression configuration + * + * @param data_type compression data product types + * @param cmp_mode compression mode + * @param model_value model weighting parameter (only need for model compression mode) + * @param lossy_par lossy rounding parameter (use CMP_LOSSLESS for lossless compression) + * + * @returns compression configuration containing the chosen parameters; + * on error the data_type record is set to DATA_TYPE_UNKOWN + */ + +struct cmp_cfg rdcu_cfg_create(enum cmp_ent_data_type data_type, enum cmp_mode cmp_mode, + uint32_t model_value, uint32_t lossy_par) +{ + struct cmp_cfg cfg = {0}; + + 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_UNKOWN; + + return cfg; +} + /** * @brief check if a buffer is in inside the RDCU SRAM * @@ -99,6 +193,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 +205,373 @@ 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 multi entity 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 data to compress start address, the first + * data address in the RDCU SRAM + * @param rdcu_model_adr RDCU model start address, the first model address + * in the RDCU SRAM (only need for model compression mode) + * @param rdcu_new_model_adr RDCU 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 compressed data start address, the first + * output data address in the RDCU SRAM + * @param rdcu_buffer_lenght length of the RDCU compressed data SRAM buffer + * in number of 16-bit 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 a 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_RDCU_GOLOMB_PAR || + cfg->golomb_par > MAX_RDCU_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_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) { + 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_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) { + 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_RDCU_GOLOMB_PAR, MAX_RDCU_GOLOMB_PAR); + cfg_invalid++; + } + + if (cfg->spill < MIN_RDCU_SPILL) { + debug_print("Error: The selected spillover threshold value: %u is too small. Smallest possible spillover value is: %u.\n", + cfg->spill, MIN_RDCU_SPILL); + cfg_invalid++; + } + + if (cfg->spill > get_max_spill(cfg->golomb_par, cfg->data_type)) { + 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, get_max_spill(cfg->golomb_par, cfg->data_type)); + cfg_invalid++; + } + + if (cfg->ap1_spill < MIN_RDCU_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_RDCU_SPILL); + cfg_invalid++; + } + + if (cfg->ap1_spill > get_max_spill(cfg->ap1_golomb_par, cfg->data_type)) { + 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, get_max_spill(cfg->ap1_golomb_par, cfg->data_type)); + cfg_invalid++; + } + + if (cfg->ap2_spill < MIN_RDCU_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_RDCU_SPILL); + cfg_invalid++; + } + + if (cfg->ap2_spill > get_max_spill(cfg->ap2_golomb_par, cfg->data_type)) { + 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, get_max_spill(cfg->ap2_golomb_par, cfg->data_type)); + 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 (Golomb parameter) + * @param spillover_par imagette spillover threshold parameter + * @param ap1_golomb_par adaptive 1 imagette compression parameter (ap1_golomb parameter) + * @param ap1_spillover_par adaptive 1 imagette spillover threshold parameter + * @param ap2_golomb_par adaptive 2 imagette compression parameter (ap2_golomb parameter) + * @param ap2_spillover_par adaptive 1 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 a 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 */ @@ -509,8 +675,6 @@ int rdcu_start_compression(void) * * @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 * @@ -700,7 +864,7 @@ 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) return (int)s; @@ -790,19 +954,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 +985,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 +994,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 +1015,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 93db7b6..a02e897 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,278 @@ 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_UNKOWN || data_type > DATA_TYPE_F_CAM_OFFSET) + 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) +{ + if (cmp_mode == CMP_MODE_DIFF_ZERO || + cmp_mode == CMP_MODE_DIFF_MULTI) + return 1; + + return 0; +} + + +/** + * @brief check if the raw mode is selected + * + * @param cmp_mode compression mode + * + * @returns 1 when the raw mode is used, otherwise 0 + */ + +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_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: + 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; default: return 0; - break; } + } /** - * @brief check if the raw mode is selected + * @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 types * - * @returns 1 when raw mode is set, otherwise 0 + * @returns 1 when the data type is supported by the RDCU, otherwise 0 */ -int raw_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_RAW_S_FX: - case MODE_RAW_32: + 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 supported by the RDCU compressor + * @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 supported by the RDCU, otherwise 0 + * @returns 1 when the compression mode is supported, otherwise 0 */ -int rdcu_supported_mode_is_used(unsigned int cmp_mode) +int cmp_mode_is_supported(enum cmp_mode cmp_mode) { switch (cmp_mode) { - case MODE_RAW: - case MODE_MODEL_ZERO: - case MODE_DIFF_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_MULTI: + 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; + } + return 0; +} + + +/** + * @brief check if zero escape symbol mechanism mode is used + * + * @param cmp_mode compression mode + * + * @returns 1 when zero escape symbol mechanism is set, otherwise 0 + */ + +int zero_escape_mech_is_used(enum cmp_mode cmp_mode) +{ + 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) +{ + 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 an adaptive imagette compression data type is used * - * @param cmp_mode compression mode + * @param data_type compression data type * - * @returns 1 when mode is available, otherwise 0 + * @returns 1 when data_type is an adaptive imagette data type, otherwise 0 */ -int cmp_mode_available(unsigned int cmp_mode) +int cmp_ap_imagette_data_type_is_used(enum cmp_data_type data_type) { - if (diff_mode_is_used(cmp_mode) || - model_mode_is_used(cmp_mode) || - raw_mode_is_used(cmp_mode)) + switch (data_type) { + case DATA_TYPE_IMAGETTE_ADAPTIVE: + case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: + case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: return 1; - else + default: return 0; - + } } /** - * @brief check if zero escape symbol mechanism mode is used + * @brief check if a flux/center of brightness compression data type is used * - * @param cmp_mode compression mode + * @param data_type compression data type * - * @returns 1 when zero escape symbol mechanism is set, otherwise 0 + * @returns 1 when data_type is a flux/center of brightness data type, otherwise 0 */ -int zero_escape_mech_is_used(unsigned int cmp_mode) +int cmp_fx_cob_data_type_is_used(enum cmp_data_type data_type) { - 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: + switch (data_type) { + 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: return 1; - break; default: return 0; - break; } - } /** - * @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 +336,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 +351,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 +365,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,9 +374,14 @@ 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) + { + /* 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); @@ -402,13 +393,13 @@ unsigned int cal_up_model(unsigned int data, unsigned int model, unsigned int /** * @brief get the maximum valid spill threshold value for a given golomb_par * - * @param golomb_par Golomb parameter - * @param cmp_mode compression mode + * @param golomb_par Golomb parameter + * @param data_type compression data type * * @returns the highest still valid spill threshold value */ -uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode) +uint32_t get_max_spill(unsigned int golomb_par, enum cmp_data_type data_type) { const uint32_t LUT_MAX_RDCU[MAX_RDCU_GOLOMB_PAR+1] = { 0, 8, 22, 35, 48, 60, 72, 84, 96, 107, 118, 129, 140, 151, 162, 173, 184, 194, @@ -420,208 +411,447 @@ uint32_t get_max_spill(unsigned int golomb_par, unsigned int cmp_mode) if (golomb_par == 0) return 0; - if (rdcu_supported_mode_is_used(cmp_mode)) { + /* the RDCU can only generate 16 bit long code words -> lower max spill needed */ + if (rdcu_supported_data_type_is_used(data_type)) { if (golomb_par > MAX_RDCU_GOLOMB_PAR) return 0; return LUT_MAX_RDCU[golomb_par]; + } + + if (golomb_par > MAX_ICU_GOLOMB_PAR) { + return 0; } 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; + /* 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 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 valid for a ICU compression + * + * @param cfg pointer to the compressor configuration + * + * @returns 1 if generic compression parameters are valid, otherwise 0 + */ + +int cmp_cfg_icu_gen_par_is_valid(const struct cmp_cfg *cfg) +{ + int cfg_invalid = 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: %u 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++; + } + + if (cfg_invalid) + return 0; + + return 1; } /** - * @brief get a good spill threshold parameter for the selected Golomb parameter - * and compression mode + * @brief check if the buffer parameters are valid * - * @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 1 if the buffer parameters are valid, otherwise 0 */ -uint32_t cmp_get_good_spill(unsigned int golomb_par, unsigned int cmp_mode) +int cmp_cfg_icu_buffers_is_valid(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 }; + int cfg_invalid = 0; - if (zero_escape_mech_is_used(cmp_mode)) - return get_max_spill(golomb_par, cmp_mode); + if (!cfg) + return 0; - if (cmp_mode == MODE_MODEL_MULTI) { - if (golomb_par > MAX_RDCU_GOLOMB_PAR) - return 0; - else - return LUT_RDCU_MULIT[golomb_par]; + 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 && cfg->buffer_length == 0 && cfg->samples != 0) { + debug_print("Error: The buffer_length is set to 0. There is no space to store the compressed data.\n"); + cfg_invalid++; + } + + if (cfg->icu_output_buf == cfg->input_buf) { + debug_print("Error: The 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++; + } + } + } + + if (raw_mode_is_used(cfg->cmp_mode)) { + if (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++; + } + } else { + if (cfg->samples < cfg->buffer_length/3) + debug_print("Warning: The size of the compressed_data buffer is 3 times smaller than the data_to_compress. This is probably unintended.This is probably unintended.\n"); + } + + if (cfg_invalid) + return 0; + + return 1; } /** - * @brief calculate the size of a sample for the different compression modes + * @brief check if the combination of the different compression parameters is valid * - * @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 1 if the parameter combination is valid, otherwise 0 */ -size_t size_of_a_sample(unsigned int cmp_mode) +static int cmp_pars_are_valid(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; + + if (!par_name) + par_name = ""; switch (cmp_mode) { - case MODE_RAW: - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - sample_len = sizeof(uint16_t); - break; - case MODE_RAW_S_FX: - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - sample_len = sizeof(struct S_FX); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - sample_len = sizeof(struct S_FX_NCOB); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - sample_len = sizeof(struct S_FX_EFX_NCOB_ECOB); + case CMP_MODE_RAW: + /* no checks needed */ break; - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - sample_len = sizeof(struct F_FX); - break; - case MODE_MODEL_ZERO_F_FX_EFX: - case MODE_MODEL_MULTI_F_FX_EFX: - case MODE_DIFF_ZERO_F_FX_EFX: - case MODE_DIFF_MULTI_F_FX_EFX: - sample_len = sizeof(struct F_FX_EFX); - break; - case MODE_MODEL_ZERO_F_FX_NCOB: - case MODE_MODEL_MULTI_F_FX_NCOB: - case MODE_DIFF_ZERO_F_FX_NCOB: - case MODE_DIFF_MULTI_F_FX_NCOB: - sample_len = sizeof(struct F_FX_NCOB); - break; - case MODE_MODEL_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_F_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_F_FX_EFX_NCOB_ECOB: - sample_len = sizeof(struct F_FX_EFX_NCOB_ECOB); + 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_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 CMP_MODE_DIFF_ZERO: + case CMP_MODE_DIFF_MULTI: + case CMP_MODE_MODEL_ZERO: + case CMP_MODE_MODEL_MULTI: + if (cmp_par < MIN_ICU_GOLOMB_PAR || + cmp_par > MAX_ICU_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_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR); + cfg_invalid++; + } + if (spill < MIN_ICU_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_ICU_SPILL); + cfg_invalid++; + } + if (spill > get_max_spill(cmp_par, data_type)) { + 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, get_max_spill(cmp_par, data_type)); + cfg_invalid++; + } + break; default: - debug_print("Error: Compression mode not supported.\n"); - return 0; + debug_print("Error: The compression mode is not supported.\n"); + cfg_invalid++; break; } - return sample_len; + + if (cfg_invalid) + return 0; + + return 1; } /** - * @brief calculates the number of samples for a given data size for the - * different compression modes + * @brief check if the imagette specific compression parameters are valid * - * @param size size of the data me - * @param cmp_mode compression mode + * @param cfg pointer to the compressor configuration * - * @returns the number samples for the given compression mode; negative on error + * @returns 1 if the imagette specific parameters are valid, otherwise 0 */ -int cmp_input_size_to_samples(unsigned int size, unsigned int cmp_mode) +int cmp_cfg_imagette_is_valid(const struct cmp_cfg *cfg) { - unsigned int samples_size = size_of_a_sample(cmp_mode); + int cfg_invalid = 0; - if (!samples_size) - return -1; + if (!cfg) + return 0; - if (!rdcu_supported_mode_is_used(cmp_mode)) { - if (size < N_DPU_ICU_MULTI_ENTRY_HDR_SIZE) - return -1; - size -= N_DPU_ICU_MULTI_ENTRY_HDR_SIZE; + 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++; } - if (size % samples_size) - return -1; + if (!cmp_pars_are_valid(cfg->golomb_par, cfg->spill, cfg->cmp_mode, + cfg->data_type, "imagette")) + cfg_invalid++; + + if (cmp_ap_imagette_data_type_is_used(cfg->data_type)) { + if (!cmp_pars_are_valid(cfg->ap1_golomb_par, cfg->ap1_spill, + cfg->cmp_mode, cfg->data_type, "adaptive 1 imagette")) + cfg_invalid++; + if (!cmp_pars_are_valid(cfg->ap2_golomb_par, cfg->ap2_spill, + cfg->cmp_mode, cfg->data_type, "adaptive 2 imagette")) + cfg_invalid++; + } - return size/samples_size; + if (cfg_invalid) + return 0; + + return 1; } /** - * @brief calculate the need bytes to hold a bitstream + * @brief check if the flux/center of brightness specific compression parameters are valid * - * @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 1 if the flux/center of brightness specific parameters are valid, otherwise 0 */ -unsigned int cmp_bit_to_4byte(unsigned int cmp_size_bit) +int cmp_cfg_fx_cob_is_valid(const struct cmp_cfg *cfg) { - return (((cmp_size_bit + 7) / 8) + 3) & ~0x3UL; + 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 */ + if (!cmp_pars_are_valid(cfg->cmp_par_fx, cfg->spill_fx, cfg->cmp_mode, cfg->data_type, "flux")) + cfg_invalid++; + + switch (cfg->data_type) { + case DATA_TYPE_S_FX: + check_exp_flags = 1; + break; + case DATA_TYPE_S_FX_DFX: + 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_DFX_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_DFX: + check_exp_flags = 1; + check_efx = 1; + check_var = 1; + break; + case DATA_TYPE_L_FX_NCOB: + check_exp_flags = 1; + check_ncob = 1; + check_var = 1; + break; + case DATA_TYPE_L_FX_DFX_NCOB_ECOB: + check_exp_flags = 1; + check_ncob = 1; + check_efx = 1; + check_ecob = 1; + check_var = 1; + break; + case DATA_TYPE_F_FX: + break; + case DATA_TYPE_F_FX_DFX: + check_efx = 1; + break; + case DATA_TYPE_F_FX_NCOB: + check_ncob = 1; + break; + case DATA_TYPE_F_FX_DFX_NCOB_ECOB: + check_ncob = 1; + check_efx = 1; + check_ecob = 1; + break; + default: + cfg_invalid++; + break; + } + + if (check_exp_flags && !cmp_pars_are_valid(cfg->cmp_par_exp_flags, cfg->spill_exp_flags, cfg->cmp_mode, cfg->data_type, "exposure flags")) + cfg_invalid++; + if (check_ncob && !cmp_pars_are_valid(cfg->cmp_par_ncob, cfg->spill_ncob, cfg->cmp_mode, cfg->data_type, "center of brightness")) + cfg_invalid++; + if (check_efx && !cmp_pars_are_valid(cfg->cmp_par_efx, cfg->spill_efx, cfg->cmp_mode, cfg->data_type, "extended flux")) + cfg_invalid++; + if (check_ecob && !cmp_pars_are_valid(cfg->cmp_par_ecob, cfg->spill_ecob, cfg->cmp_mode, cfg->data_type, "extended center of brightness")) + cfg_invalid++; + if (check_var && !cmp_pars_are_valid(cfg->cmp_par_fx_cob_variance, cfg->spill_fx_cob_variance, cfg->cmp_mode, cfg->data_type, "flux COB varianc")) + cfg_invalid++; + + if (cfg_invalid) + return 0; + + return 1; } /** - * @brief calculate the need bytes for the data + * @brief check if the auxiliary science specific compression parameters are valid * - * @param samples number of data samples - * @param cmp_mode used compression mode + * @param cfg pointer to the compressor configuration * - * @note for non RDCU modes the N_DPU ICU multi entry header size is added + * @returns 1 if the auxiliary science specific parameters are valid, otherwise 0 + */ + +int cmp_cfg_aux_is_valid(const struct cmp_cfg *cfg) +{ + 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++; + } + + if (!cmp_pars_are_valid(cfg->cmp_par_mean, cfg->spill_mean, cfg->cmp_mode, cfg->data_type, "mean")) + cfg_invalid++; + if (!cmp_pars_are_valid(cfg->cmp_par_variance, cfg->spill_variance, cfg->cmp_mode, cfg->data_type, "variance")) + cfg_invalid++; + if (cfg->data_type != DATA_TYPE_OFFSET && cfg->data_type != DATA_TYPE_F_CAM_OFFSET) + if (!cmp_pars_are_valid(cfg->cmp_par_pixels_error, cfg->spill_pixels_error, cfg->cmp_mode, cfg->data_type, "outlier pixls num")) + cfg_invalid++; + + if (cfg_invalid) + return 0; + + return 1; +} + + +/** + * @brief check if a compression configuration is valid * - * @returns the size in bytes to store the data sample + * @param cfg pointer to the compressor configuration + * + * @returns 1 if the compression configuration is valid, otherwise 0 */ -unsigned int cmp_cal_size_of_data(unsigned int samples, unsigned int cmp_mode) +int cmp_cfg_is_valid(const struct cmp_cfg *cfg) { - unsigned int s = samples * size_of_a_sample(cmp_mode); + int cfg_invalid = 0; + + if (!cfg) + return 0; + + if (!cmp_cfg_icu_gen_par_is_valid(cfg)) + cfg_invalid++; + + if (!cmp_cfg_icu_buffers_is_valid(cfg)) + cfg_invalid++; + + if (cmp_imagette_data_type_is_used(cfg->data_type)) { + if (!cmp_cfg_imagette_is_valid(cfg)) + cfg_invalid++; + } else if (cmp_fx_cob_data_type_is_used(cfg->data_type)) { + if (!cmp_cfg_fx_cob_is_valid(cfg)) + cfg_invalid++; + } else if (cmp_aux_data_type_is_used(cfg->data_type)) { + if (!cmp_cfg_aux_is_valid(cfg)) + cfg_invalid++; + } else { + cfg_invalid++; + } - if (!rdcu_supported_mode_is_used(cmp_mode)) - s += N_DPU_ICU_MULTI_ENTRY_HDR_SIZE; + if (cfg_invalid) + return 0; - return s; + return 1; } @@ -630,7 +860,6 @@ 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) diff --git a/lib/decmp.c b/lib/decmp.c index 4953f5d..c22e5e4 100644 --- a/lib/decmp.c +++ b/lib/decmp.c @@ -4,823 +4,43 @@ #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" +#include "byteorder.h" +#include "cmp_debug.h" +#include "cmp_support.h" +#include "cmp_data_types.h" +#include "cmp_entity.h" +#define CMP_ERROR_SAMLL_BUF -2 -double get_compression_ratio(const struct cmp_info *info) -{ - unsigned long orign_len_bits = info->samples_used * size_of_a_sample(info->cmp_mode_used) * CHAR_BIT; - - return (double)orign_len_bits/(double)info->cmp_size; -} - - -void *malloc_decompressed_data(const struct cmp_info *info) -{ - size_t sample_len; - - if (!info) - return NULL; - - if (info->samples_used == 0) - return NULL; - - sample_len = size_of_a_sample(info->cmp_mode_used); - - return malloc(info->samples_used * sample_len); -} - - -/** - * @brief decompression data pre-processing in RAW mode - * - * @note in RAW mode the data are uncompressed no pre_processing needed - * - * @param cmp_mode_used used compression mode - * - * @returns 0 on success, error otherwise - */ - -static int de_raw_pre_process(uint8_t cmp_mode_used) -{ - if (!raw_mode_is_used(cmp_mode_used)) - return -1; - - return 0; -} - - -/** - * @brief model decompression pre-processing - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the data to process - * @param model_buf pointer to the model of the data to process - * @param samples_used the size of the data and model buffer in 16 bit units - * @param model_value_used used model weighting parameter - * @param round_used used number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise - */ - -static int de_model_16(uint16_t *data_buf, uint16_t *model_buf, uint32_t - samples_used, uint8_t model_value_used, uint8_t - round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - if (!model_buf) - return -1; - - if (model_value_used > MAX_MODEL_VALUE) - return -1; - - for (i = 0; i < samples_used; i++) { - /* overflow is intended */ - data_buf[i] = (uint16_t)(data_buf[i] + round_fwd(model_buf[i], - round_used)); - } - - err = de_lossy_rounding_16(data_buf, samples_used, round_used); - if (err) - return -1; - - for (i = 0; i < samples_used; i++) { - model_buf[i] = (uint16_t)cal_up_model(data_buf[i], model_buf[i], - model_value_used); - } - return 0; -} - - -static int de_model_S_FX(struct S_FX *data_buf, struct S_FX *model_buf, uint32_t - samples_used, uint8_t model_value_used, uint8_t - round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - if (!model_buf) - return -1; - - if (model_value_used > MAX_MODEL_VALUE) - return -1; - - for (i = 0; i < samples_used; i++) { - /* overflow is intended */ - struct S_FX round_model = model_buf[i]; - - lossy_rounding_S_FX(&round_model, 1, round_used); - data_buf[i] = add_S_FX(data_buf[i], model_buf[i]); - } - - err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used); - if (err) - return -1; - - for (i = 0; i < samples_used; i++) - model_buf[i] = cal_up_model_S_FX(data_buf[i], model_buf[i], - model_value_used); - - return 0; -} - - -/** - * @brief 1d-differencing decompression per-processing - * - * @param data_buf pointer to the data to process - * @param samples_used the size of the data and model buffer in 16 bit units - * @param round_used used number of bits to round; if zero no rounding takes place - * - * @returns 0 on success, error otherwise - */ - -static int de_diff_16(uint16_t *data_buf, uint32_t samples_used, uint8_t - round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = data_buf[i] + data_buf[i-1]; - } - - err = de_lossy_rounding_16(data_buf, samples_used, round_used); - if (err) - return -1; - - return 0; -} - - -static int de_diff_32(uint32_t *data_buf, uint32_t samples_used, uint8_t - round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = data_buf[i] + data_buf[i-1]; - } - - err = de_lossy_rounding_32(data_buf, samples_used, round_used); - if (err) - return -1; - - return 0; -} - - -static int de_diff_S_FX(struct S_FX *data_buf, uint32_t samples_used, uint8_t - round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX(data_buf[i], data_buf[i-1]); - } - - err = de_lossy_rounding_S_FX(data_buf, samples_used, round_used); - if (err) - return -1; - - return 0; -} - - -static int de_diff_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t samples_used, - uint8_t round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX_EFX(data_buf[i], data_buf[i-1]); - } - - err = de_lossy_rounding_S_FX_EFX(data_buf, samples_used, round_used); - if (err) - return -1; - - return 0; -} - - -static int de_diff_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t samples_used, - uint8_t round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX_NCOB(data_buf[i], data_buf[i-1]); - } - - err = de_lossy_rounding_S_FX_NCOB(data_buf, samples_used, round_used); - if (err) - return -1; - - return 0; -} - - -static int de_diff_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - uint32_t samples_used, uint8_t round_used) -{ - size_t i; - int err; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 1; i < samples_used; i++) { - /* overflow intended */ - data_buf[i] = add_S_FX_EFX_NCOB_ECOB(data_buf[i], data_buf[i-1]); - } - - err = de_lossy_rounding_S_FX_EFX_NCOB_ECOB(data_buf, samples_used, - round_used); - if (err) - return -1; - - return 0; -} - - -static int de_pre_process(void *decoded_data, void *de_model_buf, - const struct cmp_info *info) -{ - if (!decoded_data) - return -1; - - if (!info) - return -1; - - if (info->samples_used == 0) - return 0; - - switch (info->cmp_mode_used) { - case MODE_RAW: - case MODE_RAW_S_FX: - return de_raw_pre_process(info->cmp_mode_used); - break; - case MODE_MODEL_ZERO: - case MODE_MODEL_MULTI: - return de_model_16((uint16_t *)decoded_data, - (uint16_t *)de_model_buf, info->samples_used, - info->model_value_used, info->round_used); - break; - case MODE_DIFF_ZERO: - case MODE_DIFF_MULTI: - return de_diff_16((uint16_t *)decoded_data, info->samples_used, - info->round_used); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - return de_model_S_FX((struct S_FX *)decoded_data, - (struct S_FX *)de_model_buf, - info->samples_used, info->model_value_used, - info->round_used); - break; - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return de_diff_S_FX((struct S_FX *)decoded_data, - info->samples_used, info->round_used); - break; - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return de_diff_S_FX_EFX((struct S_FX_EFX *)decoded_data, - info->samples_used, info->round_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - return -1; - break; - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return de_diff_S_FX_NCOB((struct S_FX_NCOB *)decoded_data, - info->samples_used, info->round_used); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - return -1; - break; - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return de_diff_S_FX_EFX_NCOB_ECOB((struct S_FX_EFX_NCOB_ECOB *) - decoded_data, - info->samples_used, - info->round_used); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - return -1; - break; - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - return de_diff_32((uint32_t *)decoded_data, info->samples_used, - info->round_used); - break; - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - return -1; - break; - default: - debug_print("Error: Compression mode not supported.\n"); - break; - } - - return -1; -} - - -static uint8_t de_map_to_pos_alg_8(uint8_t value_to_unmap) -{ - if (value_to_unmap & 0x1) /* if uneven */ - return (value_to_unmap + 1) / -2; - else - return value_to_unmap / 2; -} - - -static uint16_t de_map_to_pos_alg_16(uint16_t value_to_unmap) -{ - if (value_to_unmap & 0x1) /* if uneven */ - return (value_to_unmap + 1) / -2; - else - return value_to_unmap / 2; -} - - -static uint32_t de_map_to_pos_alg_32(uint32_t value_to_unmap) -{ - - if (value_to_unmap & 0x1) /* if uneven */ - return ((int64_t)value_to_unmap + 1) / -2; /* typecast to prevent overflow */ - else - return value_to_unmap / 2; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * 16-bit buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the uint16_t data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_16(uint16_t *data_buf, uint32_t samples_used, int - zero_mode_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) - data_buf[i] -= 1; - - data_buf[i] = (uint16_t)de_map_to_pos_alg_16(data_buf[i]); - } - return 0; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * 32-bit buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the uint16_t data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_32(uint32_t *data_buf, uint32_t samples_used, int - zero_mode_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) - data_buf[i] -= 1; - - data_buf[i] = (uint32_t)de_map_to_pos_alg_32(data_buf[i]); - } - return 0; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the S_FX data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_S_FX(struct S_FX *data_buf, uint32_t samples_used, int - zero_mode_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - } - - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - } - return 0; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX_EFX buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the S_FX_EFX data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_S_FX_EFX(struct S_FX_EFX *data_buf, uint32_t - samples_used, int zero_mode_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - data_buf[i].EFX -= 1; - } - - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].EFX = de_map_to_pos_alg_32(data_buf[i].EFX); - } - return 0; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX_NCOB buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the S_FX_NCOB data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_S_FX_NCOB(struct S_FX_NCOB *data_buf, uint32_t - samples_used, int zero_mode_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - data_buf[i].NCOB_X -= 1; - data_buf[i].NCOB_Y -= 1; - } - - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = de_map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = de_map_to_pos_alg_32(data_buf[i].NCOB_Y); - } - return 0; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * S_FX_EFX_NCOB_ECOB buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the S_FX_EFX_NCOB_ECOB data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_S_FX_EFX_NCOB_ECOB(struct S_FX_EFX_NCOB_ECOB *data_buf, - uint32_t samples_used, - int zero_mode_used) -{ - size_t i; - - if (!samples_used) - return 0; - - if (!data_buf) - return -1; - - for (i = 0; i < samples_used; i++) { - if (zero_mode_used) { - /* data_buf[i].EXPOSURE_FLAGS -= 1; */ - data_buf[i].FX -= 1; - data_buf[i].NCOB_X -= 1; - data_buf[i].NCOB_Y -= 1; - data_buf[i].EFX -= 1; - data_buf[i].ECOB_X -= 1; - data_buf[i].ECOB_Y -= 1; - } - - data_buf[i].EXPOSURE_FLAGS = - de_map_to_pos_alg_8(data_buf[i].EXPOSURE_FLAGS); - data_buf[i].FX = de_map_to_pos_alg_32(data_buf[i].FX); - data_buf[i].NCOB_X = de_map_to_pos_alg_32(data_buf[i].NCOB_X); - data_buf[i].NCOB_Y = de_map_to_pos_alg_32(data_buf[i].NCOB_Y); - data_buf[i].EFX = de_map_to_pos_alg_32(data_buf[i].EFX); - data_buf[i].ECOB_X = de_map_to_pos_alg_32(data_buf[i].ECOB_X); - data_buf[i].ECOB_Y = de_map_to_pos_alg_32(data_buf[i].ECOB_Y); - } - return 0; -} - - -/** - * @brief map the unsigned output of the pre-stage to a signed value range for a - * F_FX buffer - * - * @note change the data_buf in-place - * - * @param data_buf pointer to the F_FX data buffer to process - * @param samples_used amount of data samples in the data_buf - * @param zero_mode_used needs to be set if the zero escape symbol mechanism is used - * - * @returns 0 on success, error otherwise - */ - -static int de_map_to_pos_F_FX(uint32_t *data_buf, uint32_t samples_used, int - zero_mode_used) -{ - return de_map_to_pos_32(data_buf, samples_used, zero_mode_used); -} +/* structure to hold a setup to encode a value */ +typedef unsigned int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *); +struct decoder_setup { + /* generate_cw_f_pt generate_cw_f; /1* pointer to the code word generation function *1/ */ + decoder_ptr decode_cw_f; + int (*encode_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 max_cw_len; + 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 map the unsigned output of the pre-stage to a signed value range - * - * @note change the data_buf in-place - * - * @param decompressed_data pointer to the data to process - * @param info compressor information contains information of - * an executed compression - * - * @returns 0 on success, error otherwise - */ -static int de_map_to_pos(void *decompressed_data, const struct cmp_info *info) +double get_compression_ratio(uint32_t samples, uint32_t cmp_size_bits, + enum cmp_data_type data_type) { - int zero_mode_used; - - if (!info) - return -1; - - if (info->samples_used == 0) - return 0; - - if (!decompressed_data) - return -1; + double orign_len_bits = (double)cmp_cal_size_of_data(samples, data_type) * CHAR_BIT; - 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; + return orign_len_bits/(double)cmp_size_bits; } -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; - } - /* separate the bitOffset into word offset (set localAddr pointer) and - * local bit offset (bitsLeft) - */ - - localAddr = srcAddr + (bitOffset >> 5); - bitsLeft = bitOffset & 0x1f; - - localEndPos = bitsLeft + nBits; - - if (localEndPos <= 32) { - unsigned int shiftRight = 32 - nBits; - - bitsRight = shiftRight - bitsLeft; - - *(p_value) = *(localAddr) >> bitsRight; - - mask = (0xffffffff >> shiftRight); - - *(p_value) &= mask; - } else { - unsigned int n1 = 32 - bitsLeft; - unsigned int n2 = nBits - n1; - /* part 1 ; */ - mask = 0xffffffff >> bitsLeft; - *(p_value) = (*localAddr) & mask; - *(p_value) <<= n2; - /*part 2: */ - /* adjust address*/ - localAddr += 1; - - bitsRight = 32 - n2; - *(p_value) |= *(localAddr) >> bitsRight; - } - return nBits; -} - static unsigned int count_leading_ones(unsigned int value) { unsigned int n_ones = 0; /* number of leading 1s */ @@ -831,16 +51,15 @@ static unsigned int count_leading_ones(unsigned int value) leading_bit = value & 0x80000000; if (!leading_bit) break; - else { - n_ones++; - value <<= 1; - } + + n_ones++; + value <<= 1; } return n_ones; } -static unsigned int Rice_decoder(uint32_t code_word, unsigned int m, +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 */ @@ -863,7 +82,7 @@ static unsigned int Rice_decoder(uint32_t code_word, unsigned int m, code_word = code_word << ql; /* shift quotient code out */ - /* Right shifting an integer by a number of bits equal orgreater than + /* Right shifting an integer by a number of bits equal or greater than * its size is undefined behavior */ if (rl == 0) @@ -877,7 +96,7 @@ static unsigned int Rice_decoder(uint32_t code_word, unsigned int m, } -static unsigned int Golomb_decoder(unsigned int code_word, unsigned int m, +static unsigned int golomb_decoder(unsigned int code_word, unsigned int m, unsigned int log2_m, unsigned int *decoded_cw) { @@ -915,608 +134,382 @@ static unsigned int Golomb_decoder(unsigned int code_word, unsigned int m, } -typedef unsigned int (*decoder_ptr)(unsigned int, unsigned int, unsigned int, unsigned int *); - static decoder_ptr select_decoder(unsigned int golomb_par) { if (!golomb_par) return NULL; if (is_a_pow_of_2(golomb_par)) - return &Rice_decoder; + return &rice_decoder; else - return &Golomb_decoder; + return &golomb_decoder; } -static int decode_raw(const void *compressed_data, const struct cmp_info - *info, void *const decompressed_data) -{ - if (!info) - return -1; - if (info->samples_used == 0) - return 0; - if (!compressed_data) - return -1; - if (!decompressed_data) - return -1; - - if (info->samples_used*size_of_a_sample(info->cmp_mode_used)*CHAR_BIT - != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; - } - memcpy(decompressed_data, compressed_data, info->cmp_size/CHAR_BIT); - - return 0; -} +/** + * @brief read a value of up to 32 bits from a bitstream + * + * @param p_value pointer to the read value + * @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 (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_SAMLL_BUF if + * the bitstream buffer is too small to read the value from the bitstream + */ -static int decode_raw_16(const void *compressed_data, const struct cmp_info - *info, uint16_t *const decompressed_data) +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) { - size_t i; - uint16_t *p = decompressed_data; - uint32_t read_pos = 0; - unsigned int read_bits; - uint32_t read_val; + const unsigned int *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 (!info) - return -1; - if (info->samples_used == 0) - return 0; - if (!compressed_data) - return -1; - if (!decompressed_data) + /*leave in case of erroneous input */ + if (bit_offset < 0) 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; -} - - -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 (n_bits == 0) + return stream_len; -#if defined(LITTLE_ENDIAN) - { - size_t i; - for (i = 0; i < info->samples_used; i++) { - decompressed_data[i].FX = cpu_to_be32(decompressed_data[i].FX); - } - } -#endif - return 0; -} + if (n_bits > 32) + return -1; -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 (!bitstream_adr) + return stream_len; - if (!compressed_data) - return -1U; + if (!p_value) + return stream_len; - if (!info) - return -1U; + /* 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_SAMLL_BUF; - if (!decoded_val) - return -1U; + } - if (read_pos > info->cmp_size) - return -1U; + /* 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; - if (max_cw_len > 32) - return -1U; + localEndPos = bitsLeft + n_bits; - if (max_cw_len == 0) - return read_pos; + if (localEndPos <= 32) { + unsigned int shiftRight = 32 - n_bits; - decoder = select_decoder(info->golomb_par_used); - if (!decoder) - return -1U; + bitsRight = shiftRight - bitsLeft; - 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; + *(p_value) = cpu_to_be32(*(local_adr)) >> bitsRight; - read_bits = get_n_bits32(&read_val, read_pos, n_read_bits, - compressed_data, info->cmp_size); - if (!read_bits) - return -1U; + mask = (0xffffffff >> shiftRight); - read_val = read_val << (32 - n_read_bits); + *(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; - log2_g = ilog_2(info->golomb_par_used); - n_bits = decoder(read_val, info->golomb_par_used, log2_g, decoded_val); + bitsRight = 32 - n2; + *(p_value) |= cpu_to_be32(*(local_adr)) >> bitsRight; + } - return read_pos + n_bits; + return stream_len; } -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 decode_normal(uint32_t *decoded_value, int stream_pos, const struct decoder_setup *setup) { - 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; + uint32_t read_val = ~0U; + int n_read_bits, cw_len, n_bits; - if (max_cw_len == 0) - return read_pos; + if (stream_pos + setup->max_cw_len > setup->max_stream_len) /* check buffer overflow */ + n_read_bits = setup->max_stream_len - stream_pos; + else + n_read_bits = setup->max_cw_len; + if (n_read_bits >= 32 || n_read_bits == 0) + return -1; - 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; + n_bits = get_n_bits32(&read_val, n_read_bits, stream_pos, + setup->bitstream_adr, setup->max_stream_len); + if (n_bits <= 0) + return -1; - if (*decoded_val == 0) {/* escape symbol mechanism was used; read unencoded value */ - unsigned int n_bits; - uint32_t unencoded_val; + read_val = read_val << (32 - n_read_bits); - 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; + cw_len = setup->decode_cw_f(read_val, setup->encoder_par1, setup->encoder_par2, decoded_value); + if (cw_len < 0) + return -1; - *decoded_val = unencoded_val; - read_pos += n_bits; - } - return read_pos; + return stream_pos + cw_len; } -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) +static int decode_multi(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup) { - if (!info) - return -1U; - - if (info->samples_used == 0) - return read_pos; + stream_pos = decode_normal(decoded_value, stream_pos, setup); + if (stream_pos < 0) + return stream_pos; - if (!compressed_data) - return -1U; - - if (!decoded_val) - return -1U; - - if (read_pos > info->cmp_size) - return -1U; - - if (max_cw_len > 32) - return -1U; - - if (max_cw_len == 0) - return read_pos; - - read_pos = decode_normal(compressed_data, info, read_pos, max_cw_len, - decoded_val); - if (read_pos == -1U) - return -1U; - - if (*decoded_val >= info->spill_used) { + if (*decoded_value >= setup->outlier_par) { /* escape symbol mechanism was used; read unencoded value */ - unsigned int n_bits; - uint32_t unencoded_val; + int n_bits; + uint32_t unencoded_val = 0; unsigned int unencoded_len; - unencoded_len = (*decoded_val - info->spill_used + 1) * 2; - if (unencoded_len > max_cw_len) /* consistency check */ - return -1U; + unencoded_len = (*decoded_value - setup->outlier_par + 1) * 2; - /* check buffer overflow */ - if ((read_pos + unencoded_len) > info->cmp_size) { - /*TODO: debug message */ - return -1U; - } - n_bits = get_n_bits32(&unencoded_val, read_pos, unencoded_len, - compressed_data, info->cmp_size); - if (!n_bits) - return -1U; + n_bits = get_n_bits32(&unencoded_val, unencoded_len, stream_pos, + setup->bitstream_adr, setup->max_stream_len); + if (n_bits <= 0) + return -1; - *decoded_val = unencoded_val + info->spill_used; - read_pos += n_bits; + *decoded_value = unencoded_val + setup->outlier_par; + stream_pos += unencoded_len; } - return read_pos; -} - - -static unsigned int decode_value(const void *compressed_data, - const struct cmp_info *info, - unsigned int read_pos, - unsigned int max_cw_len, uint32_t *decoded_val) -{ - if (multi_escape_mech_is_used(info->cmp_mode_used)) - return decode_multi(compressed_data, info, read_pos, max_cw_len, - decoded_val); - - if (zero_escape_mech_is_used(info->cmp_mode_used)) - return decode_zero(compressed_data, info, read_pos, max_cw_len, - decoded_val); - return -1U; + return stream_pos; } -static int decode_16(const void *compressed_data, const struct cmp_info *info, - uint16_t *decoded_data) +static int decode_zero(uint32_t *decoded_value, int stream_pos, + const struct decoder_setup *setup) { - size_t i; - unsigned int read_pos = 0; - - if (!info) - return -1; + stream_pos = decode_normal(decoded_value, stream_pos, setup); - if (info->samples_used == 0) - return 0; + if (stream_pos <= 0) + return stream_pos; - if (!decoded_data) + if (*decoded_value > setup->outlier_par) /* consistency check */ return -1; - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; + if (*decoded_value == 0) {/* escape symbol mechanism was used; read unencoded value */ + int n_bits; + uint32_t unencoded_val = 0; - 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"); + n_bits = get_n_bits32(&unencoded_val, setup->max_data_bits, stream_pos, + setup->bitstream_adr, setup->max_stream_len); + if (n_bits <= 0) return -1; - } - - if (decoded_val > UINT16_MAX) + if (unencoded_val < setup->outlier_par && unencoded_val != 0) /* consistency check */ return -1; - decoded_data[i] = (uint16_t)decoded_val; + *decoded_value = unencoded_val; + stream_pos += setup->max_data_bits; } - - 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; - } - return 0; + (*decoded_value)--; + if (*decoded_value == 0xFFFFFFFF) /* catch underflow */ + (*decoded_value) = (*decoded_value) >> (32-setup->max_data_bits); + return stream_pos; } -static int decode_S_FX(const void *compressed_data, const struct cmp_info *info, - struct S_FX *decoded_data) -{ - size_t i; - unsigned int read_pos = 0; - struct cmp_info info_exp_flag; +/** + * @brief remap a 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 + */ - info_exp_flag.golomb_par_used = GOLOMB_PAR_EXPOSURE_FLAGS; +static uint32_t re_map_to_pos(uint32_t value_to_unmap) +{ + 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; +} - if (!info) - return -1; - if (info->samples_used == 0) - return 0; +static int decode_value(uint32_t *decoded_value, uint32_t model, + int stream_pos, const struct decoder_setup *setup) +{ + uint32_t mask = (~0U >> (32 - setup->max_data_bits)); /* mask the used bits */ - if (!decoded_data) - return -1; + stream_pos = setup->encode_method_f(decoded_value, stream_pos, setup); + if (stream_pos <= 0) + return stream_pos; - info_exp_flag = *info; + *decoded_value = re_map_to_pos(*decoded_value); //, setup->max_used_bits); - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; + *decoded_value += round_fwd(model, setup->lossy_par); - /* 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; + *decoded_value &= mask; - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].FX = decoded_val; - } + *decoded_value = round_inv(*decoded_value, setup->lossy_par); - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression."); - return 1; - } - return 0; + return stream_pos; } -static int decode_S_FX_EFX(const void *compressed_data, const struct cmp_info - *info, struct S_FX_EFX *decoded_data) +static int configure_decoder_setup(struct decoder_setup *setup, + uint32_t cmp_par, uint32_t spill, + uint32_t lossy_par, uint32_t max_data_bits, + const struct cmp_cfg *cfg) { - size_t i; - unsigned int read_pos = 0; - - if (!info) + if (multi_escape_mech_is_used(cfg->cmp_mode)) + setup->encode_method_f = &decode_multi; + else if (zero_escape_mech_is_used(cfg->cmp_mode)) + setup->encode_method_f = &decode_zero; + else { + debug_print("Error: Compression mode not supported.\n"); return -1; + } - if (info->samples_used == 0) - return 0; - - if (!decoded_data) + 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; - - for (i = 0; i < info->samples_used; i++) { - uint32_t decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 8, - &decoded_val); - if (read_pos == -1U) - return -1; - if (decoded_val > UINT8_MAX) - return -1; - decoded_data[i].EXPOSURE_FLAGS = (uint8_t)decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].FX = decoded_val; - - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].EFX = decoded_val; } + setup->max_stream_len = (cfg->buffer_length) * CHAR_BIT; /* maximum length of the bitstream/icu_output_buf in bits */ + if (rdcu_supported_data_type_is_used(cfg->data_type)) + setup->max_cw_len = 16; + else + setup->max_cw_len = 32; + setup->encoder_par1 = cmp_par; /* encoding parameter 1 */ + setup->encoder_par2 = ilog_2(cmp_par); /* encoding parameter 2 */ + setup->outlier_par = spill; /* 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); - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; - } return 0; } -static int decode_S_FX_NCOB(const void *compressed_data, const struct cmp_info - *info, struct S_FX_NCOB *decoded_data) +static int decompress_imagette(struct cmp_cfg *cfg) { size_t i; - unsigned int read_pos = 0; - - if (!info) - return -1; - - if (info->samples_used == 0) - return 0; + 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; + int err; - if (!decoded_data) + err = configure_decoder_setup(&setup, cfg->golomb_par, cfg->spill, + cfg->round, 16, cfg); + if (err) 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 < cfg->samples; i++) { + if (model_mode_is_used(cfg->cmp_mode)) + model = model_buf[i]; + else + model = decoded_value; - 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; + stream_pos = decode_value(&decoded_value, model, stream_pos, &setup); + if (stream_pos <= 0) + return stream_pos; + decompressed_data[i] = decoded_value; - 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 (up_model_buf) { + up_model_buf[i] = cmp_up_model(decoded_value, model, + cfg->model_value, setup.lossy_par); + } } - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression.\n"); - return 1; - } - return 0; + 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) +static int decompressed_data_internal(struct cmp_cfg *cfg) { - size_t i; - unsigned int read_pos = 0; - - if (!info) - return -1; - - if (info->samples_used == 0) - return 0; + int data_size, strem_len_bit = -1; - if (!decoded_data) + if (!cfg) + return 0; /* or -1? */ + if (!cfg->icu_output_buf) 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; + 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, 32, - &decoded_val); - if (read_pos == -1U) + if (model_mode_is_used(cfg->cmp_mode)) + if (!cfg->model_buf) 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; + 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_Y = decoded_val; - read_pos = decode_value(compressed_data, info, read_pos, 32, - &decoded_val); - if (read_pos == -1U) - return -1; - decoded_data[i].EFX = decoded_val; + 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].ECOB_X = decoded_val; + } else { + switch (cfg->data_type) { + case DATA_TYPE_IMAGETTE: + strem_len_bit = decompress_imagette(cfg); + break; + default: + strem_len_bit = -1; + debug_print("Error: Compressed data type not supported.\n"); + 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; } + /* TODO: is this usefull? if (strem_len_bit != data_size * CHAR_BIT) { */ + if (strem_len_bit <= 0) + return -1; - if (read_pos != info->cmp_size) { - debug_print("Warning: The size of the decompressed bitstream does not match the size of the compressed bitstream. Check if the parameters used for decompression are the same as those used for compression."); - return 1; - } - return 0; + + return data_size; } -static int decode_data(const void *compressed_data, const struct cmp_info *info, - void *decompressed_data) +int decompress_cmp_entiy(struct cmp_entity *ent, void *model_buf, + 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_buf; + cfg.icu_new_model_buf = up_model_buf; + cfg.input_buf = decompressed_data; - if (!compressed_data) + if (!ent) return -1; - if (!decompressed_data) + err = cmp_ent_read_header(ent, &cfg); + if (err) return -1; - switch (info->cmp_mode_used) { - case MODE_RAW: - return decode_raw_16(compressed_data, info, decompressed_data); - break; - case MODE_MODEL_ZERO: - case MODE_DIFF_ZERO: - case MODE_MODEL_MULTI: - case MODE_DIFF_MULTI: - return decode_16(compressed_data, info, - (uint16_t *)decompressed_data); - break; - case MODE_RAW_S_FX: - return decode_raw_S_FX(compressed_data, info, decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX: - case MODE_MODEL_MULTI_S_FX: - case MODE_DIFF_ZERO_S_FX: - case MODE_DIFF_MULTI_S_FX: - return decode_S_FX(compressed_data, info, - (struct S_FX *)decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX_EFX: - case MODE_MODEL_MULTI_S_FX_EFX: - case MODE_DIFF_ZERO_S_FX_EFX: - case MODE_DIFF_MULTI_S_FX_EFX: - return decode_S_FX_EFX(compressed_data, info, - (struct S_FX_EFX *)decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX_NCOB: - case MODE_MODEL_MULTI_S_FX_NCOB: - case MODE_DIFF_ZERO_S_FX_NCOB: - case MODE_DIFF_MULTI_S_FX_NCOB: - return decode_S_FX_NCOB(compressed_data, info, - (struct S_FX_NCOB *)decompressed_data); - break; - case MODE_MODEL_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_MODEL_MULTI_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_ZERO_S_FX_EFX_NCOB_ECOB: - case MODE_DIFF_MULTI_S_FX_EFX_NCOB_ECOB: - return decode_S_FX_EFX_NCOB_ECOB(compressed_data, info, - (struct S_FX_EFX_NCOB_ECOB *) - decompressed_data); - break; -#if 0 - case MODE_MODEL_ZERO_F_FX: - case MODE_MODEL_MULTI_F_FX: - case MODE_DIFF_ZERO_F_FX: - case MODE_DIFF_MULTI_F_FX: - break; -#endif - default: - debug_print("Error: Compression mode not supported.\n"); - break; - - } - return -1; + 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) +/* model buffer is overwritten with updated model */ + +int decompress_data(uint32_t *compressed_data, void *de_model_buf, + const struct cmp_info *info, void *decompressed_data) { - int err; + int size_decomp_data; + struct cmp_cfg cfg = {0}; if (!compressed_data) return -1; @@ -1535,18 +528,22 @@ int decompress_data(const void *compressed_data, void *de_model_buf, const if (!decompressed_data) return -1; + /* cfg.data_type = info->data_type_used; */ + 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); + cfg.input_buf = decompressed_data; + cfg.model_buf = de_model_buf; + size_decomp_data = decompressed_data_internal(&cfg); + if (size_decomp_data <= 0) + return -1; + else + return 0; - err = decode_data(compressed_data, info, decompressed_data); - if (err) - return err; - - err = de_map_to_pos(decompressed_data, info); - if (err) - return err; - - err = de_pre_process(decompressed_data, de_model_buf, info); - if (err) - return err; - return 0; } diff --git a/lib/meson.build b/lib/meson.build index 21f72ad..f072ce4 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -17,6 +17,6 @@ cmplib_sources = files([ 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 + c_args : ['-DDEBUGLEVEL=1'], +# install : 'true' # linking under windows mingw only works if this is set ) diff --git a/lib/rdcu_pkt_to_file.c b/lib/rdcu_pkt_to_file.c index 83074d7..0c71c8e 100644 --- a/lib/rdcu_pkt_to_file.c +++ b/lib/rdcu_pkt_to_file.c @@ -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; } diff --git a/meson.build b/meson.build index d300c11..6757167 100644 --- a/meson.build +++ b/meson.build @@ -5,6 +5,8 @@ project('cmp_tool', 'c', default_options : ['warning_level=3', 'c_std=gnu99'] ) +add_project_arguments('-DDEBUGLEVEL=1', language : 'c') + if host_machine.system() == 'windows' 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. diff --git a/test/cmp_icu/meson.build b/test/cmp_icu/meson.build index 80c3e27..405d376 100644 --- a/test/cmp_icu/meson.build +++ b/test/cmp_icu/meson.build @@ -1,14 +1,26 @@ -test_cmp_icu_files = files ([ - 'test_cmp_icu.c' -]) +test_case = files('test_cmp_icu.c') +test_runner = test_runner_generator.process(test_case) test_cmp_icu = executable('test_cmp_icu', - test_cmp_icu_files, + test_case, test_runner, include_directories : incdir, link_with : cmp_lib, - # c_args : ['-DMAIN'] - dependencies : cunit_dep, + dependencies : unity_dep, build_by_default : false ) -test('cmp_icu unit test', test_cmp_icu) +test('cmp_icu Unit Tests', test_cmp_icu) + + +test_case = files('test_decmp.c') +test_runner = test_runner_generator.process(test_case) + +test_cmp_decomp = executable('test_cmp_decomp', + 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_decomp) diff --git a/test/cmp_icu/test_cmp_icu.c b/test/cmp_icu/test_cmp_icu.c index 8bf30d6..35f938a 100644 --- a/test/cmp_icu/test_cmp_icu.c +++ b/test/cmp_icu/test_cmp_icu.c @@ -1,128 +1,1388 @@ -/* - * Simple example of a CUnit unit test. - * - * This program (crudely) demonstrates a very simple "black box" - * test of the standard library functions fprintf() and fread(). - * It uses suite initialization and cleanup functions to open - * and close a common temporary file used by the test functions. - * The test functions then write to and read from the temporary - * file in the course of testing the library functions. - * - * The 2 test functions are added to a single CUnit suite, and - * then run using the CUnit Basic interface. The output of the - * program (on CUnit version 2.0-2) is: - * - * CUnit : A Unit testing framework for C. - * http://cunit.sourceforge.net/ - * - * Suite: Suite_1 - * Test: test of fprintf() ... passed - * Test: test of fread() ... passed - * - * --Run Summary: Type Total Ran Passed Failed - * suites 1 1 n/a 0 - * tests 2 2 2 0 - * asserts 5 5 5 0 +#include <string.h> +#include <stdlib.h> + +#include "unity.h" + +#include "cmp_support.h" +/* this is a hack to test static functions */ +#include "../lib/cmp_icu.c" + + +/** + * @test map_to_pos */ -#include <stdio.h> -#include <string.h> -#include "CUnit/Basic.h" +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; -/* Pointer to the file used by the tests. */ -static FILE* temp_file = NULL; + value_to_map = 0; + mapped_value = map_to_pos(value_to_map, max_data_bits); + TEST_ASSERT_EQUAL_INT(0, mapped_value); -/* The suite initialization function. - * Opens the temporary file used by the tests. - * Returns zero on success, non-zero otherwise. + 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 */ -int init_suite1(void) + +#define SDP_PB_N 3 + + +static void init_PB32_arrays(uint32_t *z, uint32_t *o) { - if (NULL == (temp_file = fopen("temp.txt", "w+"))) { - return -1; - } - else { - return 0; + 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; } } -/* The suite cleanup function. - * Closes the temporary file used by the tests. - * Returns zero on success, non-zero otherwise. + +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_SAMLL_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_SAMLL_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 */ -int clean_suite1(void) + +void test_rice_encoder(void) { - if (0 != fclose(temp_file)) { - return -1; - } - else { - temp_file = NULL; - return 0; - } + uint32_t value, g_par, log2_g_par, cw, cw_len; + + /* 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_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(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); } -/* Simple test of fprintf(). - * Writes test data to the temporary file and checks - * whether the expected number of bytes were written. + +/** + * @test golomb_encoder */ -void testFPRINTF(void) + +void test_Golomb_encoder(void) { - int i1 = 10; + uint32_t value, g_par, log2_g_par, cw, cw_len; - if (NULL != temp_file) { - CU_ASSERT(0 == fprintf(temp_file, "")); - CU_ASSERT(2 == fprintf(temp_file, "Q\n")); - CU_ASSERT(7 == fprintf(temp_file, "i1 = %d", i1)); - } + /* 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_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(32, cw_len); + TEST_ASSERT_EQUAL_HEX(0x0, cw); + + value = 1; g_par = MAX_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(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); } -/* Simple test of fread(). - * Reads the data previously written by testFPRINTF() - * and checks whether the expected characters are present. - * Must be run after testFPRINTF(). + +/** + * @test encode_value_zero */ -void testFREAD(void) + +void test_encode_value_zero(void) { - unsigned char buffer[20]; + uint32_t data, model; + int stream_len; + struct encoder_setupt setup = {0}; + uint32_t bitstream[3] = {0}; - if (NULL != temp_file) { - rewind(temp_file); - CU_ASSERT(9 == fread(buffer, sizeof(unsigned char), 20, temp_file)); - CU_ASSERT(0 == strncmp(buffer, "Q\ni1 = 10", 9)); - } + /* 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_SAMLL_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_SAMLL_BUF, stream_len); + TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); + TEST_ASSERT_EQUAL_HEX(0, bitstream[2]); } -/* The main() function for setting up and running the tests. - * Returns a CUE_SUCCESS on successful running, another - * CUnit error code on failure. + +/** + * @test encode_value_multi */ -int main() + +void test_encode_value_multi(void) { - CU_pSuite pSuite = NULL; + uint32_t data, model; + int stream_len; + struct encoder_setupt setup = {0}; + uint32_t bitstream[4] = {0}; - /* initialize the CUnit test registry */ - if (CUE_SUCCESS != CU_initialize_registry()) - return CU_get_error(); + /* 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; - /* add a suite to the registry */ - pSuite = CU_add_suite("Suite_1", init_suite1, clean_suite1); - if (NULL == pSuite) { - CU_cleanup_registry(); - return CU_get_error(); - } + 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_SAMLL_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_SAMLL_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_SAMLL_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 + */ + +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); - /* add the tests to the suite */ - /* NOTE - ORDER IS IMPORTANT - MUST TEST fread() AFTER fprintf() */ - if ((NULL == CU_add_test(pSuite, "test of fprintf()", testFPRINTF)) || - (NULL == CU_add_test(pSuite, "test of fread()", testFREAD))) - { - CU_cleanup_registry(); - return CU_get_error(); + 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.smeating_mean, MAX_USED_SMEARING_MEAN_BITS); + TEST_ASSERT_EQUAL_INT(max_used_bits.smeating_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); +} + + +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])); +} + +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]); +} + + +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]); +} + + +void test_compress_imagette_raw(void) +{ + uint16_t data[] = {0x0, 0x1, 0x23, 0x42, INT16_MIN, INT16_MAX, UINT16_MAX}; + uint16_t output_buf[7] = {0}; + 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])); +} + + +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); - /* Run all tests using the CUnit Basic interface */ - CU_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_tests(); - CU_cleanup_registry(); - return CU_get_error(); + 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])); + + TEST_ASSERT_FALSE(memcmp(cfg.input_buf, cfg.icu_output_buf, MULTI_ENTRY_HDR_SIZE)); + hdr = cfg.icu_new_model_buf; + up_model_buf = (struct s_fx *)hdr->entry; + 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); } + + diff --git a/test/cmp_icu/test_cmp_icu_new.c b/test/cmp_icu/test_cmp_icu_new.c deleted file mode 100644 index a0d9109..0000000 --- a/test/cmp_icu/test_cmp_icu_new.c +++ /dev/null @@ -1,894 +0,0 @@ -#include <string.h> - -#include "unity.h" - -#include "cmp_support.h" -/* this is a hack to test static functions */ -#include "../lib/cmp_icu_new.c" - - -/** - * @test map_to_pos - */ - -void test_map_to_pos(void) -{ - uint32_t value_to_map; - uint32_t max_value_bits; - uint32_t mapped_value; - - /* test mapping 32 bits values */ - max_value_bits = 32; - - value_to_map = 0; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(0, mapped_value); - - value_to_map = -1U; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(1, mapped_value); - - value_to_map = 1; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(2, mapped_value); - - value_to_map = 42; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(84, mapped_value); - - value_to_map = INT32_MAX; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_HEX(UINT32_MAX-1, mapped_value); - - value_to_map = INT32_MIN; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_HEX(UINT32_MAX, mapped_value); - - /* test mapping 16 bits values */ - max_value_bits = 16; - - value_to_map = -1U; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(1, mapped_value); - - /* test mapping 6 bits values */ - max_value_bits = 6; - - value_to_map = 0; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(0, mapped_value); - - value_to_map = -1U; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(1, mapped_value); - - value_to_map = UINT32_MAX; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(1, mapped_value); - - value_to_map = -1U & 0x3FU; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(1, mapped_value); - - value_to_map = 63; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(1, mapped_value); - - value_to_map = 1; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(2, mapped_value); - - value_to_map = 31; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(62, mapped_value); - - value_to_map = -33U; /* aka 31 */ - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(62, mapped_value); - - value_to_map = -32U; - mapped_value = map_to_pos(value_to_map, max_value_bits); - TEST_ASSERT_EQUAL_INT(63, mapped_value); - - value_to_map = 32; - mapped_value = map_to_pos(value_to_map, max_value_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_SAMLL_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_bit_len(l) */ - v = 0x0; n = 32; o = INT32_MAX; - rval = put_n_bits32(v, n, o, testarray1, l); - TEST_ASSERT_EQUAL_INT(CMP_ERROR_SAMLL_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; - - /* 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_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(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; - - /* 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_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(32, cw_len); - TEST_ASSERT_EQUAL_HEX(0x0, cw); - - value = 1; g_par = MAX_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(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.outlier_par = 32; - setup.max_value_bits = 32; - setup.generate_cw = Rice_encoder; - setup.bitstream_adr = bitstream; - setup.max_bit_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_SAMLL_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_value_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_bit_len = 32; - data = 31; model = 0; - stream_len = encode_value_zero(data, model, stream_len, &setup); - TEST_ASSERT_EQUAL_INT(CMP_ERROR_SAMLL_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.outlier_par = 16; - setup.max_value_bits = 32; - setup.generate_cw = Rice_encoder; - setup.bitstream_adr = bitstream; - setup.max_bit_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_SAMLL_BUF, stream_len); - - /* small buffer error when creating the multi escape symbol*/ - bitstream[0] = 0; - bitstream[1] = 0; - setup.max_bit_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_SAMLL_BUF, stream_len); - TEST_ASSERT_EQUAL_HEX(0, bitstream[0]); - TEST_ASSERT_EQUAL_HEX(0, bitstream[1]); -} diff --git a/test/cmp_icu/test_decmp.c b/test/cmp_icu/test_decmp.c new file mode 100644 index 0000000..523b64f --- /dev/null +++ b/test/cmp_icu/test_decmp.c @@ -0,0 +1,442 @@ +#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 */ + + +/* 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 */ +size_t icu_compress_data_entity(struct cmp_entity *ent, const struct cmp_cfg *cfg) +{ + size_t s, hdr_size; + 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."); + + if (!ent) { + s = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type); + if (!s) + return 0; + + hdr_size = cmp_ent_cal_hdr_size(cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW); + if (!hdr_size) + return 0; + + return s + hdr_size; + } + + cfg_cpy = *cfg; + cfg_cpy.icu_output_buf = cmp_ent_get_data_buf(ent); + + cmp_size_bits = icu_compress_data(&cfg_cpy); + if (cmp_size_bits < 0) + return 0; + + s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, + cmp_bit_to_4byte(cmp_size_bits)); + if (!s) + return 0; + + 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 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; + 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; + setup.max_cw_len = 16; + + 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: negativ stream_pos */ +} + + +void test_decode_zero(void) +{ + uint32_t decoded_value; + 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; + 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]); +} + +int my_random(unsigned int min, unsigned int max) +{ + if (max-min > RAND_MAX) + TEST_ASSERT(0); + if (min > max) + TEST_ASSERT(0); + return min + rand() / (RAND_MAX / (max - min + 1) + 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_UNKOWN); + + + 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_RDCU_GOLOMB_PAR, MAX_RDCU_GOLOMB_PAR); + uint32_t max_spill = get_max_spill(golomb_par, data_type); + 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); +} diff --git a/test/cmp_tool/cmp_tool_integration_test.py b/test/cmp_tool/cmp_tool_integration_test.py index 9804d41..aac8b0b 100755 --- a/test/cmp_tool/cmp_tool_integration_test.py +++ b/test/cmp_tool/cmp_tool_integration_test.py @@ -14,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 @@ -409,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) @@ -428,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) @@ -441,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)) @@ -459,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' @@ -481,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'] = '16' 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") + + # 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_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() == + '00 00 00 01 00 02 00 03 00 04 \n') # clean up finally: del_file(data_file_name) @@ -582,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()) @@ -627,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) @@ -979,11 +1008,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: @@ -1009,6 +1036,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' @@ -1081,7 +1109,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: @@ -1106,25 +1134,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 diff --git a/test/meson.build b/test/meson.build index b843e00..4743653 100644 --- a/test/meson.build +++ b/test/meson.build @@ -34,10 +34,6 @@ subdir('tools') subdir('cmp_tool') -cunit_dep = dependency('cunit', required : false) - unity_dep = dependency('unity', fallback : ['unity', 'unity_dep']) -# unity_proj = subproject('unity') -# unity_dep = unity_proj.get_variable('unity_dep') subdir('cmp_icu') -- GitLab