|
|
|
|
@ -12,6 +12,7 @@ mod ted;
|
|
|
|
|
mod units;
|
|
|
|
|
mod windows;
|
|
|
|
|
|
|
|
|
|
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
|
|
|
|
|
use egui_plot::{Legend, Line, Plot};
|
|
|
|
|
use hound::WavWriter;
|
|
|
|
|
use rand::{Rng, rand_core::le, seq::index::sample};
|
|
|
|
|
@ -19,13 +20,22 @@ use std::{
|
|
|
|
|
cell::{Cell, RefCell},
|
|
|
|
|
collections::VecDeque,
|
|
|
|
|
env::{self, args},
|
|
|
|
|
fmt::Display,
|
|
|
|
|
fs::File,
|
|
|
|
|
io::{BufWriter, Sink, Write, stdout},
|
|
|
|
|
io::{BufWriter, Read, Sink, Write, stdout},
|
|
|
|
|
ops::DerefMut,
|
|
|
|
|
sync::Arc,
|
|
|
|
|
sync::{Arc, atomic::AtomicU64, mpsc::RecvTimeoutError},
|
|
|
|
|
time::Duration,
|
|
|
|
|
u64,
|
|
|
|
|
};
|
|
|
|
|
use tokio::{
|
|
|
|
|
io::{self, AsyncReadExt, AsyncWriteExt},
|
|
|
|
|
join,
|
|
|
|
|
net::{TcpSocket, TcpStream, UdpSocket},
|
|
|
|
|
select,
|
|
|
|
|
sync::mpsc::{UnboundedSender, error::TryRecvError, unbounded_channel},
|
|
|
|
|
time::timeout,
|
|
|
|
|
};
|
|
|
|
|
use tokio::{join, net::UdpSocket, select, sync::mpsc::error::TryRecvError, time::timeout};
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
bfsk::BFSKMod,
|
|
|
|
|
@ -33,20 +43,23 @@ use crate::{
|
|
|
|
|
filtering::{dc_block::DCBlocker, fir::FIRFilter},
|
|
|
|
|
iq::IQSampler,
|
|
|
|
|
nco::Nco,
|
|
|
|
|
squelch::Squelch,
|
|
|
|
|
ted::elg::ELGate,
|
|
|
|
|
units::frequency::hz_to_rad_per_sample,
|
|
|
|
|
};
|
|
|
|
|
use eframe::egui::{self, CentralPanel, Color32, debug_text::print};
|
|
|
|
|
use eframe::egui::{self, CentralPanel, Color32, RichText};
|
|
|
|
|
use tokio::sync::RwLock;
|
|
|
|
|
use tokio::sync::mpsc::{Receiver, Sender, channel};
|
|
|
|
|
|
|
|
|
|
const BAUD_RATE: u32 = 1000;
|
|
|
|
|
const BAUD_RATE: u32 = 1200;
|
|
|
|
|
const SAMPLE_RATE: u32 = 48000;
|
|
|
|
|
|
|
|
|
|
// Modulation parameters
|
|
|
|
|
const CENTER_FREQ: f32 = 1700.;
|
|
|
|
|
const DEVIATION: f32 = 500.;
|
|
|
|
|
|
|
|
|
|
static mut INSTANCE_ID: u32 = 0;
|
|
|
|
|
|
|
|
|
|
pub enum SampleSenderCommand {
|
|
|
|
|
Open,
|
|
|
|
|
Close,
|
|
|
|
|
@ -94,11 +107,97 @@ impl SampleSender for WavSampleSender {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct FSKReceiver {
|
|
|
|
|
eye_sender: Sender<Vec<f32>>,
|
|
|
|
|
phase_lowpass: FIRFilter,
|
|
|
|
|
elg: ELGate,
|
|
|
|
|
last_byte: u8,
|
|
|
|
|
frame_constructor: FrameConstructor,
|
|
|
|
|
bit_count: Option<u32>,
|
|
|
|
|
last_sample: Complex32,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FSKReceiver {
|
|
|
|
|
fn new(eye_sender: Sender<Vec<f32>>) -> Self {
|
|
|
|
|
let samples_per_symbol = (SAMPLE_RATE as f32) / (BAUD_RATE as f32);
|
|
|
|
|
|
|
|
|
|
let mut phase_lowpass = FIRFilter::new(&vec![
|
|
|
|
|
Complex32::new(1., 0.);
|
|
|
|
|
samples_per_symbol as usize / 2
|
|
|
|
|
]);
|
|
|
|
|
phase_lowpass.normalize_dc();
|
|
|
|
|
//let mut dc_block = DCBlocker::new(0.999);
|
|
|
|
|
//let mut dc_block = DCBlocker::new(1.);
|
|
|
|
|
|
|
|
|
|
let loop_i = 0.03;
|
|
|
|
|
let loop_p = 0.1;
|
|
|
|
|
let mut loop_ir = vec![Complex32::new(loop_i, 0.); samples_per_symbol as usize / 2];
|
|
|
|
|
loop_ir.push(Complex32::new(loop_p, 0.));
|
|
|
|
|
let elg = ELGate::new(samples_per_symbol, FIRFilter::new(&loop_ir));
|
|
|
|
|
Self {
|
|
|
|
|
//iq_sampler: IQSampler::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32)),
|
|
|
|
|
phase_lowpass,
|
|
|
|
|
elg,
|
|
|
|
|
last_byte: 0x00u8,
|
|
|
|
|
frame_constructor: FrameConstructor::new(),
|
|
|
|
|
bit_count: None,
|
|
|
|
|
eye_sender,
|
|
|
|
|
last_sample: Complex32::new(1., 0.),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn receive(&mut self, iq: Complex32) -> Result<Option<Frame>, FrameConstructionError> {
|
|
|
|
|
// Frame reconstruction
|
|
|
|
|
let dphi = self
|
|
|
|
|
.phase_lowpass
|
|
|
|
|
.next_real((self.last_sample * iq.conj()).arg());
|
|
|
|
|
self.last_sample = iq;
|
|
|
|
|
if let Some((bit_sample, eye)) = self.elg.next_eye(dphi) {
|
|
|
|
|
let _ = self.eye_sender.send(eye).await;
|
|
|
|
|
self.last_byte >>= 1;
|
|
|
|
|
self.last_byte |= ((bit_sample > 0.) as u8) << 7;
|
|
|
|
|
//last_byte <<= 1;
|
|
|
|
|
//last_byte |= ((bit_sample < 0.) as u8);
|
|
|
|
|
self.bit_count = self.bit_count.map(|x| x + 1);
|
|
|
|
|
|
|
|
|
|
if let None = self.bit_count
|
|
|
|
|
&& self.last_byte == 0xD8
|
|
|
|
|
{
|
|
|
|
|
// Potential frame starts
|
|
|
|
|
self.last_byte = 0;
|
|
|
|
|
self.frame_constructor = FrameConstructor::new();
|
|
|
|
|
self.bit_count = Some(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(8) = self.bit_count {
|
|
|
|
|
let frame_opt = self.frame_constructor.add_byte(self.last_byte);
|
|
|
|
|
self.bit_count = Some(0);
|
|
|
|
|
//print!("{}", last_byte as char);
|
|
|
|
|
print!(".{:x}.", self.last_byte);
|
|
|
|
|
let _ = std::io::stdout().flush();
|
|
|
|
|
return frame_opt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ok(None);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
enum TransceiverState {
|
|
|
|
|
Waiting,
|
|
|
|
|
Receiving,
|
|
|
|
|
EOT,
|
|
|
|
|
SendingAck,
|
|
|
|
|
Sending,
|
|
|
|
|
Listening,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Transceiver {
|
|
|
|
|
tx_stream: Sender<Vec<u8>>,
|
|
|
|
|
rx_stream: Receiver<Vec<u8>>,
|
|
|
|
|
|
|
|
|
|
eye_receiver: Receiver<Vec<f32>>,
|
|
|
|
|
state_receiver: Receiver<TransceiverState>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Transceiver {
|
|
|
|
|
@ -118,159 +217,141 @@ impl Transceiver {
|
|
|
|
|
self.eye_receiver.try_recv()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn start(
|
|
|
|
|
mut sample_stream: Receiver<f32>,
|
|
|
|
|
mut sample_sender: Sender<SampleSenderCommand>,
|
|
|
|
|
) -> Self {
|
|
|
|
|
let (mut eyes_tx, eyes_rx) = channel::<Vec<f32>>(1024);
|
|
|
|
|
pub fn try_recv_state(&mut self) -> Result<TransceiverState, TryRecvError> {
|
|
|
|
|
self.state_receiver.try_recv()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let (rx_stream_sender, rx_stream_receiver) = channel::<Vec<u8>>(1024);
|
|
|
|
|
pub fn start(mut sample_stream: Receiver<f32>, mut sample_sender: Sender<Vec<f32>>) -> Self {
|
|
|
|
|
let mut resend: Option<Vec<u8>> = None;
|
|
|
|
|
let (mut eyes_tx, eyes_rx) = channel::<Vec<f32>>(1024);
|
|
|
|
|
let (mut state_tx, state_rx) = channel::<TransceiverState>(1024);
|
|
|
|
|
state_tx.try_send(TransceiverState::Waiting);
|
|
|
|
|
|
|
|
|
|
let (rx_stream_sender, mut rx_stream_receiver) = channel::<Vec<u8>>(1024);
|
|
|
|
|
let (tx_stream_sender, mut tx_stream_receiver) = channel::<Vec<u8>>(1024);
|
|
|
|
|
|
|
|
|
|
let receiving = Arc::new(RwLock::new(false));
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let squelch_sum = 0.;
|
|
|
|
|
loop {}
|
|
|
|
|
let mut squelch = Squelch::new(200, 0.1);
|
|
|
|
|
let mut iq_sampler =
|
|
|
|
|
IQSampler::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32));
|
|
|
|
|
|
|
|
|
|
let mut current_message = None;
|
|
|
|
|
loop {
|
|
|
|
|
select! {
|
|
|
|
|
_ = async {
|
|
|
|
|
while squelch.next(iq_sampler.sample(sample_stream.recv().await.unwrap())).is_none() {}
|
|
|
|
|
}
|
|
|
|
|
=>
|
|
|
|
|
{
|
|
|
|
|
state_tx.try_send(TransceiverState::Receiving);
|
|
|
|
|
// Wait for end of tranmission
|
|
|
|
|
let mut recv = Some(FSKReceiver::new(eyes_tx.clone()));
|
|
|
|
|
let mut send_ack = false;
|
|
|
|
|
while let Some(iq) = squelch.next(iq_sampler.sample(sample_stream.recv().await.unwrap()))
|
|
|
|
|
{
|
|
|
|
|
if recv.as_ref().is_some()
|
|
|
|
|
{
|
|
|
|
|
match recv.as_mut().unwrap().receive(iq).await
|
|
|
|
|
{
|
|
|
|
|
Ok(Some(Frame::Data(_))) => {println!("GOT DATA"); send_ack = true; recv = None; state_tx.try_send(TransceiverState::EOT);},
|
|
|
|
|
Ok(Some(Frame::Ack)) => {current_message = None; recv = None; state_tx.try_send(TransceiverState::EOT);},
|
|
|
|
|
Err(()) => {recv = None;},
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if send_ack
|
|
|
|
|
{
|
|
|
|
|
state_tx.try_send(TransceiverState::SendingAck);
|
|
|
|
|
Self::transmit(Frame::Ack, &mut sample_sender).await;
|
|
|
|
|
}
|
|
|
|
|
state_tx.try_send(TransceiverState::Waiting);
|
|
|
|
|
},
|
|
|
|
|
message = async
|
|
|
|
|
{
|
|
|
|
|
if current_message.is_none()
|
|
|
|
|
{
|
|
|
|
|
current_message = Some((tx_stream_receiver).recv().await.unwrap());
|
|
|
|
|
}
|
|
|
|
|
state_tx.try_send(TransceiverState::Listening);
|
|
|
|
|
tokio::time::sleep(Duration::from_millis(500 * rand::random_range(1..6))).await;
|
|
|
|
|
current_message.as_ref().unwrap()
|
|
|
|
|
} =>
|
|
|
|
|
{
|
|
|
|
|
state_tx.try_send(TransceiverState::Sending);
|
|
|
|
|
println!("Sending message");
|
|
|
|
|
Self::transmit(Frame::Data(message.clone()), &mut sample_sender).await;
|
|
|
|
|
//current_message = None;
|
|
|
|
|
println!("Sent message");
|
|
|
|
|
state_tx.try_send(TransceiverState::Waiting);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
eye_receiver: eyes_rx,
|
|
|
|
|
state_receiver: state_rx,
|
|
|
|
|
|
|
|
|
|
tx_stream: tx_stream_sender,
|
|
|
|
|
rx_stream: rx_stream_receiver,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async fn squelch_detector(sample_stream: &mut Receiver<f32>) {
|
|
|
|
|
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 {
|
|
|
|
|
let iq = iq_sampler.sample(smpl);
|
|
|
|
|
squelch_sum += iq.mag() / length as f32;
|
|
|
|
|
i += 1;
|
|
|
|
|
|
|
|
|
|
if i >= length {
|
|
|
|
|
if squelch_sum >= level {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
i = 0;
|
|
|
|
|
squelch_sum = 0.;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn transmit(frame: Frame, samples_sender: &mut Sender<SampleSenderCommand>) {
|
|
|
|
|
pub async fn transmit(frame: Frame, samples_sender: &mut Sender<Vec<f32>>) {
|
|
|
|
|
let bytes = frame.bytes();
|
|
|
|
|
let mut bit_stream = bytes.iter().flat_map(|x| byte_to_bits(*x));
|
|
|
|
|
let modulator = BFSKMod::new(
|
|
|
|
|
(SAMPLE_RATE as f32 / BAUD_RATE as f32).round() as u32,
|
|
|
|
|
hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32),
|
|
|
|
|
&mut bit_stream,
|
|
|
|
|
);
|
|
|
|
|
let data = bytes
|
|
|
|
|
.iter()
|
|
|
|
|
.flat_map(|x| byte_to_bits(*x))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
let up_lo = Nco::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32));
|
|
|
|
|
samples_sender.send(SampleSenderCommand::Open).await;
|
|
|
|
|
for (m, up) in modulator.zip(up_lo) {
|
|
|
|
|
let sample = m * up;
|
|
|
|
|
samples_sender
|
|
|
|
|
.send(SampleSenderCommand::Sample(sample.re))
|
|
|
|
|
.await;
|
|
|
|
|
}
|
|
|
|
|
samples_sender.send(SampleSenderCommand::Close).await;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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(|i| {
|
|
|
|
|
pos_nco.step();
|
|
|
|
|
pos_nco.cexp() * windows::blackmann(i as f32 / correllator_length as f32)
|
|
|
|
|
});
|
|
|
|
|
let neg_ir = (0..correllator_length).map(|i| {
|
|
|
|
|
neg_nco.step();
|
|
|
|
|
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 / 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.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.));
|
|
|
|
|
let mut elg = ELGate::new(samples_per_symbol, FIRFilter::new(&loop_ir));
|
|
|
|
|
|
|
|
|
|
// Frame reconstruction
|
|
|
|
|
let mut last_byte = 0x00u8;
|
|
|
|
|
let mut frame_constructor = FrameConstructor::new();
|
|
|
|
|
let mut bit_count: Option<u32> = None;
|
|
|
|
|
while let Some(sample) = sample_stream.recv().await {
|
|
|
|
|
let iq = iq_sampler.sample(sample);
|
|
|
|
|
let matched =
|
|
|
|
|
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 let None = bit_count
|
|
|
|
|
&& last_byte == 0xD8
|
|
|
|
|
{
|
|
|
|
|
// Potential frame starts
|
|
|
|
|
last_byte = 0;
|
|
|
|
|
frame_constructor = FrameConstructor::new();
|
|
|
|
|
bit_count = Some(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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(ref frame_data))) = frame_opt {
|
|
|
|
|
println!("Got data");
|
|
|
|
|
return Ok(Frame(frame_data.to_vec()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Err(()) = frame_opt {
|
|
|
|
|
// Erroneous frame
|
|
|
|
|
println!("Error");
|
|
|
|
|
return Err(());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let sample_per_symbols = SAMPLE_RATE / BAUD_RATE;
|
|
|
|
|
let bitstream = (0..(bytes.len() * 8 * sample_per_symbols as usize)).map(|i| {
|
|
|
|
|
if data[i / sample_per_symbols as usize] {
|
|
|
|
|
1.
|
|
|
|
|
} else {
|
|
|
|
|
-1.
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Synthesise impulse response
|
|
|
|
|
let mut impulse_response =
|
|
|
|
|
vec![Complex32::zero(); sample_per_symbols as usize].into_boxed_slice();
|
|
|
|
|
for (i, x) in impulse_response.iter_mut().enumerate() {
|
|
|
|
|
*x = Complex32::new(
|
|
|
|
|
windows::gaussian(0.3, i as f32 / sample_per_symbols as f32),
|
|
|
|
|
0.,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return Err(());
|
|
|
|
|
|
|
|
|
|
let mut gaussian_filter = FIRFilter::new(&impulse_response);
|
|
|
|
|
gaussian_filter.normalize_dc();
|
|
|
|
|
let filtered_bitstream = bitstream.map(|x| gaussian_filter.next_real(x));
|
|
|
|
|
|
|
|
|
|
let mut nco = Nco::new(0.);
|
|
|
|
|
let mut lo = Nco::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32));
|
|
|
|
|
|
|
|
|
|
// Generate passband
|
|
|
|
|
let samples = filtered_bitstream
|
|
|
|
|
.map(|f| {
|
|
|
|
|
nco.set_frequency(hz_to_rad_per_sample(f * DEVIATION, SAMPLE_RATE as f32));
|
|
|
|
|
nco.step_n(1);
|
|
|
|
|
lo.step_n(1);
|
|
|
|
|
(nco.cexp() * lo.cexp()).re
|
|
|
|
|
})
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
let len = samples.len();
|
|
|
|
|
samples_sender.send(samples).await.unwrap();
|
|
|
|
|
tokio::time::sleep(Duration::from_secs_f32(len as f32 / SAMPLE_RATE as f32)).await;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Frame(Vec<u8>);
|
|
|
|
|
enum Frame {
|
|
|
|
|
Data(Vec<u8>),
|
|
|
|
|
Ack,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type FrameConstructionError = ();
|
|
|
|
|
pub struct FrameConstructor {
|
|
|
|
|
@ -291,12 +372,17 @@ impl FrameConstructor {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn add_byte(&mut self, byte: u8) -> Result<Option<Frame>, FrameConstructionError> {
|
|
|
|
|
if self.frame.is_empty() && byte != 0x4C && !self.started {
|
|
|
|
|
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 && !self.started {
|
|
|
|
|
self.started = true;
|
|
|
|
|
return Ok(Some(Frame::Ack));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self.frame.is_empty() && byte == 0x4C && !self.started {
|
|
|
|
|
self.started = true;
|
|
|
|
|
return Ok(None);
|
|
|
|
|
@ -317,7 +403,9 @@ impl FrameConstructor {
|
|
|
|
|
if self.frame_countdown.unwrap() == 0 {
|
|
|
|
|
// All data has been received
|
|
|
|
|
if self.checksum == byte {
|
|
|
|
|
return Ok(Some(Frame(self.frame.iter().skip(2).copied().collect())));
|
|
|
|
|
return Ok(Some(Frame::Data(
|
|
|
|
|
self.frame.iter().skip(2).copied().collect(),
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
println!("Checksum failed");
|
|
|
|
|
@ -337,34 +425,51 @@ impl Frame {
|
|
|
|
|
let mut output_bytes = vec![];
|
|
|
|
|
|
|
|
|
|
// Initial training sequence
|
|
|
|
|
output_bytes.append(&mut vec![0b01010101; 64]);
|
|
|
|
|
output_bytes.append(&mut vec![0b01010101; 32]);
|
|
|
|
|
|
|
|
|
|
// Preamble byte
|
|
|
|
|
output_bytes.push(0xD8);
|
|
|
|
|
|
|
|
|
|
let x = &self.0;
|
|
|
|
|
assert!(x.len() < 65536, "Data size over MTU");
|
|
|
|
|
// Command
|
|
|
|
|
match self {
|
|
|
|
|
Frame::Data(x) => {
|
|
|
|
|
assert!(x.len() < 65536, "Data size over MTU");
|
|
|
|
|
|
|
|
|
|
output_bytes.push(0x4C); // DATA FRAME
|
|
|
|
|
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 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());
|
|
|
|
|
let mut checksum = 0u8;
|
|
|
|
|
x.iter().for_each(|x| checksum ^= x);
|
|
|
|
|
output_bytes.extend(x.iter());
|
|
|
|
|
|
|
|
|
|
output_bytes.push(checksum);
|
|
|
|
|
output_bytes.push(checksum);
|
|
|
|
|
}
|
|
|
|
|
Frame::Ack => {
|
|
|
|
|
output_bytes.push(0xC4); // ACK FRAME
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SEND EOT
|
|
|
|
|
output_bytes.extend(std::iter::repeat_n(4, 32));
|
|
|
|
|
output_bytes.extend(std::iter::repeat_n(4, 16));
|
|
|
|
|
output_bytes
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
|
async fn main() {
|
|
|
|
|
// Read instance
|
|
|
|
|
let id = std::env::args().collect::<Vec<_>>()[1]
|
|
|
|
|
.parse::<u32>()
|
|
|
|
|
.expect("NO INPUT ID");
|
|
|
|
|
assert!(id == 0 || id == 1);
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
INSTANCE_ID = id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//Transceiver::transmit(Frame::Data("Skibditoilet".repeat(100).bytes().collect::<Vec<_>>()), &mut WavSampleSender{}).await;
|
|
|
|
|
//Transceiver::transmit(Frame::Ack, &mut WavSampleSender::default()).await;
|
|
|
|
|
//return;
|
|
|
|
|
@ -388,99 +493,109 @@ impl SampleSender for DummySampleSender {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct EguiApp {
|
|
|
|
|
a_transceiver: Transceiver,
|
|
|
|
|
b_transceiver: Transceiver,
|
|
|
|
|
transceiver: Transceiver,
|
|
|
|
|
|
|
|
|
|
eyes_a: VecDeque<Vec<f32>>,
|
|
|
|
|
eyes_b: VecDeque<Vec<f32>>,
|
|
|
|
|
eyes: VecDeque<Vec<f32>>,
|
|
|
|
|
current_state: TransceiverState,
|
|
|
|
|
}
|
|
|
|
|
impl EguiApp {
|
|
|
|
|
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
|
|
|
|
|
let (up_a_sender, mut up_a_receiver) = channel::<SampleSenderCommand>(1024);
|
|
|
|
|
let (down_a_sender, down_a_receiver) = channel::<f32>(1024);
|
|
|
|
|
let (up_sender, mut up_receiver) = channel::<Vec<f32>>(16);
|
|
|
|
|
let (down_sender, down_receiver) = channel::<f32>(1024);
|
|
|
|
|
|
|
|
|
|
let (up_b_sender, mut up_b_receiver) = channel::<SampleSenderCommand>(1024);
|
|
|
|
|
let (down_b_sender, down_b_receiver) = channel::<f32>(1024);
|
|
|
|
|
let transceiver = Transceiver::start(down_receiver, up_sender);
|
|
|
|
|
|
|
|
|
|
let (a2b_tx, mut a2b_rx) = channel::<f32>(1024);
|
|
|
|
|
let (b2a_tx, mut b2a_rx) = channel::<f32>(1024);
|
|
|
|
|
let instance_id = unsafe { INSTANCE_ID };
|
|
|
|
|
tokio::task::spawn(async move {
|
|
|
|
|
println!("Waiting for connection ...");
|
|
|
|
|
|
|
|
|
|
let a_txrx = Transceiver::start(down_a_receiver, up_a_sender);
|
|
|
|
|
let b_txrx = Transceiver::start(down_b_receiver, up_b_sender);
|
|
|
|
|
// let socket = Arc::new(
|
|
|
|
|
// UdpSocket::bind(format!("0.0.0.0:{}", 9000 + instance_id))
|
|
|
|
|
// .await
|
|
|
|
|
// .unwrap(),
|
|
|
|
|
// );
|
|
|
|
|
// socket
|
|
|
|
|
// .connect(format!("127.0.0.1:{}", 9000 + (1 - instance_id)))
|
|
|
|
|
// .await
|
|
|
|
|
// .unwrap();
|
|
|
|
|
|
|
|
|
|
// A dummy channel
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
//let rng = rand::thread_rng();
|
|
|
|
|
let mut sending = false;
|
|
|
|
|
loop {
|
|
|
|
|
let noise = rand::random::<f32>() * 0.1;
|
|
|
|
|
let mut sample = 0.;
|
|
|
|
|
// Receiving end
|
|
|
|
|
let host = cpal::default_host();
|
|
|
|
|
|
|
|
|
|
match up_a_receiver.try_recv() {
|
|
|
|
|
Ok(SampleSenderCommand::Open) => {
|
|
|
|
|
sending = true;
|
|
|
|
|
println!("open");
|
|
|
|
|
}
|
|
|
|
|
Ok(SampleSenderCommand::Close) => {
|
|
|
|
|
sending = false;
|
|
|
|
|
println!("close");
|
|
|
|
|
}
|
|
|
|
|
Ok(SampleSenderCommand::Sample(x)) => {
|
|
|
|
|
sample = x;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
let device = host.default_input_device().expect("No input device");
|
|
|
|
|
let mut config = device
|
|
|
|
|
.supported_input_configs()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.next()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.with_sample_rate(cpal::SampleRate(48000));
|
|
|
|
|
|
|
|
|
|
if sending {
|
|
|
|
|
// Flush receiver buffer but ignore
|
|
|
|
|
while let Ok(_) = b2a_rx.try_recv() {}
|
|
|
|
|
let stream = device
|
|
|
|
|
.build_input_stream(
|
|
|
|
|
&config.into(),
|
|
|
|
|
move |data: &[f32], _| {
|
|
|
|
|
for x in data.iter() {
|
|
|
|
|
let _ = down_sender.blocking_send(*x * 30.); // non-blocking send
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
move |err| eprintln!("Stream error: {}", err),
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
stream.play().unwrap();
|
|
|
|
|
|
|
|
|
|
// Send to other
|
|
|
|
|
a2b_tx.send(sample + noise).await;
|
|
|
|
|
} else if let Ok(down_sample) = b2a_rx.try_recv() {
|
|
|
|
|
down_a_sender.send(down_sample).await;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
// B dummy channel
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let mut sending = false;
|
|
|
|
|
loop {
|
|
|
|
|
let noise = rand::random::<f32>() * 0.1;
|
|
|
|
|
let mut sample = 0.;
|
|
|
|
|
while let Some(stream) = up_receiver.recv().await {
|
|
|
|
|
let stream_len = stream.len();
|
|
|
|
|
let progression = Arc::new(AtomicU64::new(0));
|
|
|
|
|
let (finished_tx, mut finished_rx) = channel::<()>(16);
|
|
|
|
|
|
|
|
|
|
match up_b_receiver.try_recv() {
|
|
|
|
|
Ok(SampleSenderCommand::Open) => {
|
|
|
|
|
sending = true;
|
|
|
|
|
}
|
|
|
|
|
Ok(SampleSenderCommand::Close) => {
|
|
|
|
|
sending = false;
|
|
|
|
|
}
|
|
|
|
|
Ok(SampleSenderCommand::Sample(x)) => {
|
|
|
|
|
sample = x;
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
let send_stream = device
|
|
|
|
|
.build_output_stream(
|
|
|
|
|
&config,
|
|
|
|
|
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
|
|
|
|
|
for d in data.iter_mut() {
|
|
|
|
|
if progression.load(std::sync::atomic::Ordering::Relaxed) as usize
|
|
|
|
|
== stream.len()
|
|
|
|
|
{
|
|
|
|
|
let _ = finished_tx.blocking_send(());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if sending {
|
|
|
|
|
// Flush receiver buffer but ignore
|
|
|
|
|
while let Ok(_) = a2b_rx.try_recv() {}
|
|
|
|
|
|
|
|
|
|
// Send to other
|
|
|
|
|
b2a_tx.send(sample + noise).await;
|
|
|
|
|
} else if let Ok(down_sample) = a2b_rx.try_recv() {
|
|
|
|
|
down_b_sender.send(down_sample).await;
|
|
|
|
|
}
|
|
|
|
|
*d = stream[progression
|
|
|
|
|
.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
|
|
|
|
as usize]
|
|
|
|
|
* 0.1; // TODO
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
move |err| {
|
|
|
|
|
eprintln!("Stream error: {}", err);
|
|
|
|
|
},
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
.unwrap();
|
|
|
|
|
send_stream.play().unwrap();
|
|
|
|
|
let _ = finished_rx.recv().await;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
EguiApp {
|
|
|
|
|
a_transceiver: a_txrx,
|
|
|
|
|
b_transceiver: b_txrx,
|
|
|
|
|
transceiver,
|
|
|
|
|
|
|
|
|
|
eyes_a: VecDeque::new(),
|
|
|
|
|
eyes_b: VecDeque::new(),
|
|
|
|
|
eyes: VecDeque::new(),
|
|
|
|
|
current_state: TransceiverState::Waiting,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -490,73 +605,51 @@ impl eframe::App for EguiApp {
|
|
|
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
|
|
|
|
let max_eyes = 100;
|
|
|
|
|
|
|
|
|
|
while let Ok(eye) = self.a_transceiver.try_recv_eye() {
|
|
|
|
|
self.eyes_a.push_back(eye);
|
|
|
|
|
while let Ok(eye) = self.transceiver.try_recv_eye() {
|
|
|
|
|
self.eyes.push_back(eye);
|
|
|
|
|
}
|
|
|
|
|
while self.eyes_a.len() > max_eyes {
|
|
|
|
|
self.eyes_a.pop_front();
|
|
|
|
|
while self.eyes.len() > max_eyes {
|
|
|
|
|
self.eyes.pop_front();
|
|
|
|
|
}
|
|
|
|
|
if let Ok(new_state) = self.transceiver.try_recv_state() {
|
|
|
|
|
self.current_state = new_state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while let Ok(eye) = self.b_transceiver.try_recv_eye() {
|
|
|
|
|
self.eyes_b.push_back(eye);
|
|
|
|
|
}
|
|
|
|
|
while self.eyes_b.len() > max_eyes {
|
|
|
|
|
self.eyes_b.pop_front();
|
|
|
|
|
}
|
|
|
|
|
ui.horizontal(|ui| {
|
|
|
|
|
if ui.button("Start").clicked() {
|
|
|
|
|
let snd = self.transceiver.get_sender();
|
|
|
|
|
let data = (0..rand::random_range(50..250))
|
|
|
|
|
.map(|_| rand::random::<char>() as u8)
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
ui.columns(2, |uis| {
|
|
|
|
|
Plot::new("EyeA")
|
|
|
|
|
.legend(Legend::default())
|
|
|
|
|
.show(&mut uis[0], |plot_ui| {
|
|
|
|
|
//plot_ui.set_auto_bounds(Vec2b { x: false, y: false });
|
|
|
|
|
for eye in self.eyes_a.iter() {
|
|
|
|
|
let line = Line::new(
|
|
|
|
|
"EyeA",
|
|
|
|
|
eye.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, x)| [i as f64, *x as f64])
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
)
|
|
|
|
|
.color(Color32::LIGHT_GREEN);
|
|
|
|
|
plot_ui.line(line);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if uis[0].button("Start").clicked() {
|
|
|
|
|
let snd = self.a_transceiver.get_sender();
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let _ = snd
|
|
|
|
|
.send("Skibditoilet".repeat(10).as_bytes().to_vec())
|
|
|
|
|
.await;
|
|
|
|
|
let _ = snd.send(data).await;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Plot::new("EyeB")
|
|
|
|
|
.legend(Legend::default())
|
|
|
|
|
.show(&mut uis[1], |plot_ui| {
|
|
|
|
|
//plot_ui.set_auto_bounds(Vec2b { x: false, y: false });
|
|
|
|
|
for eye in self.eyes_b.iter() {
|
|
|
|
|
let line = Line::new(
|
|
|
|
|
"EyeB",
|
|
|
|
|
eye.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, x)| [i as f64, *x as f64])
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
)
|
|
|
|
|
.color(Color32::LIGHT_GREEN);
|
|
|
|
|
plot_ui.line(line);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if uis[1].button("Start").clicked() {
|
|
|
|
|
let snd = self.b_transceiver.get_sender();
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let _ = snd
|
|
|
|
|
.send("Skibditoilet".repeat(10).as_bytes().to_vec())
|
|
|
|
|
.await;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
ui.label(
|
|
|
|
|
RichText::new(format!("{:?}", self.current_state))
|
|
|
|
|
.size(35.)
|
|
|
|
|
.color(Color32::LIGHT_GREEN),
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Plot::new("EyeA")
|
|
|
|
|
.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(
|
|
|
|
|
"EyeA",
|
|
|
|
|
eye.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, x)| [i as f64, *x as f64])
|
|
|
|
|
.collect::<Vec<_>>(),
|
|
|
|
|
)
|
|
|
|
|
.color(Color32::LIGHT_GREEN);
|
|
|
|
|
plot_ui.line(line);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}); // Central panel
|
|
|
|
|
|
|
|
|
|
std::thread::sleep(Duration::from_millis(16));
|
|
|
|
|
|