Skip to content
Snippets Groups Projects
interleaver.rs 3.56 KiB
Newer Older
Stephen D's avatar
Stephen D committed
use bitvec::prelude::*;
Stephen D's avatar
Stephen D committed
use labrador_ldpc::decoder::DecodeFrom;
Stephen D's avatar
Stephen D committed

use crate::{
    buffer::{Buffer, BufferOverflow},
    error::EncodeError,
};

pub(crate) fn interleave<const N: usize>(
    data: &[u8],
    out: &mut Buffer<N>,
) -> Result<(), EncodeError> {
Stephen D's avatar
Stephen D committed
    let bv = data.view_bits::<Msb0>();

    let initial_length = out.len();
Stephen D's avatar
Stephen D committed
    for _ in 0..data.len() {
        out.try_push(0).map_err(|_| EncodeError::CatsOverflow)?;
Stephen D's avatar
Stephen D committed
    }
    let bv_out = out[initial_length..].view_bits_mut::<Msb0>();
Stephen D's avatar
Stephen D committed

    let mut out_i = 0;
    for i in 0..32 {
        for j in (0..bv.len()).step_by(32) {
            if i + j >= bv.len() {
                continue;
            }

            bv_out.set(out_i, bv[i + j]);

            out_i += 1;
        }
    }

Stephen D's avatar
Stephen D committed
}

Stephen D's avatar
Stephen D committed
pub(crate) fn uninterleave<const N: usize>(
    data: &[u8],
    out: &mut Buffer<N>,
) -> Result<(), BufferOverflow> {
Stephen D's avatar
Stephen D committed
    let bv = data.view_bits::<Msb0>();

    for _ in 0..data.len() {
Stephen D's avatar
Stephen D committed
        out.try_push(0)?;
Stephen D's avatar
Stephen D committed
    }
    let bv_out = out.view_bits_mut::<Msb0>();

    let mut out_i = 0;
    for i in 0..32 {
        for j in (0..bv.len()).step_by(32) {
            if i + j >= bv.len() {
                continue;
            }

            bv_out.set(i + j, bv[out_i]);

            out_i += 1;
        }
    }

Stephen D's avatar
Stephen D committed
}

Stephen D's avatar
Stephen D committed
pub(crate) fn uninterleave_soft<const N: usize, T: DecodeFrom>(
    data: &[T],
    out: &mut Buffer<N, T>,
) -> Result<(), BufferOverflow> {
    for _ in 0..data.len() {
        out.try_push(T::zero())?;
    }

    let mut out_i = 0;
    for i in 0..32 {
        for j in (0..data.len()).step_by(32) {
            if i + j >= data.len() {
                continue;
            }

            out[i + j] = data[out_i];

            out_i += 1;
        }
    }

    Ok(())
}

Stephen D's avatar
Stephen D committed
#[cfg(test)]
mod tests {
    use super::*;
    use crate::soft_bit::FromHardBit;
Stephen D's avatar
Stephen D committed

    #[test]
    fn interleaver_works() {
        let mut data = [0x84, 0x73, 0x12, 0xA3, 0xFF, 0x00, 0xC2, 0x1B, 0x77];
        let orig = Buffer::new_full(&mut data);

        let mut interleaved = [0; 10];
        let mut interleaved = Buffer::new(&mut interleaved, 0);
        interleaved.push(b'H');
        interleave(&orig, &mut interleaved).unwrap();
Stephen D's avatar
Stephen D committed

        let expected = [b'H', 0xCD, 0xB5, 0xDB, 0x2A, 0x0A, 0x52, 0x0C, 0x89, 0x4F];
Stephen D's avatar
Stephen D committed
        assert_eq!(expected, interleaved[..]);

        let mut uninterleaved = [0; 10];
        let mut uninterleaved = Buffer::new(&mut uninterleaved, 0);
        uninterleave(&interleaved[1..], &mut uninterleaved).unwrap();
Stephen D's avatar
Stephen D committed

        assert_eq!(*orig, *uninterleaved);
Stephen D's avatar
Stephen D committed
    }
Stephen D's avatar
Stephen D committed

    #[test]
    fn hard_interleave_soft_uninterleave() {
        let mut data = [0x84, 0x73, 0x12, 0xA3, 0xFF, 0x00, 0xC2, 0x1B, 0x77];
        let orig = Buffer::new_full(&mut data);

        let mut interleaved = [0; 10];
        let mut interleaved = Buffer::new(&mut interleaved, 0);
        interleaved.push(b'H');

        interleave(&orig, &mut interleaved).unwrap();

        let mut soft_interleaved = [0.0; 10 * 8];
        for (i, b) in interleaved.iter().enumerate() {
            for j in 0..8 {
                soft_interleaved[8 * i + j] = f32::from_hard_bit(b & (1 << (7 - j)) > 0);
            }
        }

        let mut uninterleaved = [0.0; 10 * 8];
        let mut uninterleaved = Buffer::new(&mut uninterleaved, 0);
        uninterleave_soft(&soft_interleaved[8..], &mut uninterleaved).unwrap();

        assert_eq!(orig.len() * 8, uninterleaved.len());
        for (i, b) in orig.iter().enumerate() {
            for j in 0..8 {
                assert_eq!(uninterleaved[8 * i + j].hard_bit(), *b & (1 << (7 - j)) > 0);
            }
        }
    }
Stephen D's avatar
Stephen D committed
}