AlcapDAQ  1
comp_compress.cpp
Go to the documentation of this file.
1 //
3 // Compressor compression :-)
4 //
6 
7 #include <stdio.h>
8 
9 #include "midas.h"
10 
11 #include "mucap_compress.h"
12 #include "mucap_structures.h"
13 
17 
19 {
20  huffman_optimize_tree(&cmp_channel_huffman);
21  huffman_optimize_tree(&cmp_bits_huffman[0]);
22  huffman_optimize_tree(&cmp_bits_huffman[1]);
23 
24  save_huffman("/Compression/Lossless/COMP/Huffman/Channel", &cmp_channel_huffman);
25  save_huffman("/Compression/Lossless/COMP/Huffman/Bits 0", &cmp_bits_huffman[0]);
26  save_huffman("/Compression/Lossless/COMP/Huffman/Bits 1", &cmp_bits_huffman[1]);
27 }
28 
29 void comp_load()
30 {
31  huffman_init_default(&cmp_channel_huffman, 256);
32  huffman_init_default(&cmp_bits_huffman[0], 128);
33  huffman_init_default(&cmp_bits_huffman[1], 128);
34 
35  load_huffman("/Compression/Lossless/COMP/Huffman/Channel", &cmp_channel_huffman);
36  load_huffman("/Compression/Lossless/COMP/Huffman/Bits 0", &cmp_bits_huffman[0]);
37  load_huffman("/Compression/Lossless/COMP/Huffman/Bits 1", &cmp_bits_huffman[1]);
38 
39  int size = sizeof(BOOL);
40  db_get_value(hDB, 0, "/Compression/Lossless/COMP/Enabled", &should_compress_comp,
41  &size, TID_BOOL, TRUE);
42 }
43 
44 static int sign_extend(int in, int bits)
45 {
46  int sign_bit = (1 << (bits-1));
47  if(in & sign_bit) {
48  return in | ~(sign_bit - 1);
49  } else {
50  return in;
51  }
52 }
53 
54 int encode_cmp_bits(comp_word * input, int input_size, io_buffer * output)
55 {
56  //
57  // Run-length encode the bits in the compressor data. See the comment
58  // at the beginning of encode_bits for an explanation of this process.
59  //
60 
61  int num_bit_words = 0;
62  rle_state s = { 0, 0, {128, 128}, 0, cmp_bits_huffman };
63 
64  for (int i = 0; i < input_size; i++) {
65  // This word may be a header/time word:
66  if (num_bit_words == 0) {
67  num_bit_words = input[i].r1.a + input[i].r1.b;
68  } else {
69  for (int j = 0; j < 4; j++) {
70 
71  unsigned char b = input[i].bytes[j];
72  rle_put(b, &s, output);
73  }
74  num_bit_words--;
75  }
76  }
77 
78  return flush_rle(&s, output);
79 }
80 
81 int encode_cmp_times(comp_word * input, int input_size, io_buffer * output)
82 {
83  //
84  // Encode the FPGA numbers and times in the compressor data.
85  //
86  // 1. The B and A bits, which indicate the meaning of the
87  // following words, are preserved.
88  // 2. The FPGA numbers are Huffman coded, since some values are
89  // probably more likely than others.
90  // 3. The times are encoded as successive differences, which are
91  // then stored on a variable scale.
92  //
93 
94  int num_bit_words = 0;
95  int prev_time = 0;
96 
97  for (int i = 0; i < input_size; i++) {
98  // This word may be a header/time word:
99  if (num_bit_words == 0) {
100  num_bit_words = input[i].r1.a + input[i].r1.b;
101 
102  if (num_bit_words != 1 && num_bit_words != 2) {
103  printf("Warning: corrupted compressor data.\n");
104  }
105 
106  int channel = input[i].r1.fpga | input[i].r1.a << 6 | input[i].r1.b << 7;
107  huffman_put_symbol(&cmp_channel_huffman, output, channel);
108 
109  int time_diff = input[i].r1.time - prev_time;
110 
111  if (time_diff < 8 && time_diff >= -8) {
112  io_buffer_put(output, 0, 1);
113  io_buffer_put(output, time_diff & 0xf, 4);
114  } else if (time_diff < 512 && time_diff >= -512) {
115  io_buffer_put(output, 2, 2);
116  io_buffer_put(output, time_diff & 0x3ff, 10);
117  } else {
118  io_buffer_put(output, 3, 2);
119  io_buffer_put(output, time_diff & 0xffffff, 24);
120  }
121 
122  prev_time = input[i].r1.time;
123  }
124 
125  else {
126  num_bit_words--;
127  }
128  }
129 
130  return flush_output_buffer(output);
131 }
132 
133 int cmp_compress(comp_word * input, int input_size, unsigned char *output, int userParam)
134 {
135  //
136  // Encode compressor data, which are in the following format:
137  // | B | A | FPGA number (6 bits) | Time (24 bits) |
138  // ... followed by one or two 32-bit masks indicating which
139  // channels
140  // within the group have fired.
141  //
142 
143  input_size /= sizeof(comp_word);
144 
145  rle_bits_setup();
146 
147  io_buffer output_buffer;
148 
149  // store size of input data
150  int *uncompressed_size_p = (int *) output;
151  *uncompressed_size_p = input_size;
152  output += sizeof(int);
153 
154  // reserve space for the size of the compressed times
155  int *compressed_time_size_p = (int *) output;
156  output += sizeof(int);
157 
158  // compress times
159  start_output_buffer(&output_buffer, output);
160  int compressed_time_size =
161  encode_cmp_times(input, input_size, &output_buffer);
162  output += compressed_time_size;
163 
164  // store size of compressed times
165  *compressed_time_size_p = compressed_time_size;
166 
167  // reserve space for the size of the compressed bit patterns
168  int *compressed_bits_size_p = (int *) output;
169  output += sizeof(int);
170 
171  // compress bit patterns
172  start_output_buffer(&output_buffer, output);
173  int compressed_bits_size =
174  encode_cmp_bits(input, input_size, &output_buffer);
175  output += compressed_time_size;
176 
177  // store size of compressed bit patterns
178  *compressed_bits_size_p = compressed_bits_size;
179 
180  return compressed_time_size + compressed_bits_size + 3 * sizeof(int);
181 }
182 
183 void decode_cmp_times(io_buffer * input, comp_word * output)
184 {
185  //
186  // Reverse the encoding performed by encode_times.
187  //
188 
189  int num_words_in = input->num_codes;
190  int output_size = 0;
191  int prev_time = 0;
192 
193  for (int i = 0; i < num_words_in; i++) {
194 
195  int channel = huffman_get_symbol(&cmp_channel_huffman, input);
196  output[output_size].r1.fpga = channel & 0x3f;
197  output[output_size].r1.a = (channel >> 6) & 1;
198  output[output_size].r1.b = (channel >> 7) & 1;
199 
200  int time_length_flag1 = io_buffer_get(input, 1);
201  int time_diff;
202  if (time_length_flag1 == 0) {
203  time_diff = io_buffer_get(input, 4);
204  time_diff = sign_extend(time_diff, 4);
205  } else {
206  int time_length_flag2 = io_buffer_get(input, 1);
207  if (time_length_flag2 == 0) {
208  time_diff = io_buffer_get(input, 10);
209  time_diff = sign_extend(time_diff, 10);
210  } else {
211  time_diff = io_buffer_get(input, 24);
212  time_diff = sign_extend(time_diff, 24);
213  }
214  }
215 
216  output[output_size].r1.time = (prev_time + time_diff) & 0xffffff;
217  prev_time = output[output_size].r1.time;
218 
219  int num_bit_words =
220  output[output_size].r1.a + output[output_size].r1.b;
221  output_size += 1 + num_bit_words;
222  }
223 }
224 
225 void decode_cmp_bits(io_buffer * input, comp_word * output, int output_size)
226 {
227  int num_bit_words = 0;
228 
229  rle_state s = { 1, 0, {128, 128}, 0, cmp_bits_huffman };
230 
231  for (int i = 0; i < output_size; i++) {
232  if (num_bit_words == 0) {
233  num_bit_words = output[i].r1.a + output[i].r1.b;
234  } else {
235  for (int j = 0; j < 4; j++) {
236  output[i].bytes[j] = rle_get(input, &s);
237  }
238  num_bit_words--;
239  }
240  }
241 }
242 
243 int cmp_expand(unsigned char *input, int input_size, comp_word * output, int userParam)
244 {
245  //
246  // Uncompress the data produced by cmp_compress().
247  //
248 
249  rle_bits_setup();
250 
251  // Get uncompressed data size
252  int *uncompressed_size_p = (int *) input;
253  int uncompressed_size = *uncompressed_size_p;
254  input += sizeof(int);
255  input_size -= sizeof(int);
256 
257  // Get size of compressed time data
258  int *compressed_time_size_p = (int *) input;
259  int compressed_time_size = *compressed_time_size_p;
260  input += sizeof(int);
261  input_size -= sizeof(int);
262 
263  // Uncompress times
264  io_buffer input_buffer;
265  start_input_buffer(&input_buffer, input);
266  decode_cmp_times(&input_buffer, output);
267  input += compressed_time_size;
268  input_size -= compressed_time_size;
269 
270  // Get size of compressed bit patterns
271  int *compressed_bits_size_p = (int *) input;
272  int compressed_bits_size = *compressed_bits_size_p;
273  input += sizeof(int);
274  input_size -= sizeof(int);
275 
276  // Uncompress bit patterns
277  start_input_buffer(&input_buffer, input);
278  decode_cmp_bits(&input_buffer, output, uncompressed_size);
279 
280  return uncompressed_size * sizeof(comp_word);
281 }