use std::error::Error;
pub mod fsk;
pub use fsk::FSK;
pub mod bpsk;
pub use bpsk::BPSK;
pub const SAMPLE_RATE: u32 = 48_000; pub const BAUD_RATE: u32 = 1_200; pub const SAMPLES_PER_BIT: u32 = SAMPLE_RATE / BAUD_RATE;
pub fn byte_to_bits<T>(byte: u8) -> Vec<T>
where
T: From<bool>,
{
(0..8)
.map(|i| T::from(((byte >> (7 - i)) & 1) == 1))
.collect()
}
pub fn bits_to_byte<T>(bits: &[T]) -> u8
where
T: Into<bool> + Copy,
{
bits.iter()
.fold(0u8, |acc, &bit| (acc << 1) | if bit.into() { 1 } else { 0 })
}
pub trait ModemTrait {
fn modulate(&self, data: &[bool]) -> Result<Vec<f32>, Box<dyn Error>>;
fn demodulate(&self, samples: &[f32]) -> Result<Vec<bool>, Box<dyn Error>>;
fn analyze_bit(&self, samples: &[f32]) -> Result<(f32, f32), Box<dyn Error>>;
}
macro_rules! impl_codec {
(
$($codec:ident),* $(,)?
) => {
pub enum Codec {
$(
$codec($codec),
)*
}
impl Codec {
pub fn modulate(&self, data: &[u8]) -> Result<Vec<f32>, Box<dyn Error>> {
match self {
$(
Codec::$codec(codec) => codec.modulate(&data.iter().flat_map(|&b| byte_to_bits::<bool>(b)).collect::<Vec<_>>()),
)*
}
}
pub fn demodulate(&self, samples: &[f32]) -> Result<Vec<bool>, Box<dyn Error>> {
match self {
$(
Codec::$codec(codec) => codec.demodulate(samples),
)*
}
}
}
};
}
impl_codec!(
FSK,
);