Frame reception down
This commit is contained in:
209
src/main.rs
209
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<Vec<u8>>,
|
||||
mut rx_stream: Sender<Vec<u8>>,
|
||||
sample_sender: &mut T,
|
||||
mut eye_sender: Sender<Vec<f32>>
|
||||
) {
|
||||
let mut resend: Option<Vec<u8>> = 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<f32>) {
|
||||
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<T: SampleSender>(frame: Frame, samples_sender: &mut T) {
|
||||
pub async fn transmit<T: SampleSender>(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<f32>) -> Result<Frame, FrameConstructionError> {
|
||||
async fn receive(sample_stream: &mut Receiver<f32>, eye_sender: &mut Sender<Vec<f32>>) -> Result<Frame, FrameConstructionError> {
|
||||
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::<Vec<_>>());
|
||||
let mut neg_correllator = FIRFilter::new(&neg_ir.collect::<Vec<_>>());
|
||||
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<u8>,
|
||||
frame_countdown: Option<u16>,
|
||||
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<Option<Frame>, 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::<Vec<_>>()), &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<Vec<f32>>,
|
||||
eyes: VecDeque<Vec<f32>>
|
||||
}
|
||||
impl EguiApp {
|
||||
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
||||
let (eye_tx, mut eye_rx) = channel::<Vec<f32>>(1024);
|
||||
let (eye_red_tx, eye_red_rx) = channel::<Vec<f32>>(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::<f32>(1024);
|
||||
|
||||
let (transmit_tx, transmit_rx) = channel::<Vec<u8>>(1024);
|
||||
let (receive_tx, receive_rx) = channel::<Vec<u8>>(1024);
|
||||
let (receive_tx, mut receive_rx) = channel::<Vec<u8>>(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::<Vec<_>>(),
|
||||
)
|
||||
.color(Color32::LIGHT_GREEN);
|
||||
plot_ui.line(line);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user