From: Moritz Hanke Date: Fri, 11 May 2012 12:59:04 +0000 (+0200) Subject: adds initial code for binary header decoding X-Git-Tag: accepted/tizen/5.0/unified/20181102.025501~286 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=adddb9a0b04fe055daa7f6f074d774330747c5ab;p=platform%2Fupstream%2Flibaec.git adds initial code for binary header decoding --- diff --git a/include/bit_macros.h b/include/bit_macros.h new file mode 100644 index 0000000..617f0e9 --- /dev/null +++ b/include/bit_macros.h @@ -0,0 +1,16 @@ +#define B1 (0x0001) +#define B2 (0x0003) +#define B3 (0x0007) +#define B4 (0x000F) +#define B5 (0x001F) +#define B6 (0x003F) +#define B7 (0x007F) +#define B8 (0x00FF) +#define B9 (0x01FF) +#define B10 (0x03FF) +#define B11 (0x07FF) +#define B12 (0x0FFF) +#define B13 (0x1FFF) +#define B14 (0x3FFF) +#define B15 (0x7FFF) +#define B16 (0xFFFF) diff --git a/include/cip.h b/include/cip.h new file mode 100644 index 0000000..8d1d603 --- /dev/null +++ b/include/cip.h @@ -0,0 +1,137 @@ +// Copyright © 2011 Moritz Hanke + +// Based on Lossless Data Compression. Blue Book. Issue 1. May 1997. +// CCSDS 121.0-B-1 +// +// http://public.ccsds.org/publications/bluebooks.aspx +// http://public.ccsds.org/publications/archive/121x0b1c2.pdf + +// Compression Identification Packet (optinal) +// The CIP is used to configure the decompressor in case no configuration +// data is available. +// It is comprised of the cip Primary Header (as described in "CCSDS Space +// Packet Protocol Blue Book") and the Packet Data Field. + +enum cip_packet_type { + + TELEMETRY, // reporting + TELECOMMAND, // requesting (makes no sense for compression) +}; + +enum cip_sequence_flag { + + CONTINUE = 0, + FIRST = 1, + LAST = 2, + UNSEGMENTED = 3, +}; + +enum cip_compression_technique { + + NO = 0, // no compression is used + LOSSLESS = 1, // lossless compression is used +}; + +enum cip_predictor_type { + + BYPASS_P = 0, // bypass predictor + UNIT_DELAY_P = 1, // unit delay predictor + APP_SPECIFIC_P = 7, // application-specific predictor +}; + +enum cip_mapper_type { + + STANDARD_M = 0, // standard prediction error mapper as described in the reference + APP_SPECIFIC_M = 3, // application-specific mapper +}; + +enum cip_data_sense { + + TWOS_COMPLEMENT = 0, // two's complement + POSITIVE = 1, // positive (mandatory if preprocessor is bypassed) +}; + +enum entropy_coder_option { + + OPTION_S = 1, // for resolution n <= 8 + OPTION_M = 2, // for resolution 8 < n <= 16 + OPTION_L = 3, // for resolution 16 < n <= 32 +}; + +struct cip_header { + + //---------------------------- + // Packet Primary Header data + //---------------------------- + + char packet_version_number; // Packet Version Number + + // Packet Identification + enum cip_packet_type type; // Packet Type + char secondary_header_available; // Sequence Header Flag + unsigned apid; // Application Process Identifier + + // Packet Sequence Control + enum cip_sequence_flag sequence_flag; // Sequence Flags + unsigned sequence_count; // Packet Sequence Count + // in case of a TELECOMMAND type cip + // data package this contains the + // Packet Name + + unsigned data_length; // length of the Packet Data Field - 1 in byte +}; + +struct cip_preprocessor_configuration { + + char preprocessor_present; // Preprocessor Status (0 - absent, 1 - present) + + enum cip_predictor_type predictor_type; // Predictor type (undefined if preprocessor is absent) + + enum cip_mapper_type mapper_type; // Mapper type (undefined if preprocessor is absent) + + char block_size; // Block size (8, 16 or application specific) + + enum cip_data_sense data_sense; + + char resolution; // Input data sample resolution (1-32) +}; + +struct cip_entropy_coder_configuration { + + enum entropy_coder_option option; // Entropy Coder option + + unsigned num_cds_per_packet; // Number of coded data sets per packet +}; + +struct cip_source_data_field { + + unsigned grouping_data_length; // Grouping Data Length + + enum cip_compression_technique compression_technique; // Compression Technique Identification + + unsigned reference_sample_interval; // Reference Sample Interval + // - in case a preprocessor is + // used that requires a + // reference sample + // - in case of the zero-block + // option it contains the + // interval of input data sample + // blocks + + struct cip_preprocessor_configuration preprocessor_config; // Preprocessor Configuration + + struct cip_entropy_coder_configuration entropy_coder_config; // Entropy Coder Configuration +}; + +struct cip { + + struct cip_header header; // Information from the Primary Header + struct cip_source_data_field sdf; // Information on the data +}; + +void * decode_cip(void * buffer, struct cip * cip); + // data: buffer starting with a cip + // cip: in case cip is not NULL the configuration information + // contained in the cip is written to it + // returns a pointer to the compressed data without the cip + // returns NULL in case an error occured while decoding diff --git a/src/cip.c b/src/cip.c new file mode 100644 index 0000000..ff071bb --- /dev/null +++ b/src/cip.c @@ -0,0 +1,305 @@ +// Copyright © 2011 Moritz Hanke + +#include +#include +#include + +#include "bit_macros.h" +#include "cip.h" + +// decode Packet Primary Header +void * decode_pph(void * buffer, struct cip * cip); + +// decode Secondary Header +void * decode_sh(void * buffer, struct cip * cip); + +// decode Source Data Field +void * decode_sdf(void * buffer, struct cip * cip); + +// decode Preprocessor Parameters +void * decode_preprocessor(void * buffer, struct cip * cip); + +// decode Entopy Coder Parameters +void * decode_entropy_coder(void * buffer, struct cip * cip); + +// decode Instrument Configuration +void * decode_instrument_configuration(void * buffer, struct cip * cip); + +void * decode_cip(void * buffer, struct cip * cip) { + + void * pdf; // Packet Data Field + void * sdf; // Source Data Field + void * cds; // Coded data sets + + pdf = decode_pph(buffer, cip); + + if (cip->header.secondary_header_available) + sdf = decode_sh(pdf, cip); + else + sdf = pdf; + + cds = decode_sdf(sdf, cip); + + if ((char*)cds > (char*)pdf + cip->header.data_length + 1) { + + fprintf(stderr, "Packet Data Field is bigger than specified in CIP Packet Primary Header\n"); + exit(EXIT_FAILURE); + } + + return (char*)pdf + cip->header.data_length + 1; +} + +// decode Primary Header +void * decode_pph(void * buffer, struct cip * cip) { + + char * cip_buf = buffer; + + // Packet Version Number + + cip->header.packet_version_number = (cip_buf[0] >> 5) & B3 ; + + if (cip->header.packet_version_number != 0) { + + fprintf(stderr, "Undefined Packet Version Number\n"); + exit(EXIT_FAILURE); + } + + // Packet Identification + { + // Packet Type + + cip->header.type = ((cip_buf[0] >> 4) & B1)?TELECOMMAND:TELEMETRY; + + // is a Secondary Header available + + cip->header.secondary_header_available = (cip_buf[0] >> 3) & B1; + + // Application Process Identifer + + cip->header.apid = ((unsigned)(cip_buf[0] & B3) << 8) | cip_buf[1]; + } + + // Packet Sequence Control + { + // Sequence Flags + + cip->header.sequence_flag = (cip_buf[2] >> 6) & B2; + + // Packet Sequence Count or Packet Name + + assert(sizeof(unsigned) > 2); + + cip->header.sequence_count = ((unsigned)(cip_buf[2] & B6) << 8) | + cip_buf[3]; + } + + // Packet Data Length + + cip->header.data_length = ((unsigned)cip_buf[4] << 8) | cip_buf[5]; + + return (char*)cip + 6; // the Packet Primary Header has a size of 48 + // bits +} + +void * decode_sh(void * buffer, struct cip * cip) { + + // The Secondary Header contains information like time and position + // or attitude of a spacecraft. + // The handling of a Secondary Header is currently not implemented. + + fprintf(stderr, "Compression Identification Packet contains a Secondary Header\n"); + exit(EXIT_FAILURE); + + return buffer; +} + +void * decode_sdf(void * buffer, struct cip * cip) { + + char * sdf = buffer; + + // Grouping Data Length (number of packets containing compressed data) + + cip->sdf.grouping_data_length = (((unsigned)(sdf[0] & B4) << 8) | + sdf[1]) + 1; + + // check whether a compression is used for the current group + + if (sdf[2] > 1) { + + fprintf(stderr, "Undefined compression technique\n"); + exit(EXIT_FAILURE); + } + + cip->sdf.compression_technique = sdf[2]; + + // Reference Sample Interval + + cip->sdf.reference_sample_interval = sdf[3]+1; + + + if (cip->sdf.compression_technique == LOSSLESS) { + + // decode Preprocessor Parameters + sdf = decode_preprocessor(sdf, cip); + } + + // decode Entropy Coder Parameters + sdf = decode_entropy_coder(sdf, cip); + + // decode Instrument Configuration + sdf = decode_instrument_configuration(sdf, cip); + + return sdf; +} + +void * decode_preprocessor(void * buffer, struct cip * cip) { + + char * sdf = buffer; + + unsigned header; + + // check for correct header + header = (sdf[0] >> 6) & B2; + if (header != 0) { + + fprintf(stderr, "Wrong header for preprocessor field\n"); + exit(EXIT_FAILURE); + } + + // get preprocessor presents + cip->sdf.preprocessor_config.preprocessor_present = (sdf[0] >> 5) & B1; + + // if a preprocessor is present + if (cip->sdf.preprocessor_config.preprocessor_present) { + + // Predictor type + switch ((sdf[0] >> 2) & B3) { + + case (0): + cip->sdf.preprocessor_config.predictor_type = BYPASS_P; + break; + case (1): + cip->sdf.preprocessor_config.predictor_type = UNIT_DELAY_P; + break; + case (7): + cip->sdf.preprocessor_config.predictor_type = APP_SPECIFIC_P; + break; + default: + fprintf(stderr, "Invalid predictor type\n"); + exit(EXIT_FAILURE); + }; + + // Mapper type + switch (sdf[0] & B2) { + + case (0): + cip->sdf.preprocessor_config.mapper_type = STANDARD_M; + break; + case (3): + cip->sdf.preprocessor_config.mapper_type = APP_SPECIFIC_M; + break; + default: + fprintf(stderr, "Invalid mapper type\n"); + exit(EXIT_FAILURE); + }; + } + + // Block size (J) + switch ((sdf[1] >> 6) & B2) { + + case (0): + cip->sdf.preprocessor_config.block_size = 8; + break; + case (1): + cip->sdf.preprocessor_config.block_size = 16; + break; + case(3): + fprintf(stderr, "Missing implementation for application-specific block size\n"); + exit(EXIT_FAILURE); + default: + fprintf(stderr, "Invalid block size\n"); + exit(EXIT_FAILURE); + }; + + // Data sense + cip->sdf.preprocessor_config.data_sense = (sdf[1] >> 5) & 1; + + // check whether preprocessor presents and data sense match + if (!cip->sdf.preprocessor_config.preprocessor_present && + cip->sdf.preprocessor_config.data_sense != POSITIVE) { + + fprintf(stderr, "If no preprocessor is present, the data sense has to be positive.\n"); + exit(EXIT_FAILURE); + } + + // Input data sample resolution + cip->sdf.preprocessor_config.resolution = (sdf[1] & B5) + 1; + + return (char*)buffer + 2; // the preprocessor field has a size of 2 byte +} + +void * decode_entropy_coder(void * buffer, struct cip * cip) { + + char * sdf = buffer; + + unsigned header; + + // check for correct header + header = (sdf[0] >> 6) & B2; + if (header != 1) { + + fprintf(stderr, "Wrong header for entropy coder field\n"); + exit(EXIT_FAILURE); + } + + // Entropy Coder option + switch ((sdf[0] >> 4) & B2) { + + case (1): + if (cip->sdf.preprocessor_config.resolution > 8) { + + fprintf(stderr, "Entropy coder option does not match input data sample resolution\n"); + exit(EXIT_FAILURE); + } + cip->sdf.entropy_coder_config.option = OPTION_S; + break; + case (2): + if ((cip->sdf.preprocessor_config.resolution <= 8) || + (cip->sdf.preprocessor_config.resolution > 16)) { + + fprintf(stderr, "Entropy coder option does not match input data sample resolution\n"); + exit(EXIT_FAILURE); + } + cip->sdf.entropy_coder_config.option = OPTION_M; + break; + case (3): + if ((cip->sdf.preprocessor_config.resolution <= 16) || + (cip->sdf.preprocessor_config.resolution > 32)) { + + fprintf(stderr, "Entropy coder option does not match input data sample resolution\n"); + exit(EXIT_FAILURE); + } + cip->sdf.entropy_coder_config.option = OPTION_L; + break; + default: + fprintf(stderr, "Invalid entropy coder option\n"); + exit(EXIT_FAILURE); + }; + + assert(sizeof(unsigned) > 2); + + // Number of coded data sets per packet + cip->sdf.entropy_coder_config.num_cds_per_packet = + (((unsigned)(sdf[0] & B4) << 8) | sdf[1]) + 1; + + return (char*)buffer + 2; // entropy coder field has a size of 2 byte +} + +void * decode_instrument_configuration(void * buffer, struct cip * cip) { + + // Instrument Configuration is mission specific. + // This implementation assumes that there is no. + // In an one is added later, the first 2 bits of buffer have to 10. + + return buffer; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..4d15230 --- /dev/null +++ b/src/main.c @@ -0,0 +1,12 @@ +// Copyright © 2011 Moritz Hanke + +#include + +#include "cip.h" + +int main() { + + + + return EXIT_SUCCESS; +}