adds initial code for binary header decoding
authorMoritz Hanke <hanke@dkrz.de>
Fri, 11 May 2012 12:59:04 +0000 (14:59 +0200)
committerMoritz Hanke <hanke@dkrz.de>
Fri, 11 May 2012 12:59:04 +0000 (14:59 +0200)
include/bit_macros.h [new file with mode: 0644]
include/cip.h [new file with mode: 0644]
src/cip.c [new file with mode: 0644]
src/main.c [new file with mode: 0644]

diff --git a/include/bit_macros.h b/include/bit_macros.h
new file mode 100644 (file)
index 0000000..617f0e9
--- /dev/null
@@ -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 (file)
index 0000000..8d1d603
--- /dev/null
@@ -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 (file)
index 0000000..ff071bb
--- /dev/null
+++ b/src/cip.c
@@ -0,0 +1,305 @@
+// Copyright © 2011 Moritz Hanke
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#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 (file)
index 0000000..4d15230
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright © 2011 Moritz Hanke
+
+#include <stdlib.h>
+
+#include "cip.h"
+
+int main() {
+
+
+
+   return EXIT_SUCCESS;
+}