From e7bb36d655d7694271a314fd03354bb86d928020 Mon Sep 17 00:00:00 2001 From: Albin Chaboissier Date: Fri, 3 Oct 2025 02:19:32 +0200 Subject: [PATCH] framed com --- src/main.rs | 128 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 33 deletions(-) diff --git a/src/main.rs b/src/main.rs index bd1fdff..7629344 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,12 +5,11 @@ use std::{ f32::consts::PI, fs::File, i16, - io::{Read, Write}, + io::{self, Read, Write}, ops::{Add, Div, Mul, Sub}, os::unix::thread, sync::{ - Arc, - mpsc::{self, Receiver, Sender, TryRecvError, sync_channel}, + atomic::{AtomicU32, Ordering}, mpsc::{self, channel, sync_channel, Receiver, Sender, TryRecvError}, Arc }, time::Duration, }; @@ -35,7 +34,7 @@ use cpal::{ use fft::DFTAlgorithm; use nco::Nco; -use eframe::egui::{self, Color32, Context, Vec2b, debug_text::print}; +use eframe::egui::{self, debug_text::print, decode_animated_image_uri, Color32, Context, Vec2b}; use egui_plot::{self, Bar, BarChart, Legend, Line, LineStyle, Plot, PlotPoints, VLine}; use plotters::style::Color; use rand::{seq::index::sample, Rng}; @@ -263,6 +262,9 @@ fn demodulator( ); // Timing recovery + let mut preamble_count = 0; + let mut bit_index = 0; + let mut last = 0u8; while let Ok(real_sample) = rx.recv() { let iq = iq_sampler.sample(real_sample); @@ -272,10 +274,35 @@ fn demodulator( let matched = matched_filter.next_real(pos_energy.mag() - neg_energy.mag()); - if let Some((_, 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 + { + bit_index += 1; + if bit_index == 8 + { + if last == 4 + { + println!(); + preamble_count = 0; + } + else + { + print!("{}", last as char); + bit_index = 0; + } + } + } + if last == 0xD8 + { + preamble_count += 1; + } } } } @@ -436,39 +463,74 @@ fn modulate() { let sample_rate = 48000; let baud_rate = BAUD_RATE; - // File to modulate - let f = File::open("s.txt").unwrap(); - let mut bitstream = std::iter::repeat_n(0b01010101u8, 1) - .chain(std::iter::repeat_n(0b01010111u8, 1)) - .chain(f.bytes().map(|x| x.unwrap())) - .chain(std::iter::repeat_n(0u8, 1)) - .flat_map(byte_to_bits); + let host = cpal::default_host(); + 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) + .expect("Device does not support 48kHz f32 output"); + let config = supported_config.with_sample_rate(cpal::SampleRate(48_000)).config(); - let mut modulator = BFSKMod::new( - sample_rate / baud_rate, - units::frequency::hz_to_rad_per_sample(deviation, sample_rate as f32), - &mut bitstream, - ); - let mut lo = Nco::new(units::frequency::hz_to_rad_per_sample( - frequency, - sample_rate as f32, - )); + loop + { + let mut buffer = String::new(); + let stdin = io::stdin(); // We get `Stdin` here. + stdin.read_line(&mut buffer).unwrap(); - let spec = hound::WavSpec { - channels: 1, - sample_rate, - bits_per_sample: 16, - sample_format: hound::SampleFormat::Int, - }; + // Construct payload + let mut bitstream = + std::iter::repeat_n(0b01010101u8, 32) + .chain(std::iter::repeat_n(0b11011000, 1)) + .chain(buffer.bytes()) + .chain(std::iter::repeat_n(4u8, 32)) + .flat_map(byte_to_bits); - let mut writer = hound::WavWriter::create("audio/modulated.wav", spec).unwrap(); - for (s, up) in modulator.zip(lo) { - let sample = (s * up).re; // Project to I coords - let amplitude = i16::MAX as f32; - writer.write_sample((sample * amplitude) as i16).unwrap(); + let mut modulator = BFSKMod::new( + sample_rate / baud_rate, + units::frequency::hz_to_rad_per_sample(deviation, sample_rate as f32), + &mut bitstream, + ); + + let mut lo = Nco::new(units::frequency::hz_to_rad_per_sample( + frequency, + sample_rate as f32, + )); + + // To send + let stream = modulator.zip(lo) + .map(|(s, up)| (s * up).re) + .collect::>(); + + 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; + } + *d = stream[sample_clock.fetch_add(1, Ordering::Relaxed) as usize] + } + + }, + move |err| { + eprintln!("Stream error: {}", err); + }, + None + ).unwrap(); + + stream.play().unwrap(); + let _ = rx.recv(); + stream.pause().unwrap(); } - writer.finalize().unwrap(); } fn byte_to_bits(byte: u8) -> Vec {