Framed transmission

This commit is contained in:
2025-10-03 12:28:01 +02:00
parent e7bb36d655
commit 64369d58ab

View File

@ -9,7 +9,9 @@ use std::{
ops::{Add, Div, Mul, Sub},
os::unix::thread,
sync::{
atomic::{AtomicU32, Ordering}, mpsc::{self, channel, sync_channel, Receiver, Sender, TryRecvError}, Arc
Arc,
atomic::{AtomicU32, Ordering},
mpsc::{self, Receiver, Sender, TryRecvError, channel, sync_channel},
},
time::Duration,
};
@ -34,10 +36,10 @@ use cpal::{
use fft::DFTAlgorithm;
use nco::Nco;
use eframe::egui::{self, debug_text::print, decode_animated_image_uri, Color32, Context, Vec2b};
use eframe::egui::{self, Color32, Context, Vec2b, debug_text::print, decode_animated_image_uri};
use egui_plot::{self, Bar, BarChart, Legend, Line, LineStyle, Plot, PlotPoints, VLine};
use plotters::style::Color;
use rand::{seq::index::sample, Rng};
use rand::{Rng, seq::index::sample};
use crate::{
bfsk::BFSKDem,
@ -57,7 +59,7 @@ where
{
((input - in_min.clone()) / (in_max - in_min)) * (out_max - out_min.clone()) + out_min
}
const BAUD_RATE: u32 = 1000;
const BAUD_RATE: u32 = 1200;
fn main() {
modulate();
@ -134,8 +136,7 @@ fn main() {
}
// Early late gate
struct ELGate
{
struct ELGate {
samples_per_symbol: f32,
buffer: VecDeque<f32>, // Store baseband, matched filtered samples,
@ -145,35 +146,33 @@ struct ELGate
current_position: f32,
}
impl ELGate
{
pub fn new(samples_per_symbol: f32, loop_filter: FIRFilter) -> Self
{
Self
{
impl ELGate {
pub fn new(samples_per_symbol: f32, loop_filter: FIRFilter) -> Self {
Self {
samples_per_symbol,
loop_filter,
buffer: VecDeque::with_capacity(2 * samples_per_symbol.ceil() as usize),
delta: 0.5,
next_sample: samples_per_symbol,
current_position: 0.
current_position: 0.,
}
}
pub fn next(&mut self, sample: f32) -> Option<bool>
{
pub fn next(&mut self, sample: f32) -> Option<bool> {
Some(self.next_eye(sample)?.0) // Ignore eye
}
pub fn next_eye(&mut self, sample: f32) -> Option<(bool, Vec<f32>)>
{
self.buffer.push_front(sample);
pub fn next_eye(&mut self, sample: f32) -> Option<(bool, Vec<f32>)> {
self.buffer.push_front(sample);
self.current_position += 1.;
if self.current_position >= self.next_sample
{
if self.current_position >= self.next_sample {
// Sample center, early late
let early_id = (self.samples_per_symbol / 2. + self.samples_per_symbol * self.delta).floor().min(self.buffer.len() as f32 - 1.) as usize;
let late_id = (self.samples_per_symbol / 2. - self.samples_per_symbol * self.delta).floor().max(0.) as usize;
let early_id = (self.samples_per_symbol / 2. + self.samples_per_symbol * self.delta)
.floor()
.min(self.buffer.len() as f32 - 1.) as usize;
let late_id = (self.samples_per_symbol / 2. - self.samples_per_symbol * self.delta)
.floor()
.max(0.) as usize;
let sample_id = (self.samples_per_symbol / 2.) as usize;
let early_sample = self.buffer[early_id];
@ -184,8 +183,7 @@ impl ELGate
// Remove until only current sample is in buffer (the next sample might need data from
// current sample if error advances sample position)
while self.buffer.len() > self.samples_per_symbol as usize
{
while self.buffer.len() > self.samples_per_symbol as usize {
let _ = self.buffer.pop_back();
}
@ -194,9 +192,7 @@ impl ELGate
self.next_sample = self.samples_per_symbol - self.loop_filter.next_real(error);
Some((sample > 0., Vec::from(self.buffer.clone())))
}
else
{
} else {
None
}
}
@ -256,11 +252,8 @@ fn demodulator(
let mut loop_filter = FIRFilter::new(&loop_filter_ir);
//loop_filter.normalize_sum();
let mut elg = ELGate::new(
sample_per_symbol as f32,
loop_filter
);
let mut elg = ELGate::new(sample_per_symbol as f32, loop_filter);
// Timing recovery
let mut preamble_count = 0;
let mut bit_index = 0;
@ -274,33 +267,26 @@ fn demodulator(
let matched = matched_filter.next_real(pos_energy.mag() - neg_energy.mag());
if let Some((bit, eye)) = elg.next_eye(matched)
{
if let Some((bit, eye)) = elg.next_eye(matched) {
let _ = eye_sender.send(eye);
ctx.request_repaint();
last <<= 1;
last |= bit as u8;
if preamble_count >= 2
{
if preamble_count >= 2 {
bit_index += 1;
if bit_index == 8
{
if last == 4
{
if bit_index == 8 {
if last == 4 {
println!();
preamble_count = 0;
}
else
{
} else {
print!("{}", last as char);
bit_index = 0;
}
}
}
if last == 0xD8
{
if last == 0xD8 {
preamble_count += 1;
}
}
@ -467,23 +453,29 @@ fn modulate() {
let device = host.default_output_device().unwrap();
let mut supported_configs_range = device.supported_output_configs().unwrap();
let supported_config = supported_configs_range
.find(|config| config.sample_format() == cpal::SampleFormat::F32
&& config.min_sample_rate().0 <= 48000
&& config.max_sample_rate().0 >= 48000)
.find(|config| {
config.sample_format() == cpal::SampleFormat::F32
&& config.min_sample_rate().0 <= 48000
&& config.max_sample_rate().0 >= 48000
})
.expect("Device does not support 48kHz f32 output");
let config = supported_config.with_sample_rate(cpal::SampleRate(48_000)).config();
let config = supported_config
.with_sample_rate(cpal::SampleRate(48_000))
.config();
loop
{
loop {
let mut buffer = String::new();
let stdin = io::stdin(); // We get `Stdin` here.
stdin.read_line(&mut buffer).unwrap();
for c in buffer.bytes() {
print!("{}", c as char);
}
println!();
// Construct payload
let mut bitstream =
std::iter::repeat_n(0b01010101u8, 32)
.chain(std::iter::repeat_n(0b11011000, 1))
let mut bitstream = std::iter::repeat_n(0b01010101u8, 64)
.chain(std::iter::repeat_n(0xD8, 2))
.chain(buffer.bytes())
.chain(std::iter::repeat_n(4u8, 32))
.flat_map(byte_to_bits);
@ -495,37 +487,37 @@ fn modulate() {
);
let mut lo = Nco::new(units::frequency::hz_to_rad_per_sample(
frequency,
sample_rate as f32,
frequency,
sample_rate as f32,
));
// To send
let stream = modulator.zip(lo)
let stream = modulator
.zip(lo)
.map(|(s, up)| (s * up).re)
.collect::<Vec<_>>();
let sample_clock = Arc::new(AtomicU32::new(0));
let (tx, rx) = channel::<()>();
let stream = device.build_output_stream(
&config,
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
for d in data.iter_mut()
{
if sample_clock.load(Ordering::Relaxed) as usize == stream.len()
{
tx.send(()).unwrap();
break;
let stream = device
.build_output_stream(
&config,
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
for d in data.iter_mut() {
if sample_clock.load(Ordering::Relaxed) as usize == stream.len() {
tx.send(()).unwrap();
break;
}
*d = stream[sample_clock.fetch_add(1, Ordering::Relaxed) as usize]
}
*d = stream[sample_clock.fetch_add(1, Ordering::Relaxed) as usize]
}
},
move |err| {
eprintln!("Stream error: {}", err);
},
None
).unwrap();
},
move |err| {
eprintln!("Stream error: {}", err);
},
None,
)
.unwrap();
stream.play().unwrap();
let _ = rx.recv();