use viterbi::encoder::ViterbiEncoder;
use viterbi::params::CodeParams;
const TAIL_BITS: usize = 6;
const G1: u32 = 0o171;
const G2: u32 = 0o133;
#[test]
fn encoder_matches_traced_ccsds_impulse() {
let enc = ViterbiEncoder::new(CodeParams::ccsds_r1_2()).unwrap();
assert_eq!(
enc.encode_bits(&[0x80], 1).unwrap(),
viterbi::packing::CodedBlock {
bytes: vec![0xBA, 0x48],
nbits: 14,
}
);
assert_eq!(enc.encode(&[0x00]).unwrap().nbits, 28);
}
fn naive_ccsds_encode(data: &[u8], nbits: usize) -> Vec<u8> {
let mut reg: u32 = 0; let mut bits: Vec<u8> = Vec::new();
let step = |input: u8, bits: &mut Vec<u8>, reg: &mut u32| {
let g = ((input as u32) << 6) | *reg;
bits.push(((g & G1).count_ones() & 1) as u8);
bits.push((((g & G2).count_ones() & 1) ^ 1) as u8); *reg = (g >> 1) & 0x3F;
};
for i in 0..nbits {
step((data[i / 8] >> (7 - (i % 8))) & 1, &mut bits, &mut reg);
}
for _ in 0..TAIL_BITS {
step(0, &mut bits, &mut reg); }
let mut out = vec![0u8; bits.len().div_ceil(8)];
for (i, &b) in bits.iter().enumerate() {
if b == 1 {
out[i / 8] |= 1 << (7 - (i % 8));
}
}
out
}
#[test]
fn encoder_matches_independent_oracle() {
let enc = ViterbiEncoder::new(CodeParams::ccsds_r1_2()).unwrap();
for data in [
&[0x00u8][..],
&[0xFF],
&[0x80],
&[0x01, 0x23, 0x45, 0x67],
b"CCSDS",
] {
assert_eq!(
enc.encode(data).unwrap().bytes,
naive_ccsds_encode(data, data.len() * 8),
"production encoder must match the independent oracle for {data:?}"
);
}
}