diff --git a/lib/cmp_chunk.h b/lib/cmp_chunk.h index 4c5f5183450b2302f30e098b7e6d2176e0b14970..93e1ce88366dc309abb781e4a9226e2ad1dce9cc 100644 --- a/lib/cmp_chunk.h +++ b/lib/cmp_chunk.h @@ -155,11 +155,12 @@ void compress_chunk_init(uint64_t(return_timestamp)(void), uint32_t version_id); * compress_chunk_cmp_size_bound(chunk, chunk_size) * as it eliminates one potential failure scenario: * not enough space in the dst buffer to write the - * compressed data; size is round down to a multiple - * of 4 + * compressed data; size is internally round down + * to a multiple of 4 * @returns the byte size of the compressed_data buffer on success; negative on * error, CMP_ERROR_SMALL_BUF (-2) if the compressed data buffer is too - * small to hold the whole compressed data + * small to hold the whole compressed data; the compressed and updated + * model are only valid on positive return values */ int32_t compress_chunk(void *chunk, uint32_t chunk_size, @@ -182,7 +183,7 @@ int32_t compress_chunk(void *chunk, uint32_t chunk_size, * @returns 0 on success, otherwise error */ -int compress_chunk_set_model_id_and_counter(uint32_t *dst, int dst_size, +int compress_chunk_set_model_id_and_counter(void *dst, int dst_size, uint16_t model_id, uint8_t model_counter); #endif /* CMP_CHUNK_H */ diff --git a/lib/common/cmp_data_types.c b/lib/common/cmp_data_types.c index 7a6989b2f3c755386bfa06bbae15d6c8f3db4f8d..122cd6814e19967b9649cf783403a9c19bbd124b 100644 --- a/lib/common/cmp_data_types.c +++ b/lib/common/cmp_data_types.c @@ -362,7 +362,14 @@ int cmp_col_set_data_length(struct collection_hdr *col, uint16_t length) } -/* TODO: doc string */ +/** + * @brief converts a subservice to its associated compression data type + * + * @param subservice collection subservice + * + * @returns the converted compression data type; DATA_TYPE_UNKNOWN if the + * subservice is unknown + */ enum cmp_data_type convert_subservice_to_cmp_data_type(uint8_t subservice) { @@ -413,9 +420,15 @@ enum cmp_data_type convert_subservice_to_cmp_data_type(uint8_t subservice) } -/* TODO: doc string */ +/** + * @brief converts a compression data type to its associated subservice. + * + * @param data_type compression data type + * + * @returns the converted subservice; -1 if the data type is unknown. + */ -uint8_t convert_data_type_to_subservice(enum cmp_data_type data_type) +uint8_t convert_cmp_data_type_to_subservice(enum cmp_data_type data_type) { uint8_t sst = 0; @@ -840,7 +853,20 @@ static void be_to_cpus_f_fx_efx_ncob_ecob(struct f_fx_efx_ncob_ecob *a, uint32_t } -/* TODO: doc string */ +/** + * @brief swaps the endianness of (collection) data from big endian to the CPU + * endianness (or vice versa) in place. + * @note if you want to swap the data of a whole collection, including a + * collection header or a chunk of collections use the be_to_cpu_chunk() or + * cpu_to_be_chunk() functions + * + * @param data a pointer to the data to swap (not including a + * collection header); can be NULL + * @param data_size_byte size of the data in bytes + * @param data_type compression data type + * + * @returns 0 on success; -1 on failure + */ int be_to_cpu_data_type(void *data, uint32_t data_size_byte, enum cmp_data_type data_type) { @@ -916,10 +942,12 @@ int be_to_cpu_data_type(void *data, uint32_t data_size_byte, enum cmp_data_type case DATA_TYPE_F_FX_EFX_NCOB_ECOB: be_to_cpus_f_fx_efx_ncob_ecob(data, samples); break; + /* LCOV_EXCL_START */ case DATA_TYPE_UNKNOWN: default: debug_print("Error: Can not swap endianness for this compression data type."); return -1; + /* LCOV_EXCL_STOP */ } #endif /*__BYTE_ORDER__ */ @@ -927,14 +955,22 @@ int be_to_cpu_data_type(void *data, uint32_t data_size_byte, enum cmp_data_type } -/* we do not convert the endianness of the collection header */ -/* TODO: doc string */ +/** + * @brief swaps the endianness of chunk data from big endian to the CPU + * endianness (or vice versa) in place + * @note the endianness of the collection header is not changed! + * + * @param chunk pointer to a chunk of collections (can be NULL) + * @param chunk_size size in bytes of the chunk + * + * @returns 0 on success; -1 on failure + */ int be_to_cpu_chunk(uint8_t *chunk, size_t chunk_size) { uint8_t *col_p = chunk; - if (!chunk) + if (!chunk) /* nothing to do */ return 0; if (chunk_size < COLLECTION_HDR_SIZE) diff --git a/lib/common/cmp_data_types.h b/lib/common/cmp_data_types.h index 267baf1487b59b0160e6395ee1fd77f367b1b993..a64661e8e85c3ecba44b4911f2bc3f78d91009eb 100644 --- a/lib/common/cmp_data_types.h +++ b/lib/common/cmp_data_types.h @@ -324,6 +324,7 @@ int cmp_col_set_sequence_num(struct collection_hdr *col, uint8_t sequence_num); int cmp_col_set_data_length(struct collection_hdr *col, uint16_t length); enum cmp_data_type convert_subservice_to_cmp_data_type(uint8_t subservice); +uint8_t convert_cmp_data_type_to_subservice(enum cmp_data_type data_type); size_t size_of_a_sample(enum cmp_data_type data_type); uint32_t cmp_cal_size_of_data(uint32_t samples, enum cmp_data_type data_type); diff --git a/lib/common/cmp_entity.c b/lib/common/cmp_entity.c index 82c697c18345ecbec14c1ce088cf54343082b073..46df7e957266a35fa69606ac94a8969527455ec0 100644 --- a/lib/common/cmp_entity.c +++ b/lib/common/cmp_entity.c @@ -1637,28 +1637,24 @@ uint16_t cmp_ent_get_non_ima_cmp_par6(const struct cmp_entity *ent) void *cmp_ent_get_data_buf(struct cmp_entity *ent) { enum cmp_data_type data_type; + void *data_ptr; if (!ent) return NULL; data_type = cmp_ent_get_data_type(ent); - if (data_type == DATA_TYPE_UNKNOWN) { - debug_print("Error: Compression data type not supported."); - return NULL; - } - - if (cmp_ent_get_data_type_raw_bit(ent)) - return (uint8_t *)ent + GENERIC_HEADER_SIZE; switch (data_type) { case DATA_TYPE_IMAGETTE: case DATA_TYPE_SAT_IMAGETTE: case DATA_TYPE_F_CAM_IMAGETTE: - return ent->ima.ima_cmp_dat; + data_ptr = ent->ima.ima_cmp_dat; + break; case DATA_TYPE_IMAGETTE_ADAPTIVE: case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE: case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE: - return ent->ima.ap_ima_cmp_data; + data_ptr = ent->ima.ap_ima_cmp_data; + break; case DATA_TYPE_OFFSET: case DATA_TYPE_BACKGROUND: case DATA_TYPE_SMEARING: @@ -1677,13 +1673,19 @@ void *cmp_ent_get_data_buf(struct cmp_entity *ent) case DATA_TYPE_F_CAM_OFFSET: case DATA_TYPE_F_CAM_BACKGROUND: case DATA_TYPE_CHUNK: - return ent->non_ima.cmp_data; - /* LCOV_EXCL_START */ + data_ptr = ent->non_ima.cmp_data; + break; case DATA_TYPE_UNKNOWN: default: + debug_print("Error: Compression data type not supported."); return NULL; - /* LCOV_EXCL_STOP */ } + + /* the uncompressed data do not have a specific entity header */ + if (cmp_ent_get_data_type_raw_bit(ent)) + return (uint8_t *)ent + GENERIC_HEADER_SIZE; + + return data_ptr; } diff --git a/lib/common/cmp_support.c b/lib/common/cmp_support.c index fe6d486b94102937d74691ae7e915bb52346eb3e..a211c3c4acad03e11b3f8b1e8780a32de2de6000 100644 --- a/lib/common/cmp_support.c +++ b/lib/common/cmp_support.c @@ -132,7 +132,6 @@ int rdcu_supported_cmp_mode_is_used(enum cmp_mode cmp_mode) default: return 0; } - } diff --git a/lib/common/compiler.h b/lib/common/compiler.h index 7a8e12142366326795e10d7d046e3f79875befe6..983ffa46d046fa6bafbf102a8271387741ea0c6c 100644 --- a/lib/common/compiler.h +++ b/lib/common/compiler.h @@ -147,6 +147,11 @@ * It does *not* protect against the actual use of the "unused" variables. */ -#define MAYBE_UNUSED __attribute__((__unused__)) +#if (DEBUGLEVEL == 0) +#define MAYBE_UNUSED __attribute__((unused)) +#else +#define MAYBE_UNUSED +#endif + #endif /* COMPILER_H */ diff --git a/lib/icu_compress/cmp_icu.c b/lib/icu_compress/cmp_icu.c index 4b8f3e9f6d788dbee4289c25931897e1e291796b..5ce8e224a44619f677a4b202e5689748a2c6cc3b 100644 --- a/lib/icu_compress/cmp_icu.c +++ b/lib/icu_compress/cmp_icu.c @@ -56,7 +56,7 @@ static uint64_t default_get_timestamp(void) /** * @brief function pointer to a function returning a current PLATO timestamp - * initialised with the compress_chunk_init() function + * initialised with the compress_chunk_init() function */ static uint64_t (*get_timestamp)(void) = default_get_timestamp; @@ -64,7 +64,7 @@ static uint64_t (*get_timestamp)(void) = default_get_timestamp; /** * @brief holding the version_identifier for the compression header - * initialised with the compress_chunk_init() function + * initialised with the compress_chunk_init() function */ static uint32_t version_identifier; @@ -96,7 +96,10 @@ struct encoder_setupt { }; -/* TODO: doc string */ +/** + * @brief types of chunks containing different types of collection + * according to DetailedBudgetWorking_2023-10-11 + */ enum chunk_type { CHUNK_TYPE_UNKNOWN, @@ -523,8 +526,8 @@ static uint32_t rice_encoder(uint32_t value, uint32_t m, uint32_t log2_m, /* * 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 and qc = 0. To prevent undefined b - * ehavior, the right shift operand is masked (& 0x1FU) + * bits can only be formed if q = 0 and qc = 0. To prevent undefined + * behavior, the right shift operand is masked (& 0x1FU) */ return rl + q; /* calculate the length of the code word */ @@ -772,10 +775,9 @@ static int encode_value(uint32_t data, uint32_t model, int stream_len, * @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 buffer_length length of the icu_output_buf in bytes * * @returns buffer size in bits - * */ static uint32_t cmp_buffer_length_to_bits(uint32_t buffer_length) @@ -2119,7 +2121,21 @@ static int pad_bitstream(const struct cmp_cfg *cfg, int cmp_size) } -/* TODO: doc string */ +/** + * @brief internal data compression function + * This function can compress all types of collection data (one at a time). + * This function does not take the header of a collection into account. + * + * @param cfg pointer to a compression configuration + * + * @note the validity of the cfg structure is checked before the compression is + * started + * + * @returns the bit length of the bitstream on success; negative on error, + * CMP_ERROR_SMALL_BUF (-2) if the compressed data buffer is too small to + * hold the whole compressed data, CMP_ERROR_HIGH_VALUE (-3) if a data or + * model value is bigger than the max_used_bits parameter + */ static int compress_data_internal(const struct cmp_cfg *cfg, int stream_len) { @@ -2131,7 +2147,7 @@ static int compress_data_internal(const struct cmp_cfg *cfg, int stream_len) if (stream_len < 0) return stream_len; - if (cfg->samples == 0) /* nothing to compress we are done*/ + if (cfg->samples == 0) /* nothing to compress we are done */ return stream_len; if (stream_len & 0x7) { @@ -2286,7 +2302,14 @@ int icu_compress_data(const struct cmp_cfg *cfg) } -/* TODO: doc string */ +/** + * @brief estimate a "good" spillover threshold parameter + * + * @param golomb_par Golomb parameter + * + * @returns a spill over threshold parameter + * TODO: tune this calculation for multi escape symbol mechanism + */ static uint32_t cmp_guess_good_spill(uint32_t golomb_par) { @@ -2296,26 +2319,52 @@ static uint32_t cmp_guess_good_spill(uint32_t golomb_par) } -/* TODO: doc string */ +/** + * @brief set the compressed collection size field + * + * @param cmp_col_size_field pointer to the compressed collection size field + * @param cmp_col_size size of the compressed collection (not including + * the compressed collection header size and the + * size of the compressed collection size field + * itself) + * + * @returns 0 on success; -1 on failure + */ -static int set_cmp_col_size(uint8_t *p, int cmp_col_size) +static int set_cmp_col_size(uint8_t *cmp_col_size_field, int32_t cmp_col_size) { - uint16_t v = (uint16_t)cmp_col_size; + uint16_t const v = cpu_to_be16((uint16_t)cmp_col_size); if (cmp_col_size > UINT16_MAX) return -1; - v -= COLLECTION_HDR_SIZE+CMP_COLLECTION_FILD_SIZE; - if (p) { - memset(p, v >> 8, 1); - memset(p+1, v & 0xFF, 1); - } + if (cmp_col_size_field) + memcpy(cmp_col_size_field, &v, CMP_COLLECTION_FILD_SIZE); return 0; } -/* TODO: doc string */ +/** + * @brief compresses a collection (with a collection header followed by data) + * + * @param col pointer to a collection header + * @param model pointer to the model to be used for compression, or NULL + * if not applicable + * @param updated_model pointer to the buffer where the updated model will be + * stored, or NULL if not applicable + * @param dst pointer to the buffer where the compressed data will be + * stored, or NULL to only get the size + * @param dst_capacity the size of the dst buffer in bytes + * @param cfg pointer to a compression configuration + * @param dst_size the already used size of the dst buffer in bytes + * + * @returns the size of the compressed data in bytes (new dst_size) on + * success; negative on error, CMP_ERROR_SMALL_BUF (-2) if the compressed + * data buffer is too small to hold the whole compressed data; the + * compressed and updated model are only valid on positive return + * values + */ static int32_t cmp_collection(uint8_t *col, uint8_t *model, uint8_t *updated_model, uint32_t *dst, uint32_t dst_capacity, @@ -2394,14 +2443,35 @@ static int32_t cmp_collection(uint8_t *col, uint8_t *model, uint8_t *updated_mod } dst_size = (int32_t)cmp_bit_to_byte((unsigned int)dst_size_bits); /*TODO: fix casts */ - if (dst && cfg->cmp_mode != CMP_MODE_RAW) - if (set_cmp_col_size((uint8_t *)dst+dst_size_begin, dst_size-dst_size_begin)) + if (dst && cfg->cmp_mode != CMP_MODE_RAW) { + int32_t cmp_col_size = dst_size - dst_size_begin - + COLLECTION_HDR_SIZE - CMP_COLLECTION_FILD_SIZE; + + if (set_cmp_col_size((uint8_t *)dst+dst_size_begin, cmp_col_size)) return -1; + } return dst_size; } +/** + * @brief builds a compressed entity header for a compressed chunk + * + * @param ent start address of the compression entity header + * (can be NULL if you only wont the entity header + * size) + * @param chunk_size the original size of the chunk in bytes + * @param cfg pointer to the compression configuration used to + * compress the chunk + * @param start_timestamp the start timestamp of the chunk compression + * @param cmp_ent_size_byte the size of the compression entity (entity + * header plus compressed data) + * + * @return the size of the compressed entity header in bytes, or -1 if an error + * occurred + */ + static int cmp_ent_build_chunk_header(struct cmp_entity *ent, uint32_t chunk_size, const struct cmp_cfg *cfg, uint64_t start_timestamp, int32_t cmp_ent_size_byte) @@ -2446,13 +2516,25 @@ static int cmp_ent_build_chunk_header(struct cmp_entity *ent, uint32_t chunk_siz if (err) return -1; } - return NON_IMAGETTE_HEADER_SIZE; + + if (cfg->cmp_mode == CMP_MODE_RAW) + return GENERIC_HEADER_SIZE; + else + return NON_IMAGETTE_HEADER_SIZE; } -/* TODO: doc string; ref document */ +/** + * @brief map a sub-service to a chunk service according to + * DetailedBudgetWorking_2023-10-11 + * + * @param subservice subservice of a science data product + * + * @returns the chunk type of the subservice on success, CHUNK_TYPE_UNKNOWN on + * failure + */ -static enum chunk_type get_chunk_type(uint16_t subservice) +static enum chunk_type get_chunk_type(uint8_t subservice) { enum chunk_type chunk_type = CHUNK_TYPE_UNKNOWN; @@ -2504,14 +2586,33 @@ static enum chunk_type get_chunk_type(uint16_t subservice) } +/** + * @brief get the chunk_type of a collection + * + * @param col pointer to a collection header + * + * @returns chunk type of the collection + */ + static enum chunk_type cmp_col_get_chunk_type(const struct collection_hdr *col) { return get_chunk_type(cmp_col_get_subservice(col)); } -static int read_in_cmp_par(const struct cmp_par *par, enum chunk_type chunk_type, - struct cmp_cfg *cfg) +/** + * @brief Set the compression configuration from the compression parameters + * based on the chunk type + * + * @param[in] par pointer to a compression parameters struct + * @param[in] chunk_type the type of the chunk to be compressed + * @param[out] cfg pointer to a compression configuration + * + * @returns 0 success; -1 on failure + */ + +static int init_cmp_cfg_from_cmp_par(const struct cmp_par *par, enum chunk_type chunk_type, + struct cmp_cfg *cfg) { memset(cfg, 0, sizeof(struct cmp_cfg)); @@ -2622,11 +2723,12 @@ void compress_chunk_init(uint64_t(return_timestamp)(void), uint32_t version_id) * compress_chunk_cmp_size_bound(chunk, chunk_size) * as it eliminates one potential failure scenario: * not enough space in the dst buffer to write the - * compressed data; size is round down to a multiple - * of 4 + * compressed data; size is internally round down + * to a multiple of 4 * @returns the byte size of the compressed_data buffer on success; negative on * error, CMP_ERROR_SMALL_BUF (-2) if the compressed data buffer is too - * small to hold the whole compressed data + * small to hold the whole compressed data; the compressed and updated + * model are only valid on non negative return values */ int32_t compress_chunk(void *chunk, uint32_t chunk_size, @@ -2655,11 +2757,12 @@ int32_t compress_chunk(void *chunk, uint32_t chunk_size, return -1; } + chunk_type = cmp_col_get_chunk_type(col); + if (init_cmp_cfg_from_cmp_par(cmp_par, chunk_type, &cfg)) + return -1; + /* we will build the compression header after the compression of the chunk */ - if (cmp_par->cmp_mode == CMP_MODE_RAW) - cmp_size_byte = GENERIC_HEADER_SIZE; - else - cmp_size_byte = NON_IMAGETTE_HEADER_SIZE; + cmp_size_byte = cmp_ent_build_chunk_header(NULL, chunk_size, &cfg, start_timestamp, 0); if (dst) { if (dst_capacity < (uint32_t)cmp_size_byte) { debug_print("Error: The destination capacity is smaller than the minimum compression entity size."); @@ -2668,10 +2771,6 @@ int32_t compress_chunk(void *chunk, uint32_t chunk_size, memset(dst, 0, (uint32_t)cmp_size_byte); } - chunk_type = cmp_col_get_chunk_type(col); - if (read_in_cmp_par(cmp_par, chunk_type, &cfg)) - return -1; - for (read_bytes = 0; read_bytes < chunk_size - COLLECTION_HDR_SIZE; read_bytes += cmp_col_get_size(col)) { @@ -2747,7 +2846,7 @@ uint32_t compress_chunk_cmp_size_bound(const void *chunk, size_t chunk_size) return 0; } - return COMPRESS_CHUNK_BOUND((uint32_t)chunk_size, num_col); + return (uint32_t)COMPRESS_CHUNK_BOUND(chunk_size, num_col); } @@ -2765,13 +2864,11 @@ uint32_t compress_chunk_cmp_size_bound(const void *chunk, size_t chunk_size) * @returns 0 on success, otherwise error */ -int compress_chunk_set_model_id_and_counter(uint32_t *dst, int dst_size, +int compress_chunk_set_model_id_and_counter(void *dst, int dst_size, uint16_t model_id, uint8_t model_counter) { - if (dst_size < NON_IMAGETTE_HEADER_SIZE) + if (dst_size < GENERIC_HEADER_SIZE) return 1; - return cmp_ent_set_model_id((struct cmp_entity *)dst, model_id) || - cmp_ent_set_model_counter((struct cmp_entity *)dst, model_counter); - + return cmp_ent_set_model_id(dst, model_id) || cmp_ent_set_model_counter(dst, model_counter); }