From fe4f1657e5075b200132751972c29b5e22620a7d Mon Sep 17 00:00:00 2001 From: Albin Chaboissier Date: Thu, 9 Oct 2025 22:32:41 +0200 Subject: [PATCH] Frame reception down --- src/main.rs | 209 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 163 insertions(+), 46 deletions(-) diff --git a/src/main.rs b/src/main.rs index e918e32..ff86859 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,9 @@ mod ted; mod units; mod windows; +use egui_plot::{Legend, Line, Plot}; use rand::{rand_core::le, seq::index::sample}; -use std::{collections::VecDeque, time::Duration}; +use std::{collections::VecDeque, io::{stdout, Write}, time::Duration}; use tokio::{join, net::UdpSocket, select, time::timeout}; use crate::{ @@ -24,7 +25,7 @@ use crate::{ ted::elg::ELGate, units::frequency::hz_to_rad_per_sample, }; -use eframe::{egui, glow::SAMPLE_MASK_VALUE}; +use eframe::{egui::{self, Color32}, glow::SAMPLE_MASK_VALUE}; use tokio::sync::mpsc::{Receiver, Sender, channel}; const BAUD_RATE: u32 = 1000; @@ -34,12 +35,44 @@ const SAMPLE_RATE: u32 = 48000; const CENTER_FREQ: f32 = 1700.; const DEVIATION: f32 = 500.; + pub trait SampleSender { fn open_link(&mut self); fn send_samples(&mut self, samples: &[f32]); fn close_link(&mut self); } +struct WavSampleSender +{ + +} + +impl SampleSender for WavSampleSender +{ + fn open_link(&mut self) { + } + + fn send_samples(&mut self, samples: &[f32]) { + let spec = hound::WavSpec { + channels: 1, + sample_rate: SAMPLE_RATE, + bits_per_sample: 16, + sample_format: hound::SampleFormat::Int, + }; + let mut writer = hound::WavWriter::create("audio/modulated.wav", spec).unwrap(); + + for s in samples + { + let out_sample = (s * i16::MAX as f32) as i16; + writer.write_sample(out_sample).unwrap(); + } + writer.finalize().unwrap(); + } + + fn close_link(&mut self) { + } +} + struct Transceiver {} impl Transceiver { @@ -48,16 +81,16 @@ impl Transceiver { mut tx_stream: Receiver>, mut rx_stream: Sender>, sample_sender: &mut T, + mut eye_sender: Sender> ) { let mut resend: Option> = None; loop { select! { _ = Self::squelch_detector(&mut sample_stream) => { - println!("Squelch UP"); select! { - x = Self::receive(&mut sample_stream) => + x = Self::receive(&mut sample_stream, &mut eye_sender) => { match x { @@ -73,7 +106,7 @@ impl Transceiver { } } }, - _ = tokio::time::sleep(Duration::from_secs(2)) => {continue;}, //TODO: 65 + _ = tokio::time::sleep(Duration::from_secs(100)) => {continue;}, //TODO: 65 //sec //timeout } @@ -103,13 +136,12 @@ impl Transceiver { } async fn squelch_detector(sample_stream: &mut Receiver) { - let length = 500; - let level = 0.01; + let length = 200; + let level = 0.4; let mut iq_sampler = IQSampler::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32)); let mut squelch_sum = 0.; let mut i = 0; while let Some(smpl) = sample_stream.recv().await { - println!("sdkf"); let iq = iq_sampler.sample(smpl); squelch_sum += iq.mag() / length as f32; i += 1; @@ -118,14 +150,13 @@ impl Transceiver { if squelch_sum >= level { return; } - } else { i = 0; squelch_sum = 0.; } } } - async fn transmit(frame: Frame, samples_sender: &mut T) { + pub async fn transmit(frame: Frame, samples_sender: &mut T) { let bytes = frame.bytes(); let mut bit_stream = bytes.iter().flat_map(|x| byte_to_bits(*x)); let modulator = BFSKMod::new( @@ -147,7 +178,7 @@ impl Transceiver { samples_sender.close_link(); } - async fn receive(sample_stream: &mut Receiver) -> Result { + async fn receive(sample_stream: &mut Receiver, eye_sender: &mut Sender>) -> Result { let mut iq_sampler = IQSampler::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32)); let samples_per_symbol = (SAMPLE_RATE as f32) / (BAUD_RATE as f32); @@ -155,25 +186,29 @@ impl Transceiver { let correllator_length = samples_per_symbol as usize; let mut pos_nco = Nco::new(hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32)); let mut neg_nco = Nco::new(hz_to_rad_per_sample(-DEVIATION, SAMPLE_RATE as f32)); - let pos_ir = (0..correllator_length).map(|_| { + let pos_ir = (0..correllator_length).map(|i| { pos_nco.step(); - pos_nco.cexp() + pos_nco.cexp() * windows::blackmann(i as f32 / correllator_length as f32) }); - let neg_ir = (0..correllator_length).map(|_| { + let neg_ir = (0..correllator_length).map(|i| { neg_nco.step(); - neg_nco.cexp() + neg_nco.cexp() * windows::blackmann(i as f32 / correllator_length as f32) }); let mut pos_correllator = FIRFilter::new(&pos_ir.collect::>()); let mut neg_correllator = FIRFilter::new(&neg_ir.collect::>()); + pos_correllator.normalize_freq(hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32)); + neg_correllator.normalize_freq(hz_to_rad_per_sample(-DEVIATION, SAMPLE_RATE as f32)); let mut matched_lowpass = - FIRFilter::new(&vec![Complex32::new(1., 0.); samples_per_symbol as usize]); - let mut dc_block = DCBlocker::new(0.995); + FIRFilter::new(&vec![Complex32::new(1., 0.); samples_per_symbol as usize / 2]); + matched_lowpass.normalize_freq(hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32)); + //let mut dc_block = DCBlocker::new(0.999); + let mut dc_block = DCBlocker::new(1.); - let loop_i = 0.1; + let loop_i = 0.0; let loop_p = 0.1; let mut loop_ir = vec![Complex32::new(loop_i, 0.); samples_per_symbol as usize]; - loop_ir.push(Complex32::new(loop_p, 0.)); + loop_ir.push(Complex32::new(loop_p, 0.)); let mut elg = ELGate::new(samples_per_symbol, FIRFilter::new(&loop_ir)); // Frame reconstruction @@ -183,18 +218,22 @@ impl Transceiver { while let Some(sample) = sample_stream.recv().await { let iq = iq_sampler.sample(sample); let matched = - dc_block - .next_real(matched_lowpass.next_real( - pos_correllator.next(iq).mag() - neg_correllator.next(iq).mag(), - )); - if let Some(bit_sample) = elg.next(matched) { - last_byte <<= 1; - last_byte |= (bit_sample > 0.) as u8; + matched_lowpass.next_real( + dc_block.next_real( + pos_correllator.next(iq).mag() - neg_correllator.next(iq).mag(), + ) + ); + if let Some((bit_sample, eye)) = elg.next_eye(matched) { + let _ = eye_sender.send(eye).await; + last_byte >>= 1; + last_byte |= ((bit_sample > 0.) as u8) << 7; + //last_byte <<= 1; + //last_byte |= ((bit_sample < 0.) as u8); bit_count = bit_count.map(|x| x + 1); - if last_byte == 0xD8 - // Potential frame starts + if let None = bit_count && last_byte == 0xD8 { + // Potential frame starts last_byte = 0; frame_constructor = FrameConstructor::new(); bit_count = Some(0); @@ -203,16 +242,23 @@ impl Transceiver { if let Some(8) = bit_count { let frame_opt = frame_constructor.add_byte(last_byte); bit_count = Some(0); + //print!("{}", last_byte as char); + print!(".{:x}.", last_byte); + let _ = std::io::stdout().flush(); + if let Ok(Some(Frame::Ack)) = frame_opt { + println!("Got ack"); return Ok(Frame::Ack); } if let Ok(Some(Frame::Data(ref frame_data))) = frame_opt { + println!("Got data"); return Ok(Frame::Data(frame_data.to_vec())); } if let Err(()) = frame_opt { // Erroneous frame + println!("Error"); return Err(()); } } @@ -232,6 +278,7 @@ pub struct FrameConstructor { frame: Vec, frame_countdown: Option, checksum: u8, + started: bool } impl FrameConstructor { @@ -240,19 +287,24 @@ impl FrameConstructor { frame: Vec::new(), frame_countdown: None, checksum: 0u8, + started: false } } pub fn add_byte(&mut self, byte: u8) -> Result, FrameConstructionError> { - if self.frame.is_empty() && byte != 0xC4 && byte != 0x4C { + if self.frame.is_empty() && byte != 0xC4 && byte != 0x4C && !self.started { + println!("Wrong type {:x}", byte); + self.started = true; return Err(()); } - if self.frame.is_empty() && byte == 0xC4 { + if self.frame.is_empty() && byte == 0xC4 && !self.started{ + self.started = true; return Ok(Some(Frame::Ack)); } - if self.frame.is_empty() && byte == 0x4C { + if self.frame.is_empty() && byte == 0x4C && !self.started{ + self.started = true; return Ok(None); } @@ -276,10 +328,11 @@ impl FrameConstructor { ))); } + println!("Checksum failed"); return Err(()); } - self.frame.push(byte); + //self.frame.push(byte); self.checksum ^= byte; *self.frame_countdown.as_mut().unwrap() -= 1; @@ -300,15 +353,16 @@ impl Frame { // Command match self { Frame::Data(x) => { - let mut checksum = 0u8; - x.iter().for_each(|x| checksum ^= x); - assert!(x.len() < 65536, "Data size over MTU"); - let len_u16 = x.len() as u16; + output_bytes.push(0x4C); // DATA FRAME + + let len_u16 = x.len() as u16; output_bytes.push((len_u16 & 0xFF).try_into().unwrap()); output_bytes.push(((len_u16 >> 8) & 0xFF).try_into().unwrap()); + let mut checksum = 0u8; + x.iter().for_each(|x| checksum ^= x); output_bytes.extend(x.iter()); output_bytes.push(checksum); @@ -326,6 +380,10 @@ impl Frame { #[tokio::main] async fn main() { + let rand = rand::rng(); + Transceiver::transmit(Frame::Data("Skibditoilet".repeat(100).bytes().collect::>()), &mut WavSampleSender{}).await; + //return; + let native_options = eframe::NativeOptions::default(); let _ = eframe::run_native( "Egui", @@ -335,7 +393,6 @@ async fn main() { } //#[derive(Default)] -struct EguiApp {} struct DummySampleSender(); @@ -345,47 +402,107 @@ impl SampleSender for DummySampleSender { fn close_link(&mut self) {} } +struct EguiApp { + eye_receiver: Receiver>, + eyes: VecDeque> +} impl EguiApp { fn new(_cc: &eframe::CreationContext<'_>) -> Self { + let (eye_tx, mut eye_rx) = channel::>(1024); + let (eye_red_tx, eye_red_rx) = channel::>(1024); + let ctx = _cc.egui_ctx.clone(); + tokio::spawn(async move + { + loop + { + if let Some(eye) = eye_rx.recv().await + { + ctx.request_repaint(); + eye_red_tx.send(eye).await; + } + } + } + ); + let (sample_tx, sample_rx) = channel::(1024); let (transmit_tx, transmit_rx) = channel::>(1024); - let (receive_tx, receive_rx) = channel::>(1024); + let (receive_tx, mut receive_rx) = channel::>(1024); tokio::spawn(async move { - Transceiver::start(sample_rx, transmit_rx, receive_tx, &mut DummySampleSender()).await; + Transceiver::start(sample_rx, transmit_rx, receive_tx, &mut DummySampleSender(), eye_tx).await; + }); + + tokio::spawn(async move { + loop + { + let bytes = receive_rx.recv().await.unwrap(); + let str = String::from_utf8(bytes).unwrap(); + println!("{}", str); + + } }); tokio::spawn(async move { let sock = UdpSocket::bind("0.0.0.0:8080").await.unwrap(); - let mut buf = [0u8; 1024]; - let mut sample = 0i16; + let mut buf = [0u8; 2048]; + let mut sample = [0u8; 2]; let mut byte_index = 0; loop { let len = sock.recv(&mut buf).await.unwrap(); for x in buf.iter().take(len) { - sample |= (*x as i16) << (byte_index * 8); + sample[byte_index] = *x; byte_index += 1; if byte_index >= 2 { + let pcm16_sample = i16::from_le_bytes(sample); sample_tx - .send(sample as f32 / i16::MAX as f32) + .send(pcm16_sample as f32 / i16::MAX as f32) .await .unwrap(); byte_index = 0; - sample = 0i16; } } } }); - Self {} + Self { + eye_receiver: eye_red_rx, + eyes: VecDeque::with_capacity(100) + } } } impl eframe::App for EguiApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { - egui::CentralPanel::default().show(ctx, |_ui| {}); + egui::CentralPanel::default().show(ctx, |ui| { + let max_eyes = 100; + + while let Ok(eye) = self.eye_receiver.try_recv() { + self.eyes.push_back(eye); + } + + while self.eyes.len() > max_eyes { + self.eyes.pop_front(); + } + + Plot::new("Eye") + .legend(Legend::default()) + .show(ui, |plot_ui| { + //plot_ui.set_auto_bounds(Vec2b { x: false, y: false }); + for eye in self.eyes.iter() { + let line = Line::new( + "Eye", + eye.iter() + .enumerate() + .map(|(i, x)| [i as f64, *x as f64]) + .collect::>(), + ) + .color(Color32::LIGHT_GREEN); + plot_ui.line(line); + } + }); + }); } }