27#ifndef CCSDS124_COMPRESSOR_HPP
28#define CCSDS124_COMPRESSOR_HPP
58template <std::
size_t N, std::
size_t MaxOutputBytes = N * 6>
class Compressor {
69 int rt_limit = 0) noexcept
74 pt_counter_(pt_limit),
75 ft_counter_(ft_limit),
76 rt_counter_(rt_limit) {
86 initial_mask_ = initial_mask;
99 flag_history_index_ = 0;
102 mask_ = initial_mask_;
109 change_history_[i].zero();
110 change_weight_history_[i] = 0;
115 new_mask_flag_history_[i] = 0;
119 pt_counter_ = pt_limit_;
120 ft_counter_ = ft_limit_;
121 rt_counter_ = rt_limit_;
133 template <std::
size_t OutputSize>
138 if (params !=
nullptr) {
139 effective_params = *params;
157 work_prev_build_ = build_;
163 update_mask(mask_, input, prev_input_, work_prev_build_,
171 change_history_[history_index_] = work_change_;
172 change_weight_history_[history_index_] = work_change_.hamming_weight();
180 compute_robustness_window(work_Xt_, work_change_);
183 std::uint8_t Vt = compute_effective_robustness();
186 bool ct = compute_ct_flag(Vt, effective_params.
new_mask_flag);
197 auto rle_result =
rle_encode(output, work_Xt_);
207 std::size_t xt_weight = work_Xt_.hamming_weight();
210 if (Vt > 0 && xt_weight > 0) {
212 bool et = has_positive_updates(work_Xt_, mask_);
221 work_inverted_.not_of(mask_);
235 auto dt_result = output.
append_bit(dt ? 1 : 0);
251 work_shifted_.left_shift(mask_);
252 work_diff_.xor_with(mask_, work_shifted_);
254 auto rle_mask_result =
rle_encode(output, work_diff_);
256 return rle_mask_result;
274 auto count_result =
count_encode(output,
static_cast<std::uint32_t
>(N));
280 return append_result;
292 work_diff_.or_with(mask_, work_Xt_);
293 auto be_result =
bit_extract(output, input, work_diff_);
298 auto be_result =
bit_extract(output, input, mask_);
312 new_mask_flag_history_[flag_history_index_] = effective_params.
new_mask_flag ? 1 : 0;
313 flag_history_index_ = (flag_history_index_ + 1) & (
MAX_VT_HISTORY - 1);
319 history_index_ = (history_index_ + 1) & (
MAX_HISTORY - 1);
355 if (pt_limit_ > 0 && ft_limit_ > 0 && rt_limit_ > 0) {
356 if (packet_index == 0) {
364 if (ft_counter_ == 1) {
366 ft_counter_ = ft_limit_;
373 if (pt_counter_ == 1) {
375 pt_counter_ = pt_limit_;
382 if (rt_counter_ == 1) {
384 rt_counter_ = rt_limit_;
392 if (packet_index <=
static_cast<std::size_t
>(robustness_)) {
410 if (robustness_ == 0 || t_ == 0) {
418 std::size_t num_changes = (t_ < robustness_) ? t_ : robustness_;
419 constexpr std::size_t history_mask =
MAX_HISTORY - 1;
422 for (std::size_t i = 1; i <= num_changes; ++i) {
423 std::size_t hist_idx = (history_index_ +
MAX_HISTORY - i) & history_mask;
424 Xt.or_in_place(change_history_[hist_idx]);
434 std::uint8_t compute_effective_robustness() const noexcept {
436 if (t_ <= robustness_) [[likely]] {
441 std::uint8_t Vt = robustness_;
442 constexpr std::uint8_t max_Vt = 15;
443 constexpr std::size_t history_mask =
MAX_HISTORY - 1;
444 const std::size_t max_check = (t_ < 15) ? t_ : 15;
446 for (std::size_t i = robustness_ + 1; i <= max_check; ++i) {
447 std::size_t hist_idx = (history_index_ +
MAX_HISTORY - i) & history_mask;
449 if (change_weight_history_[hist_idx] > 0) {
466 static bool has_positive_updates(
const BitVector<N>& Xt,
const BitVector<N>&
mask)
noexcept {
468 for (std::size_t w = 0; w < BitVector<N>::NUM_WORDS; ++w) {
469 if ((Xt.data()[w] & ~
mask.data()[w]) != 0) {
481 bool compute_ct_flag(std::uint8_t Vt,
bool current_new_mask_flag)
const noexcept {
489 if (current_new_mask_flag) {
494 std::size_t iterations_to_check = (Vt <= t_) ? Vt : t_;
497 for (std::size_t i = 0; i < iterations_to_check; ++i) {
498 std::size_t hist_idx = (flag_history_index_ +
MAX_VT_HISTORY - 1 - i) & vt_history_mask;
499 if (new_mask_flag_history_[hist_idx] != 0) {
508 std::uint8_t robustness_;
514 BitVector<N> initial_mask_;
516 BitVector<N> prev_mask_;
518 BitVector<N> prev_input_;
520 std::size_t history_index_ = 0;
524 std::size_t flag_history_index_ = 0;
528 std::size_t change_weight_history_[
MAX_HISTORY] = {0};
539 BitVector<N> work_prev_build_;
540 BitVector<N> work_change_;
541 BitVector<N> work_Xt_;
542 BitVector<N> work_inverted_;
543 BitVector<N> work_shifted_;
544 BitVector<N> work_diff_;
Variable-length bit buffer for building compressed output.
Fixed-length bit vector with static allocation.
Variable-length bit buffer with static allocation.
void clear() noexcept
Clear buffer to empty state.
Error append_bit(int bit) noexcept
Append a single bit.
Error append_bitvector(const BitVector< N > &bv, std::size_t num_bits) noexcept
Append bits from a BitVector.
Error append_value(std::uint32_t value, std::size_t num_bits) noexcept
Append multiple bits from a value.
Fixed-length bit vector with compile-time size.
CCSDS 124.0-B-1 compressor with static memory allocation.
std::size_t time_index() const noexcept
Get current time index.
std::uint8_t robustness() const noexcept
Get robustness level.
const BitVector< N > & mask() const noexcept
Get current mask.
CompressParams compute_auto_params(std::size_t packet_index) noexcept
Compute parameters for automatic mode.
void reset() noexcept
Reset compressor to initial state.
Error compress_packet(const BitVector< N > &input, BitBuffer< OutputSize > &output, const CompressParams *params=nullptr) noexcept
Compress a single input packet.
Compressor(std::uint8_t robustness=0, int pt_limit=0, int ft_limit=0, int rt_limit=0) noexcept
Construct compressor with configuration.
void set_initial_mask(const BitVector< N > &initial_mask) noexcept
Set the initial mask.
CCSDS 124.0-B-1 compile-time configuration.
CCSDS 124.0-B-1 encoding functions (COUNT, RLE, BE).
CCSDS 124.0-B-1 error handling.
constexpr std::size_t MAX_ROBUSTNESS
constexpr std::size_t MAX_VT_HISTORY
constexpr std::size_t MAX_HISTORY
CCSDS 124.0-B-1 mask update logic.
Error count_encode(BitBuffer< MaxBytes > &output, std::uint32_t A) noexcept
Counter encoding (CCSDS Section 5.2.2, Equation 9).
Error bit_extract(BitBuffer< MaxBytes > &output, const BitVector< N > &data, const BitVector< N > &mask) noexcept
Bit extraction in reverse order (CCSDS Section 5.2.4, Equation 11).
Error
Error codes for error-code-based error handling.
void compute_change(BitVector< N > &change, const BitVector< N > &mask, const BitVector< N > &prev_mask, std::size_t t) noexcept
Compute change vector (CCSDS Equation 8).
Error bit_extract_forward(BitBuffer< MaxBytes > &output, const BitVector< N > &data, const BitVector< N > &mask) noexcept
Bit extraction in forward order.
void update_mask(BitVector< N > &mask, const BitVector< N > &input, const BitVector< N > &prev_input, const BitVector< N > &build_prev, bool new_mask_flag) noexcept
Update mask vector (CCSDS Equation 7).
Error rle_encode(BitBuffer< MaxBytes > &output, const BitVector< N > &input) noexcept
Run-length encoding (CCSDS Section 5.2.3, Equation 10).
void update_build(BitVector< N > &build, const BitVector< N > &input, const BitVector< N > &prev_input, bool new_mask_flag, std::size_t t) noexcept
Update build vector (CCSDS Equation 6).
Compression parameters for a single packet.
bool new_mask_flag
p_t: Update mask from build vector
bool uncompressed_flag
r_t: Send uncompressed
bool send_mask_flag
f_t: Include mask in output
std::uint8_t min_robustness
R_t: Minimum robustness level (0-7)