use super::dvb_t_frame::{DvbTFrameDemod, DvbTRxError, DvbTRxFrame};
use super::dvb_t_probe::DvbTRxProbe;
use crate::sync::dvb_t_gi_sync;
use crate::waveform::dvb_t::{DVB_T_N_FFT, DvbTFrameParams};
use num_complex::Complex32 as C32;
pub struct DvbTFrameStreamDemod {
demod: DvbTFrameDemod,
n_symbols: usize,
payload_len: usize,
sps: usize,
buf: Vec<C32>,
}
impl DvbTFrameStreamDemod {
pub fn new(params: DvbTFrameParams, n_symbols: usize, payload_len: usize) -> Self {
let cp_len = params.config().carrier_plan.cp_len();
Self {
demod: DvbTFrameDemod::new(params),
n_symbols,
payload_len,
sps: DVB_T_N_FFT + cp_len,
buf: Vec::new(),
}
}
pub fn with_integer_cfo_correction(mut self, on: bool) -> Self {
self.demod = self.demod.with_integer_cfo_correction(on);
self
}
pub fn with_rx_window_backoff(mut self, backoff: usize) -> Self {
self.demod = self.demod.with_rx_window_backoff(backoff);
self
}
pub fn with_error_rates(mut self, on: bool) -> Self {
self.demod = self.demod.with_error_rates(on);
self
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
pub fn view_buf(&self) -> &[C32] {
&self.buf
}
pub fn clear(&mut self) {
self.buf.clear();
}
fn frame_samples(&self) -> usize {
self.n_symbols * self.sps
}
pub fn feed(&mut self, iq: &[C32]) -> Vec<Result<DvbTRxFrame, DvbTRxError>> {
self.buf.extend_from_slice(iq);
self.drain(None)
}
pub fn flush(&mut self) -> Vec<Result<DvbTRxFrame, DvbTRxError>> {
self.drain(None)
}
pub fn feed_probed(
&mut self,
iq: &[C32],
probe: &mut DvbTRxProbe,
) -> Vec<Result<DvbTRxFrame, DvbTRxError>> {
probe.clear();
self.buf.extend_from_slice(iq);
self.drain(Some(probe))
}
pub fn flush_probed(
&mut self,
probe: &mut DvbTRxProbe,
) -> Vec<Result<DvbTRxFrame, DvbTRxError>> {
probe.clear();
self.drain(Some(probe))
}
fn drain(
&mut self,
mut probe: Option<&mut DvbTRxProbe>,
) -> Vec<Result<DvbTRxFrame, DvbTRxError>> {
let mut out = Vec::new();
while let FrameStep::Decoded(result, consume_to) = self.try_one_frame(probe.as_deref_mut())
{
self.buf.drain(..consume_to);
out.push(result);
}
out
}
fn try_one_frame(&mut self, probe: Option<&mut DvbTRxProbe>) -> FrameStep {
let n_fft = DVB_T_N_FFT;
let cp_len = self.sps - n_fft;
let fs = self.demod.params().config().fs;
let need = self.sps + self.frame_samples();
if self.buf.len() < need {
return FrameStep::NeedMore;
}
let Some(acq) = dvb_t_gi_sync(&self.buf, n_fft, cp_len, fs, self.sps) else {
return FrameStep::NeedMore;
};
let start = acq.start_sample;
let consume_to = start + self.frame_samples();
if consume_to > self.buf.len() {
return FrameStep::NeedMore;
}
let decoded = match probe {
Some(p) => {
self.demod
.decode_probed(&self.buf[start..], self.n_symbols, self.payload_len, p)
}
None => self
.demod
.decode(&self.buf[start..], self.n_symbols, self.payload_len),
};
match decoded {
Ok(frame) => FrameStep::Decoded(Ok(frame), consume_to),
Err(e) => FrameStep::Decoded(Err(e), consume_to),
}
}
}
enum FrameStep {
Decoded(Result<DvbTRxFrame, DvbTRxError>, usize),
NeedMore,
}