#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BlockInterleaver {
rows: usize,
cols: usize,
}
impl BlockInterleaver {
pub fn new(rows: usize, cols: usize) -> Self {
assert!(
rows > 0 && cols > 0,
"interleaver dimensions must be nonzero"
);
Self { rows, cols }
}
#[inline]
pub fn block_len(&self) -> usize {
self.rows * self.cols
}
pub fn rows(&self) -> usize {
self.rows
}
pub fn cols(&self) -> usize {
self.cols
}
pub fn interleave<T: Copy>(&self, input: &[T], output: &mut [T]) {
let n = self.block_len();
assert_eq!(input.len(), n, "interleave input must be one full block");
assert_eq!(output.len(), n, "interleave output must be one full block");
for r in 0..self.rows {
for c in 0..self.cols {
output[c * self.rows + r] = input[r * self.cols + c];
}
}
}
pub fn deinterleave<T: Copy>(&self, input: &[T], output: &mut [T]) {
let n = self.block_len();
assert_eq!(input.len(), n, "deinterleave input must be one full block");
assert_eq!(
output.len(),
n,
"deinterleave output must be one full block"
);
for r in 0..self.rows {
for c in 0..self.cols {
output[r * self.cols + c] = input[c * self.rows + r];
}
}
}
}
use std::collections::VecDeque;
#[inline]
pub const fn conv_roundtrip_delay(branches: usize, depth: usize) -> usize {
branches * (branches - 1) * depth
}
#[derive(Debug, Clone)]
pub struct ConvInterleaver {
branches: usize,
depth: usize,
fifos: Vec<VecDeque<u8>>,
pos: usize,
}
impl ConvInterleaver {
pub fn new(branches: usize, depth: usize) -> Self {
assert!(
branches > 0 && depth > 0,
"convolutional interleaver dimensions must be nonzero"
);
Self {
branches,
depth,
fifos: (0..branches)
.map(|j| VecDeque::from(vec![0u8; j * depth]))
.collect(),
pos: 0,
}
}
pub fn dvbt() -> Self {
Self::new(12, 17)
}
pub fn branches(&self) -> usize {
self.branches
}
pub fn depth(&self) -> usize {
self.depth
}
pub fn roundtrip_delay(&self) -> usize {
conv_roundtrip_delay(self.branches, self.depth)
}
pub fn reset(&mut self) {
for (j, fifo) in self.fifos.iter_mut().enumerate() {
fifo.clear();
fifo.extend(std::iter::repeat_n(0u8, j * self.depth));
}
self.pos = 0;
}
pub fn feed(&mut self, data: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(data.len());
for &b in data {
let j = self.pos % self.branches;
if j == 0 {
out.push(b);
} else {
self.fifos[j].push_back(b);
out.push(self.fifos[j].pop_front().unwrap());
}
self.pos += 1;
}
out
}
pub fn flush(&mut self) -> Vec<u8> {
let d = self.roundtrip_delay();
self.feed(&vec![0u8; d])
}
}
#[derive(Debug, Clone)]
pub struct ConvDeinterleaver {
branches: usize,
depth: usize,
fifos: Vec<VecDeque<u8>>,
pos: usize,
}
impl ConvDeinterleaver {
pub fn new(branches: usize, depth: usize) -> Self {
assert!(
branches > 0 && depth > 0,
"convolutional interleaver dimensions must be nonzero"
);
Self {
branches,
depth,
fifos: (0..branches)
.map(|j| VecDeque::from(vec![0u8; (branches - 1 - j) * depth]))
.collect(),
pos: 0,
}
}
pub fn dvbt() -> Self {
Self::new(12, 17)
}
pub fn branches(&self) -> usize {
self.branches
}
pub fn depth(&self) -> usize {
self.depth
}
pub fn roundtrip_delay(&self) -> usize {
conv_roundtrip_delay(self.branches, self.depth)
}
pub fn reset(&mut self) {
for (j, fifo) in self.fifos.iter_mut().enumerate() {
fifo.clear();
fifo.extend(std::iter::repeat_n(
0u8,
(self.branches - 1 - j) * self.depth,
));
}
self.pos = 0;
}
pub fn feed(&mut self, data: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(data.len());
for &b in data {
let j = self.pos % self.branches;
if self.branches - 1 - j == 0 {
out.push(b);
} else {
self.fifos[j].push_back(b);
out.push(self.fifos[j].pop_front().unwrap());
}
self.pos += 1;
}
out
}
pub fn flush(&mut self) -> Vec<u8> {
let d = self.roundtrip_delay();
self.feed(&vec![0u8; d])
}
}