use super::dvb_t_frame::{DvbTFrame, DvbTFrameMod};
use crate::fec::PunctureRate;
use crate::modulate::ConstellationOrder;
use crate::waveform::dvb_t::{DvbTFrameParams, DvbTLinkParams, GuardInterval};
use num_complex::Complex32 as C32;
pub const DVB_T_FRAMES_PER_SUPER_FRAME: usize = 4;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DvbTSuperFrameParams {
pub link: DvbTLinkParams,
pub cell_id: u16,
}
impl DvbTSuperFrameParams {
pub fn guard(self) -> GuardInterval {
self.link.guard
}
pub fn constellation(self) -> ConstellationOrder {
self.link.constellation
}
pub fn code_rate(self) -> PunctureRate {
self.link.code_rate
}
pub fn frame(self, frame_number: u8) -> DvbTFrameParams {
let cell_id = if frame_number.is_multiple_of(2) {
(self.cell_id >> 8) as u8 } else {
(self.cell_id & 0xFF) as u8 };
DvbTFrameParams {
link: self.link,
frame_number,
cell_id,
}
}
}
#[derive(Debug, Clone)]
pub struct DvbTSuperFrame {
pub iq: Vec<C32>,
pub symbols_per_frame: usize,
pub samples_per_symbol: usize,
pub frame_payload_lens: [usize; DVB_T_FRAMES_PER_SUPER_FRAME],
}
impl DvbTSuperFrame {
pub fn n_symbols(&self) -> usize {
DVB_T_FRAMES_PER_SUPER_FRAME * self.symbols_per_frame
}
}
#[derive(Debug, Clone)]
pub struct DvbTSuperFrameMod {
params: DvbTSuperFrameParams,
}
impl DvbTSuperFrameMod {
pub fn new(params: DvbTSuperFrameParams) -> Self {
Self { params }
}
pub fn params(&self) -> DvbTSuperFrameParams {
self.params
}
pub fn modulate(&self, payload: &[u8]) -> DvbTSuperFrame {
let params = self.params;
let n = DVB_T_FRAMES_PER_SUPER_FRAME;
let base = payload.len() / n;
let rem = payload.len() % n;
let mut parts: Vec<Vec<u8>> = Vec::with_capacity(n);
let mut off = 0usize;
let mut frame_payload_lens = [0usize; DVB_T_FRAMES_PER_SUPER_FRAME];
for (i, len_slot) in frame_payload_lens.iter_mut().enumerate() {
let len = base + usize::from(i < rem);
parts.push(payload[off..off + len].to_vec());
*len_slot = len;
off += len;
}
let part_len = frame_payload_lens.iter().copied().max().unwrap_or(0);
for part in &mut parts {
part.resize(part_len, 0);
}
let frames: Vec<DvbTFrame> = (0..n)
.map(|f| DvbTFrameMod::new(params.frame(f as u8)).modulate(&parts[f]))
.collect();
let symbols_per_frame = frames[0].n_symbols;
let samples_per_symbol = frames[0].samples_per_symbol;
debug_assert!(
frames.iter().all(|f| f.n_symbols == symbols_per_frame),
"equal-length parts must modulate to equal symbol counts"
);
let mut iq = Vec::with_capacity(symbols_per_frame * samples_per_symbol * n);
for frame in &frames {
iq.extend_from_slice(&frame.iq);
}
DvbTSuperFrame {
iq,
symbols_per_frame,
samples_per_symbol,
frame_payload_lens,
}
}
}