use crate::discriminator::{Discriminator, QuadratureCorrelator};
use crate::error::ConfigError;
use crate::slicer::Slicer;
use crate::types::{BaudRate, Bit, SampleRate, TonePair};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DemodulatorConfig {
sample_rate: SampleRate,
baud: BaudRate,
tones: TonePair,
}
impl DemodulatorConfig {
pub const fn new(
sample_rate: SampleRate,
baud: BaudRate,
tones: TonePair,
) -> Result<Self, ConfigError> {
if sample_rate.hz() / baud.bps() < 2 {
return Err(ConfigError::BaudExceedsSampleRate {
baud: baud.bps(),
sample_rate: sample_rate.hz(),
});
}
if let Err(e) = TonePair::new(tones.mark_hz(), tones.space_hz(), sample_rate) {
return Err(e);
}
Ok(Self {
sample_rate,
baud,
tones,
})
}
pub const fn bell_202(sample_rate: SampleRate) -> Result<Self, ConfigError> {
let baud = match BaudRate::new(1_200) {
Ok(b) => b,
Err(e) => return Err(e),
};
let tones = match TonePair::new(1_200, 2_200, sample_rate) {
Ok(t) => t,
Err(e) => return Err(e),
};
Self::new(sample_rate, baud, tones)
}
pub const fn sample_rate(self) -> SampleRate {
self.sample_rate
}
pub const fn baud(self) -> BaudRate {
self.baud
}
pub const fn tones(self) -> TonePair {
self.tones
}
}
#[derive(Debug, Clone)]
pub struct Demodulator<D> {
discriminator: D,
slicer: Slicer,
}
pub type AfskDemodulator = Demodulator<QuadratureCorrelator>;
impl AfskDemodulator {
pub fn new(config: DemodulatorConfig) -> Result<Self, ConfigError> {
let discriminator =
QuadratureCorrelator::new(config.sample_rate(), config.baud(), config.tones())?;
Self::with_discriminator(config, discriminator)
}
}
impl<D: Discriminator> Demodulator<D> {
pub fn with_discriminator(
config: DemodulatorConfig,
discriminator: D,
) -> Result<Self, ConfigError> {
let slicer = Slicer::new(config.sample_rate(), config.baud())?;
Ok(Self {
discriminator,
slicer,
})
}
pub fn push_sample_i16(&mut self, sample: i16) -> Option<Bit> {
let metric = self.discriminator.push_i16(sample);
self.slicer.push(metric)
}
pub fn push_sample_f32(&mut self, sample: f32) -> Option<Bit> {
let metric = self.discriminator.push_f32(sample);
self.slicer.push(metric)
}
pub fn i16_bits<I>(self, samples: I) -> I16Bits<I::IntoIter, D>
where
I: IntoIterator<Item = i16>,
{
I16Bits {
demodulator: self,
samples: samples.into_iter(),
}
}
pub fn f32_bits<I>(self, samples: I) -> F32Bits<I::IntoIter, D>
where
I: IntoIterator<Item = f32>,
{
F32Bits {
demodulator: self,
samples: samples.into_iter(),
}
}
}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct I16Bits<I, D> {
demodulator: Demodulator<D>,
samples: I,
}
impl<I, D> Iterator for I16Bits<I, D>
where
I: Iterator<Item = i16>,
D: Discriminator,
{
type Item = Bit;
fn next(&mut self) -> Option<Bit> {
loop {
let sample = self.samples.next()?;
if let Some(bit) = self.demodulator.push_sample_i16(sample) {
return Some(bit);
}
}
}
}
#[derive(Debug, Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
pub struct F32Bits<I, D> {
demodulator: Demodulator<D>,
samples: I,
}
impl<I, D> Iterator for F32Bits<I, D>
where
I: Iterator<Item = f32>,
D: Discriminator,
{
type Item = Bit;
fn next(&mut self) -> Option<Bit> {
loop {
let sample = self.samples.next()?;
if let Some(bit) = self.demodulator.push_sample_f32(sample) {
return Some(bit);
}
}
}
}