CCSDS 124.0-B-1 C 1.0.0
CCSDS 124.0-B-1 Lossless Compression
Loading...
Searching...
No Matches
decompress.c
Go to the documentation of this file.
1
29#include "ccsds124.h"
30#include <string.h>
31
49 const bitvector_t *bv,
50 size_t *positions,
51 size_t max_pos
52) {
53 size_t count = 0U;
54
55 /* Process words in forward order to get positions in ascending order */
56 for (size_t word = 0U; (word < bv->num_words) && (count < max_pos); word++) {
57 uint32_t word_data = bv->data[word];
58
59 while ((word_data != 0U) && (count < max_pos)) {
60 /* Find MSB position using count leading zeros */
61 int clz = __builtin_clz(word_data);
62 size_t bit_pos_in_word = (size_t)clz;
63
64 /* Global position */
65 size_t global_pos = (word * 32U) + bit_pos_in_word;
66
67 if (global_pos < bv->length) {
68 positions[count] = global_pos;
69 count++;
70 }
71
72 /* Clear the MSB we just processed */
73 word_data &= ~(1U << (31U - (uint32_t)clz));
74 }
75 }
76
77 return count;
78}
79
/* End of Internal Helper Functions */
81
88void bitreader_init(bitreader_t *reader, const uint8_t *data, size_t num_bits) {
89 if (reader != NULL) {
90 reader->data = data;
91 reader->num_bits = num_bits;
92 reader->bit_pos = 0U;
93 }
94}
95
96
98 int result = -1;
99
100 if ((reader != NULL) && (reader->bit_pos < reader->num_bits)) {
101 size_t byte_index = reader->bit_pos / 8U;
102 size_t bit_index = reader->bit_pos % 8U;
103
104 /* MSB-first: bit 0 of byte is at position 7 */
105 uint8_t shifted = reader->data[byte_index] >> (7U - bit_index);
106 uint8_t masked = shifted & 1U;
107 result = (int)masked;
108 reader->bit_pos++;
109 }
110
111 return result;
112}
113
114
115uint32_t bitreader_read_bits(bitreader_t *reader, size_t num_bits) {
116 uint32_t value = 0U;
117
118 if ((reader != NULL) && (num_bits <= 32U)) {
119 /* Check sufficient bits remain before reading */
120 if (bitreader_remaining(reader) < num_bits) {
121 return 0U;
122 }
123
124 for (size_t i = 0U; i < num_bits; i++) {
125 int bit = bitreader_read_bit(reader);
126 if (bit >= 0) {
127 value = (value << 1U) | ((uint32_t)bit & 1U);
128 }
129 }
130 }
131
132 return value;
133}
134
135
136size_t bitreader_position(const bitreader_t *reader) {
137 size_t pos = 0U;
138
139 if (reader != NULL) {
140 pos = reader->bit_pos;
141 }
142
143 return pos;
144}
145
146
147size_t bitreader_remaining(const bitreader_t *reader) {
148 size_t remaining = 0U;
149
150 if ((reader != NULL) && (reader->bit_pos < reader->num_bits)) {
151 remaining = reader->num_bits - reader->bit_pos;
152 }
153
154 return remaining;
155}
156
157
159 if (reader != NULL) {
160 size_t bit_offset = reader->bit_pos % 8U;
161 if (bit_offset != 0U) {
162 reader->bit_pos += (8U - bit_offset);
163 }
164 }
165}
166
/* End of Bit Reader Functions */
168
175int ccsds124_count_decode(bitreader_t *reader, uint32_t *value) {
176 int result = CCSDS124_ERROR_INVALID_ARG;
177
178 if ((reader == NULL) || (value == NULL)) {
179 return result;
180 }
181
182 if (bitreader_remaining(reader) == 0U) {
184 }
185
186 /* Read first bit */
187 int bit0 = bitreader_read_bit(reader);
188
189 if (bit0 == 0) {
190 /* Case 1: '0' → value is 1 */
191 *value = 1U;
192 result = CCSDS124_OK;
193 } else {
194 /* First bit is 1, read second bit */
195 int bit1 = bitreader_read_bit(reader);
196
197 if (bit1 == 0) {
198 /* Case 2: '10' → terminator (value 0) */
199 *value = 0U;
200 result = CCSDS124_OK;
201 } else {
202 /* First two bits are 11, read third bit */
203 int bit2 = bitreader_read_bit(reader);
204
205 if (bit2 == 0) {
206 /* Case 3: '110' + 5 bits → value + 2 */
207 if (bitreader_remaining(reader) < 5U) {
209 }
210 uint32_t raw = bitreader_read_bits(reader, 5U);
211 *value = raw + 2U;
212 result = CCSDS124_OK;
213 } else {
214 /* Case 4: '111' + variable bits
215 * Need to find the size by counting zeros until a 1 */
216 size_t size = 0U;
217 int next_bit = 0;
218
219 /* Count zeros to determine field size */
220 do {
221 next_bit = bitreader_read_bit(reader);
222 if (next_bit < 0) {
224 }
225 size++;
226 } while (next_bit == 0);
227
228 /* Size of value field is size + 5 */
229 size_t value_bits = size + 5U;
230
231 /* Back up one bit since the '1' is part of the value */
232 reader->bit_pos--;
233
234 /* Check sufficient bits remain for value field */
235 if (bitreader_remaining(reader) < value_bits) {
237 }
238
239 /* Read the value field */
240 uint32_t raw = bitreader_read_bits(reader, value_bits);
241 *value = raw + 2U;
242 result = CCSDS124_OK;
243 }
244 }
245 }
246
247 return result;
248}
249
250
251int ccsds124_rle_decode(bitreader_t *reader, bitvector_t *result, size_t length) {
252 int status = CCSDS124_ERROR_INVALID_ARG;
253
254 if ((reader == NULL) || (result == NULL)) {
255 return status;
256 }
257
258 /* Initialize result to all zeros */
259 (void)bitvector_init(result, length);
260 bitvector_zero(result);
261
262 /* Start from end of vector (matching RLE encoding which processes LSB to MSB) */
263 size_t bit_position = length;
264
265 /* Read COUNT values until terminator */
266 uint32_t delta = 0U;
267 status = ccsds124_count_decode(reader, &delta);
268
269 while ((status == CCSDS124_OK) && (delta != 0U)) {
270 /* Delta represents (count of zeros + 1) */
271 if (delta > bit_position) {
272 /* Invalid: delta exceeds remaining positions (v1.6/v1.7/v1.8) */
274 }
275 bit_position -= delta;
276 /* Set the bit at this position */
277 bitvector_set_bit(result, bit_position, 1);
278
279 /* Read next delta */
280 status = ccsds124_count_decode(reader, &delta);
281 }
282
283 return status;
284}
285
286
287int ccsds124_bit_insert(bitreader_t *reader, bitvector_t *data, const bitvector_t *mask) {
288 int status = CCSDS124_ERROR_INVALID_ARG;
289
290 if ((reader == NULL) || (data == NULL) || (mask == NULL)) {
291 return status;
292 }
293
294 if (data->length != mask->length) {
295 return status;
296 }
297
298 size_t hamming = bitvector_hamming_weight(mask);
299
300 if (hamming == 0U) {
301 /* No bits to insert */
302 return CCSDS124_OK;
303 }
304
305 /* Check sufficient bits remain before reading */
306 if (bitreader_remaining(reader) < hamming) {
308 }
309
310 /* Collect positions of '1' bits in mask using word-level processing */
311 size_t positions[CCSDS124_MAX_PACKET_LENGTH];
312 size_t pos_count = bitvector_get_set_positions(mask, positions, hamming);
313
314 /* Insert bits in reverse order (matching BE extraction) */
315 for (size_t i = pos_count; i > 0U; i--) {
316 int bit = bitreader_read_bit(reader);
317 if (bit < 0) {
319 }
320 bitvector_set_bit(data, positions[i - 1U], bit);
321 }
322
323 status = CCSDS124_OK;
324 return status;
325}
326
/* End of Decoding Functions */
328
337 size_t F,
338 const bitvector_t *initial_mask,
339 uint8_t robustness
340) {
341 if (decomp == NULL) {
343 }
344
345 if ((F == 0U) || (F > (size_t)CCSDS124_MAX_PACKET_LENGTH)) {
347 }
348
349 if (robustness > (uint8_t)CCSDS124_MAX_ROBUSTNESS) {
351 }
352
353 /* Store configuration */
354 decomp->F = F;
355 decomp->robustness = robustness;
356
357 /* Initialize bit vectors */
358 (void)bitvector_init(&decomp->mask, F);
359 (void)bitvector_init(&decomp->initial_mask, F);
360 (void)bitvector_init(&decomp->prev_output, F);
361 (void)bitvector_init(&decomp->Xt, F);
362
363 /* Set initial mask */
364 if (initial_mask != NULL) {
365 bitvector_copy(&decomp->initial_mask, initial_mask);
366 bitvector_copy(&decomp->mask, initial_mask);
367 } else {
369 bitvector_zero(&decomp->mask);
370 }
371
372 /* Initialize diagnostics */
373 decomp->mask_inconsistent = 0U;
374 decomp->count_f_mismatch = 0U;
375
376 /* Initialize accuracy guarantee tracking */
377 decomp->mask_synced = 0U;
378 decomp->received_status_count = 0U;
379 decomp->received_status_index = 0U;
380 (void)memset(decomp->received_status_ring, 0, sizeof(decomp->received_status_ring));
381
382 /* Reset state */
384
385 return CCSDS124_OK;
386}
387
388
390 if (decomp != NULL) {
391 decomp->t = 0U;
392 bitvector_copy(&decomp->mask, &decomp->initial_mask);
393 bitvector_zero(&decomp->prev_output);
394 bitvector_zero(&decomp->Xt);
395
396 /* Reset diagnostics */
397 decomp->mask_inconsistent = 0U;
398 decomp->count_f_mismatch = 0U;
399
400 /* Reset accuracy guarantee tracking */
401 decomp->mask_synced = 0U;
402 decomp->received_status_count = 0U;
403 decomp->received_status_index = 0U;
404 (void)memset(decomp->received_status_ring, 0, sizeof(decomp->received_status_ring));
405 }
406}
407
408
411 uint32_t lost_count
412) {
413 if (decomp == NULL) {
415 }
416
417 if (lost_count == 0U) {
418 return CCSDS124_OK; /* No loss, nothing to do */
419 }
420
421 /*
422 * Advance the time index to account for lost packets.
423 * This is critical for synchronization with the compressor's time index.
424 *
425 * Note: After packet loss, the next packet should ideally have:
426 * - rt=1 (uncompressed) for full recovery, OR
427 * - ft=1 (full mask) for mask recovery
428 *
429 * If the loss count <= R (minimum robustness), the next packet's Xt
430 * window will contain all mask changes, allowing mask synchronization.
431 * However, prev_output will be stale unless the next packet is uncompressed.
432 */
433 decomp->t += lost_count;
434
435 /*
436 * Mark prev_output as potentially invalid.
437 * The next packet's data should be uncompressed (rt=1) for reliable recovery,
438 * or we accept that prediction-based decompression may fail.
439 *
440 * Per CCSDS 124.0-B-1 Section 3.3.2: "The uncompressed flag, rt, which
441 * shall be rt = 1 if t <= Rt" - this ensures the first R+1 packets are
442 * always uncompressed, providing natural synchronization points.
443 */
444
445 /* Packet loss breaks mask synchronization */
446 decomp->mask_synced = 0U;
447
448 /* Record 0x02 (lost) status entries in the ring buffer */
449 for (uint32_t i = 0U; i < lost_count; i++) {
450 decomp->received_status_ring[decomp->received_status_index] = 0x02U;
453 decomp->received_status_count++;
454 }
455 }
456
457 return CCSDS124_OK;
458}
459
/* End of Decompressor Initialization */
461
473typedef struct {
474 uint8_t Vt;
475 uint8_t ft;
476 uint8_t rt;
478
493 bitreader_t *reader,
494 bitvector_t *output,
496) {
497 if ((decomp == NULL) || (reader == NULL) || (output == NULL)) {
499 }
500
501 (void)bitvector_init(output, decomp->F);
502
503 /* Copy previous output as prediction base */
504 bitvector_copy(output, &decomp->prev_output);
505
506 /* Clear positive changes tracker */
507 bitvector_zero(&decomp->Xt);
508
509 /* ====================================================================
510 * Parse hₜ: Mask change information
511 * hₜ = RLE(Xₜ) ∥ BIT₄(Vₜ) ∥ eₜ ∥ kₜ ∥ cₜ ∥ ḋₜ
512 * ==================================================================== */
513
514 /* Decode RLE(Xₜ) - mask changes */
515 bitvector_t Xt;
516 int status = ccsds124_rle_decode(reader, &Xt, decomp->F);
517 if (status != CCSDS124_OK) {
518 return status;
519 }
520
521 /* Read BIT₄(Vₜ) - effective robustness */
522 if (bitreader_remaining(reader) < 4U) {
524 }
525 uint32_t vt_raw = bitreader_read_bits(reader, 4U);
526 uint8_t Vt = (uint8_t)(vt_raw & 0x0FU);
527
528 /* Process eₜ, kₜ, cₜ if Vₜ > 0 and there are changes */
529 int ct = 0;
530 size_t change_count = bitvector_hamming_weight(&Xt);
531
532 if ((Vt > 0U) && (change_count > 0U)) {
533 /* Read eₜ */
534 int et = bitreader_read_bit(reader);
535 if (et < 0) {
537 }
538
539 /* Pre-extract positions of set bits in Xt (word-level, much faster than bit-by-bit) */
540 size_t change_positions[CCSDS124_MAX_PACKET_LENGTH];
541 size_t num_changes = bitvector_get_set_positions(&Xt, change_positions, change_count);
542
543 if (et == 1) {
544 /* Read kₜ - determines positive/negative updates */
545 /* kₜ has one bit per change in Xt */
546 uint8_t kt_bits[CCSDS124_MAX_PACKET_LENGTH];
547
548 /* Read kt bits using pre-extracted positions */
549 if (bitreader_remaining(reader) < num_changes) {
551 }
552 for (size_t idx = 0U; idx < num_changes; idx++) {
553 int bit_val = bitreader_read_bit(reader);
554 if (bit_val < 0) {
556 }
557 kt_bits[idx] = (bit_val > 0) ? 1U : 0U;
558 }
559
560 /* Apply mask updates using pre-extracted positions */
561 for (size_t idx = 0U; idx < num_changes; idx++) {
562 size_t pos = change_positions[idx];
563 /* kt=1 means positive update (mask becomes 0) */
564 /* kt=0 means negative update (mask becomes 1) */
565 if (kt_bits[idx] != 0U) {
566 bitvector_set_bit(&decomp->mask, pos, 0);
567 bitvector_set_bit(&decomp->Xt, pos, 1); /* Track positive change */
568 } else {
569 bitvector_set_bit(&decomp->mask, pos, 1);
570 }
571 }
572
573 /* Read cₜ */
574 ct = bitreader_read_bit(reader);
575 if (ct < 0) {
577 }
578 } else {
579 /* et = 0: all updates are negative (mask bits become 1) */
580 for (size_t idx = 0U; idx < num_changes; idx++) {
581 bitvector_set_bit(&decomp->mask, change_positions[idx], 1);
582 }
583 }
584 } else if ((Vt == 0U) && (change_count > 0U)) {
585 /* Vt = 0: toggle mask bits at change positions */
586 /* Pre-extract positions of set bits in Xt */
587 size_t change_positions[CCSDS124_MAX_PACKET_LENGTH];
588 size_t num_changes = bitvector_get_set_positions(&Xt, change_positions, change_count);
589
590 for (size_t idx = 0U; idx < num_changes; idx++) {
591 size_t pos = change_positions[idx];
592 int current_val = bitvector_get_bit(&decomp->mask, pos);
593 int toggled = 0;
594 if (current_val == 0) {
595 toggled = 1;
596 }
597 bitvector_set_bit(&decomp->mask, pos, toggled);
598 }
599 } else {
600 /* No changes to apply (change_count == 0) */
601 }
602
603 /* Read ḋₜ */
604 int dt = bitreader_read_bit(reader);
605 if (dt < 0) {
607 }
608
609 /* ====================================================================
610 * Parse qₜ: Optional full mask
611 * ==================================================================== */
612
613 int ft = 0;
614 int rt = 0;
615
616 /* Reset diagnostics flags */
617 decomp->mask_inconsistent = 0U;
618 decomp->count_f_mismatch = 0U;
619
620 /* dt=1 means both ft=0 and rt=0 (optimization per CCSDS Eq. 13) */
621 /* dt=0 means we need to read ft and rt from the stream */
622
623 if (dt == 0) {
624 /* Read ft flag */
625 ft = bitreader_read_bit(reader);
626 if (ft < 0) {
628 }
629
630 if (ft == 1) {
631 /* Save delta-updated mask before full mask replacement (v1.11) */
632 bitvector_t delta_mask;
633 bitvector_copy(&delta_mask, &decomp->mask);
634
635 /* Full mask follows: decode RLE(M XOR (M<<)) */
636 bitvector_t mask_diff;
637 status = ccsds124_rle_decode(reader, &mask_diff, decomp->F);
638 if (status != CCSDS124_OK) {
639 return status;
640 }
641
642 /* Reverse the horizontal XOR to get the actual mask.
643 * HXOR encoding: HXOR[i] = M[i] XOR M[i+1], with HXOR[F-1] = M[F-1]
644 * Reversal: start from LSB (position F-1) and work towards MSB (position 0)
645 * M[F-1] = HXOR[F-1] (just copy)
646 * M[i] = HXOR[i] XOR M[i+1] for i < F-1
647 */
648
649 /* Copy LSB bit directly (position F-1 in bitvector) */
650 int current = bitvector_get_bit(&mask_diff, decomp->F - 1U);
651 bitvector_set_bit(&decomp->mask, decomp->F - 1U, current);
652
653 /* Process remaining bits from F-2 down to 0 */
654 for (size_t i = decomp->F - 1U; i > 0U; i--) {
655 size_t pos = i - 1U;
656 int hxor_bit = bitvector_get_bit(&mask_diff, pos);
657 /* M[pos] = HXOR[pos] XOR M[pos+1] = HXOR[pos] XOR current */
658 current = hxor_bit ^ current;
659 bitvector_set_bit(&decomp->mask, pos, current);
660 }
661
662 /* Check delta/full mask consistency (v1.11) */
663 if (bitvector_equals(&delta_mask, &decomp->mask) == 0) {
664 decomp->mask_inconsistent = 1U;
665 }
666
667 }
668
669 /* Read rt flag */
670 rt = bitreader_read_bit(reader);
671 if (rt < 0) {
673 }
674 }
675
676 /* Populate flags if requested */
677 if (flags != NULL) {
678 flags->Vt = Vt;
679 flags->ft = (ft != 0) ? 1U : 0U;
680 flags->rt = (rt != 0) ? 1U : 0U;
681 }
682
683 if (rt == 1) {
684 /* Full packet follows: COUNT(F) ∥ Iₜ */
685 uint32_t packet_length = 0U;
686 status = ccsds124_count_decode(reader, &packet_length);
687 if (status != CCSDS124_OK) {
688 return status;
689 }
690
691 /* Check COUNT(F) against expected packet length (diagnostic flag).
692 * A mismatch indicates corruption but we still attempt decompression
693 * so the harness can decide whether to accept or reject. */
694 if (packet_length != (uint32_t)decomp->F) {
695 decomp->count_f_mismatch = 1U;
696 }
697
698 /* Read full packet */
699 if (bitreader_remaining(reader) < decomp->F) {
701 }
702 for (size_t i = 0U; i < decomp->F; i++) {
703 int bit = bitreader_read_bit(reader);
704 if (bit < 0) {
706 }
707 bitvector_set_bit(output, i, bit);
708 }
709 } else {
710 /* Compressed: extract unpredictable bits */
711 bitvector_t extraction_mask;
712 (void)bitvector_init(&extraction_mask, decomp->F);
713
714 if ((ct == 1) && (Vt > 0U)) {
715 /* BE(Iₜ, (Xₜ OR Mₜ)) */
716 bitvector_or(&extraction_mask, &decomp->mask, &decomp->Xt);
717 } else {
718 /* BE(Iₜ, Mₜ) */
719 bitvector_copy(&extraction_mask, &decomp->mask);
720 }
721
722 /* Insert unpredictable bits */
723 status = ccsds124_bit_insert(reader, output, &extraction_mask);
724 if (status != CCSDS124_OK) {
725 return status;
726 }
727 }
728
729 /* ====================================================================
730 * Update state for next cycle
731 * ==================================================================== */
732
733 bitvector_copy(&decomp->prev_output, output);
734 decomp->t++;
735
736 return CCSDS124_OK;
737}
738
739
742 bitreader_t *reader,
743 bitvector_t *output
744) {
745 return ccsds124_decompress_packet_internal(decomp, reader, output, NULL);
746}
747
748
751 const uint8_t *data,
752 size_t num_bits,
753 bitvector_t *output,
755) {
756 if ((decomp == NULL) || (data == NULL) || (output == NULL)) {
758 }
759
760 if (num_bits == 0U) {
762 }
763
764 /* Save decompressor state before attempting decompression.
765 * Per cross-validation v1.9: restore state if packet is invalid
766 * to avoid propagating errors to subsequent packets. */
767 ccsds124_decompressor_t saved_decomp;
768 (void)memcpy(&saved_decomp, decomp, sizeof(*decomp));
769
770 /* Create bit reader and decompress with flag extraction */
771 bitreader_t reader;
772 bitreader_init(&reader, data, num_bits);
773
775 int rc = ccsds124_decompress_packet_internal(decomp, &reader, output, &flags);
776
777 /* Validate: only padding bits should remain (at most 7) (v1.10).
778 * Reference packets (rt=1) are exempt: they are self-delimiting via
779 * COUNT(F), and per the cross-validation rules a Received Packet
780 * Length larger than the bits actually needed means the remainder is
781 * simply ignored. */
782 if ((rc == CCSDS124_OK) && (flags.rt == 0U) &&
783 (bitreader_remaining(&reader) >= 8U)) {
785 }
786
787 if (rc != CCSDS124_OK) {
788 /* Decompression failed: restore state */
789 (void)memcpy(decomp, &saved_decomp, sizeof(*decomp));
790 decomp->mask_synced = 0U;
791
792 /* Record 0x01 in status ring */
793 decomp->received_status_ring[decomp->received_status_index] = 0x01U;
796 decomp->received_status_count++;
797 }
798
799 if (result != NULL) {
800 result->status = 0x01U;
801 result->Vt = 0U;
802 result->ft = 0U;
803 result->rt = 0U;
804 }
805 return rc;
806 }
807
808 /* Decompression succeeded — evaluate accuracy guarantee decision tree */
809 uint8_t mask_inconsistent_detected = ((decomp->mask_synced != 0U) &&
810 (decomp->mask_inconsistent != 0U)) ? 1U : 0U;
811 uint8_t count_f_mismatch_detected = (decomp->count_f_mismatch != 0U) ? 1U : 0U;
812
813 uint8_t guaranteed;
814 if (mask_inconsistent_detected != 0U) {
815 guaranteed = 0U;
816 } else if (count_f_mismatch_detected != 0U) {
817 guaranteed = 0U;
818 } else if (flags.rt == 1U) {
819 /* Reference packet: guaranteed if mask is synced or ft=1 resynchronizes */
820 if ((decomp->mask_synced != 0U) || (flags.ft == 1U)) {
821 guaranteed = 1U;
822 } else {
823 guaranteed = 0U;
824 }
825 } else {
826 /* Non-reference packet: check preceding Vt received packets.
827 * Skip lost packets (0x02) in the window. */
828 guaranteed = 1U;
829 if (flags.Vt > 0U) {
830 size_t checked = 0U;
831 /* Walk backwards through the ring buffer (before current entry) */
832 size_t ring_walk = decomp->received_status_count;
834
835 while ((checked < (size_t)flags.Vt) && (ring_walk > 0U)) {
836 uint8_t st = decomp->received_status_ring[idx];
837 if (st == 0x02U) {
838 /* Skip lost packets */
840 ring_walk--;
841 continue;
842 }
843 if (st != 0x00U) {
844 guaranteed = 0U;
845 break;
846 }
847 checked++;
849 ring_walk--;
850 }
851 /* If we checked fewer than Vt received packets because history
852 * is too short, trust the guarantee (early packets are reliable). */
853 }
854 }
855
856 /* Apply state decisions based on guarantee result */
857 uint8_t out_status;
858 int ret;
859
860 if (guaranteed != 0U) {
861 out_status = 0x00U;
862 ret = CCSDS124_OK;
863
864 /* ft=1 resynchronizes the mask */
865 if (flags.ft == 1U) {
866 decomp->mask_synced = 1U;
867 }
868 } else if (mask_inconsistent_detected != 0U) {
869 /* Mask inconsistency while synced: restore state, clear sync */
870 (void)memcpy(decomp, &saved_decomp, sizeof(*decomp));
871 decomp->mask_synced = 0U;
872 out_status = 0x01U;
874 } else if (count_f_mismatch_detected != 0U) {
875 /* COUNT(F) mismatch: keep state (ft=1 still syncs mask) */
876 out_status = 0x01U;
878 if (flags.ft == 1U) {
879 decomp->mask_synced = 1U;
880 }
881 } else {
882 /* Unguaranteed for other reasons: restore state, clear sync */
883 (void)memcpy(decomp, &saved_decomp, sizeof(*decomp));
884 decomp->mask_synced = 0U;
885 out_status = 0x01U;
887 }
888
889 /* Record status in ring buffer */
890 decomp->received_status_ring[decomp->received_status_index] = out_status;
893 decomp->received_status_count++;
894 }
895
896 /* Populate result struct if requested */
897 if (result != NULL) {
898 result->status = out_status;
899 result->Vt = flags.Vt;
900 result->ft = flags.ft;
901 result->rt = flags.rt;
902 }
903
904 return ret;
905}
906
907
932static int skip_rle_sequence_span(bitreader_t *reader, uint32_t *hamming_weight,
933 uint64_t *span) {
934 uint32_t hw = 0U;
935 uint64_t total = 0U;
936 uint32_t count_val = 0U;
937 int rc = ccsds124_count_decode(reader, &count_val);
938
939 while ((rc == CCSDS124_OK) && (count_val != 0U)) {
940 hw++;
941 total += (uint64_t)count_val;
942 rc = ccsds124_count_decode(reader, &count_val);
943 }
944
945 if (rc == CCSDS124_OK) {
946 *hamming_weight = hw;
947 *span = total;
948 }
949
950 return rc;
951}
952
953
955 const uint8_t *data,
956 size_t num_bits,
957 uint32_t *packet_length
958) {
959 if ((data == NULL) || (packet_length == NULL)) {
961 }
962
963 if (num_bits == 0U) {
965 }
966
967 /* Default: not discoverable from this packet */
968 *packet_length = 0U;
969
970 bitreader_t reader;
971 bitreader_init(&reader, data, num_bits);
972
973 /* 1. Skip RLE(Xt) — self-delimiting, doesn't need F */
974 uint32_t H_Xt = 0U;
975 uint64_t Xt_span = 0U;
976 if (skip_rle_sequence_span(&reader, &H_Xt, &Xt_span) != CCSDS124_OK) {
977 return CCSDS124_OK; /* Parse error — not discoverable */
978 }
979
980 /* 2. BIT4(Vt) — 4 bits */
981 if (bitreader_remaining(&reader) < 4U) {
982 return CCSDS124_OK;
983 }
984 uint32_t Vt = bitreader_read_bits(&reader, 4U);
985
986 /* 3. If H(Xt) > 0 and Vt > 0: read et, then kt+ct only if et==1 */
987 if ((H_Xt > 0U) && (Vt > 0U)) {
988 int et = bitreader_read_bit(&reader);
989 if (et < 0) {
990 return CCSDS124_OK;
991 }
992 if (et == 1) {
993 /* kt: H(Xt) bits — skip them */
994 if (bitreader_remaining(&reader) < (size_t)H_Xt) {
995 return CCSDS124_OK;
996 }
997 for (uint32_t i = 0U; i < H_Xt; i++) {
998 (void)bitreader_read_bit(&reader);
999 }
1000 /* ct: 1 bit */
1001 if (bitreader_read_bit(&reader) < 0) {
1002 return CCSDS124_OK;
1003 }
1004 }
1005 /* et==0: all changes are negative — no kt or ct in bitstream */
1006 }
1007 /* If H(Xt) > 0 and Vt == 0: no et/kt/ct (toggle mode) */
1008
1009 /* 4. dt — 1 bit */
1010 int dt = bitreader_read_bit(&reader);
1011 if (dt < 0) {
1012 return CCSDS124_OK;
1013 }
1014
1015 if (dt == 1) {
1016 /* dt=1 means ft=0 and rt=0 — can't discover F */
1017 return CCSDS124_OK;
1018 }
1019
1020 /* 5. dt=0: read ft flag */
1021 int ft = bitreader_read_bit(&reader);
1022 if (ft < 0) {
1023 return CCSDS124_OK;
1024 }
1025
1026 uint64_t mask_span = 0U;
1027 if (ft == 1) {
1028 /* Full mask follows as RLE — skip it */
1029 uint32_t mask_hw = 0U;
1030 if (skip_rle_sequence_span(&reader, &mask_hw, &mask_span) != CCSDS124_OK) {
1031 return CCSDS124_OK;
1032 }
1033 }
1034
1035 /* Read rt flag */
1036 int rt = bitreader_read_bit(&reader);
1037 if (rt < 0) {
1038 return CCSDS124_OK;
1039 }
1040
1041 if (rt != 1) {
1042 /* Not a reference packet — can't discover F */
1043 return CCSDS124_OK;
1044 }
1045
1046 /* 6. rt=1: read COUNT(F) */
1047 uint32_t discovered_F = 0U;
1048 int rc = ccsds124_count_decode(&reader, &discovered_F);
1049 if ((rc != CCSDS124_OK) || (discovered_F == 0U)) {
1050 return CCSDS124_OK;
1051 }
1052
1053 /* Validity (cross-validation rule v1.6): the signaled length must be
1054 * within the standard's range (1..65535), and the packet's own h and q
1055 * vectors must be consistent with it — an RLE span exceeding F encodes
1056 * positions beyond the packet, making the signaled length
1057 * untrustworthy. */
1058 if ((discovered_F > 65535U) ||
1059 (Xt_span > (uint64_t)discovered_F) ||
1060 (mask_span > (uint64_t)discovered_F)) {
1061 return CCSDS124_OK;
1062 }
1063
1064 /* Truncated reference packet: the bitstream ran out after COUNT(F) but
1065 * before the full I_t. Per the cross-validation rules the signaled
1066 * length is still to be considered ("stored as the actual packet length
1067 * if it is valid and was not known before"), but it is weaker evidence
1068 * than a fully-validated reference packet — report it distinctly so
1069 * callers can prefer a strict discovery elsewhere in the stream. */
1070 if (bitreader_remaining(&reader) < (size_t)discovered_F) {
1071 *packet_length = discovered_F;
1073 }
1074
1075 /* Excess bits after I_t are ignored: reference packets are
1076 * self-delimiting via COUNT(F), and a Received Packet Length larger
1077 * than the bits actually needed means the remainder is ignored. */
1078 *packet_length = discovered_F;
1079 return CCSDS124_OK;
1080}
1081
1082
1085 const uint8_t *input_data,
1086 size_t input_size,
1087 uint8_t *output_buffer,
1088 size_t output_buffer_size,
1089 size_t *output_size
1090) {
1091 if ((decomp == NULL) || (input_data == NULL) ||
1092 (output_buffer == NULL) || (output_size == NULL)) {
1094 }
1095
1096 /* Reset decompressor */
1098
1099 /* Initialize bit reader */
1100 bitreader_t reader;
1101 bitreader_init(&reader, input_data, input_size * 8U);
1102
1103 /* Output packet size in bytes */
1104 size_t packet_bytes = (decomp->F + 7U) / 8U;
1105 size_t total_output = 0U;
1106
1107 /* Decompress packets until input exhausted */
1108 while (bitreader_remaining(&reader) > 0U) {
1109 bitvector_t output;
1110 int status = ccsds124_decompress_packet(decomp, &reader, &output);
1111 if (status != CCSDS124_OK) {
1112 return status;
1113 }
1114
1115 /* Check output buffer space */
1116 if ((total_output + packet_bytes) > output_buffer_size) {
1118 }
1119
1120 /* Copy to output buffer */
1121 (void)bitvector_to_bytes(&output, &output_buffer[total_output], packet_bytes);
1122 total_output += packet_bytes;
1123
1124 /* Align to byte boundary for next packet */
1125 bitreader_align_byte(&reader);
1126 }
1127
1128 *output_size = total_output;
1129 return CCSDS124_OK;
1130}
1131
/* End of Packet Decompression */
CCSDS 124.0-B-1 Compression Library - Public API.
static int ccsds124_decompress_packet_internal(ccsds124_decompressor_t *decomp, bitreader_t *reader, bitvector_t *output, ccsds124_decompress_flags_t *flags)
Internal decompression with optional flag extraction.
Definition decompress.c:491
static int skip_rle_sequence_span(bitreader_t *reader, uint32_t *hamming_weight, uint64_t *span)
Skip COUNT values in an RLE sequence until the terminator.
Definition decompress.c:932
static size_t bitvector_get_set_positions(const bitvector_t *bv, size_t *positions, size_t max_pos)
Extract positions of all set bits in a bitvector using word-level processing.
Definition decompress.c:48
size_t bitreader_position(const bitreader_t *reader)
Get current bit position.
Definition decompress.c:136
void bitreader_align_byte(bitreader_t *reader)
Skip to next byte boundary.
Definition decompress.c:158
int bitreader_read_bit(bitreader_t *reader)
Read a single bit.
Definition decompress.c:97
uint32_t bitreader_read_bits(bitreader_t *reader, size_t num_bits)
Read multiple bits as unsigned value.
Definition decompress.c:115
size_t bitreader_remaining(const bitreader_t *reader)
Get remaining bits.
Definition decompress.c:147
void bitreader_init(bitreader_t *reader, const uint8_t *data, size_t num_bits)
Initialize bit reader.
Definition decompress.c:88
void bitvector_copy(bitvector_t *dest, const bitvector_t *src)
Copy bit vector contents.
Definition bitvector.c:72
int bitvector_to_bytes(const bitvector_t *bv, uint8_t *data, size_t num_bytes)
Store bit vector to byte array.
Definition bitvector.c:311
size_t bitvector_hamming_weight(const bitvector_t *bv)
Count number of set bits (Hamming weight).
Definition bitvector.c:222
static void bitvector_set_bit(bitvector_t *bv, size_t pos, int value)
Set bit value at position (inline for performance).
Definition ccsds124.h:188
int bitvector_init(bitvector_t *bv, size_t num_bits)
Initialize a bit vector with specified length.
Definition bitvector.c:44
static int bitvector_get_bit(const bitvector_t *bv, size_t pos)
Get bit value at position (inline for performance).
Definition ccsds124.h:169
int bitvector_equals(const bitvector_t *a, const bitvector_t *b)
Compare two bit vectors for equality.
Definition bitvector.c:247
void bitvector_zero(bitvector_t *bv)
Set all bits to zero.
Definition bitvector.c:65
void bitvector_or(bitvector_t *result, const bitvector_t *a, const bitvector_t *b)
Bitwise OR operation.
Definition bitvector.c:110
#define CCSDS124_MAX_VT_HISTORY
Definition ccsds124.h:72
#define CCSDS124_MAX_PACKET_LENGTH
Definition ccsds124.h:66
#define CCSDS124_MAX_ROBUSTNESS
Definition ccsds124.h:70
int ccsds124_rle_decode(bitreader_t *reader, bitvector_t *result, size_t length)
Run-length decoding (inverse of ccsds124_rle_encode).
Definition decompress.c:251
int ccsds124_count_decode(bitreader_t *reader, uint32_t *value)
Counter decoding (inverse of ccsds124_count_encode).
Definition decompress.c:175
int ccsds124_bit_insert(bitreader_t *reader, bitvector_t *data, const bitvector_t *mask)
Bit insertion (inverse of ccsds124_bit_extract).
Definition decompress.c:287
int ccsds124_decompress_packet(ccsds124_decompressor_t *decomp, bitreader_t *reader, bitvector_t *output)
Decompress a single compressed packet.
Definition decompress.c:740
void ccsds124_decompressor_reset(ccsds124_decompressor_t *decomp)
Reset decompressor to initial state.
Definition decompress.c:389
int ccsds124_decompress_packet_checked(ccsds124_decompressor_t *decomp, const uint8_t *data, size_t num_bits, bitvector_t *output, ccsds124_decompress_result_t *result)
Decompress a single packet with accuracy guarantee checking.
Definition decompress.c:749
int ccsds124_decompress(ccsds124_decompressor_t *decomp, const uint8_t *input_data, size_t input_size, uint8_t *output_buffer, size_t output_buffer_size, size_t *output_size)
Decompress entire compressed data stream.
int ccsds124_discover_packet_length(const uint8_t *data, size_t num_bits, uint32_t *packet_length)
Discover packet length (F) from a compressed packet.
Definition decompress.c:954
int ccsds124_decompressor_notify_packet_loss(ccsds124_decompressor_t *decomp, uint32_t lost_count)
Notify decompressor of packet loss.
Definition decompress.c:409
int ccsds124_decompressor_init(ccsds124_decompressor_t *decomp, size_t F, const bitvector_t *initial_mask, uint8_t robustness)
Initialize decompressor state.
Definition decompress.c:335
#define CCSDS124_ERROR_OVERFLOW
Definition ccsds124.h:49
#define CCSDS124_ERROR_INVALID_ARG
Definition ccsds124.h:48
#define CCSDS124_OK
Definition ccsds124.h:47
#define CCSDS124_ERROR_UNDERFLOW
Definition ccsds124.h:50
#define CCSDS124_STATUS_TRUNCATED_LENGTH
Definition ccsds124.h:58
#define CCSDS124_STATUS_UNGUARANTEED
Definition ccsds124.h:57
Bit reader structure for sequential reading.
Definition ccsds124.h:748
const uint8_t * data
Definition ccsds124.h:749
size_t bit_pos
Definition ccsds124.h:751
size_t num_bits
Definition ccsds124.h:750
Fixed-length bit vector structure.
Definition ccsds124.h:133
size_t num_words
Definition ccsds124.h:136
size_t length
Definition ccsds124.h:135
uint32_t data[((CCSDS124_MAX_PACKET_BYTES)+3U)/4U]
Definition ccsds124.h:134
Internal flags extracted during decompression.
Definition decompress.c:473
Decompression result with accuracy guarantee status.
Definition ccsds124.h:107
Decompressor state structure.
Definition ccsds124.h:872
uint8_t mask_inconsistent
Definition ccsds124.h:894
uint8_t received_status_index
Definition ccsds124.h:903
bitvector_t prev_output
Definition ccsds124.h:883
uint8_t received_status_ring[CCSDS124_MAX_VT_HISTORY]
Definition ccsds124.h:901
uint8_t received_status_count
Definition ccsds124.h:902
bitvector_t initial_mask
Definition ccsds124.h:876