transceiver
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -3330,6 +3330,18 @@ dependencies = [
|
||||
"mio",
|
||||
"pin-project-lite",
|
||||
"slab",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -10,4 +10,4 @@ egui_plot = "0.33.0"
|
||||
hound = "3.5.1"
|
||||
plotters = "0.3.7"
|
||||
rand = "0.9.2"
|
||||
tokio = "1.47.1"
|
||||
tokio = { version = "1.47.1", features = ["macros", "sync", "time"] }
|
||||
|
||||
525
main.rs
525
main.rs
@ -1,525 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
f32::consts::PI,
|
||||
fs::File,
|
||||
i16,
|
||||
io::{self, Read, Write, stdout},
|
||||
ops::{Add, Div, Mul, Sub},
|
||||
os::unix::thread,
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicU32, Ordering},
|
||||
mpsc::{self, Receiver, Sender, TryRecvError, channel, sync_channel},
|
||||
},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
mod bfsk;
|
||||
mod complex;
|
||||
pub mod fft;
|
||||
mod filtering;
|
||||
mod iq;
|
||||
mod nco;
|
||||
mod units;
|
||||
mod windows;
|
||||
mod ted;
|
||||
|
||||
use bfsk::BFSKMod;
|
||||
use complex::Complex;
|
||||
use complex::Complex32;
|
||||
use cpal::{
|
||||
SampleRate,
|
||||
traits::{DeviceTrait, HostTrait, StreamTrait},
|
||||
};
|
||||
use fft::DFTAlgorithm;
|
||||
use nco::Nco;
|
||||
|
||||
use eframe::{
|
||||
egui::{self, Color32, Context, Vec2b, debug_text::print, decode_animated_image_uri},
|
||||
glow::TOP_LEVEL_ARRAY_STRIDE,
|
||||
};
|
||||
use egui_plot::{
|
||||
self, AxisHints, Bar, BarChart, HLine, Legend, Line, LineStyle, Plot, PlotPoints, VLine,
|
||||
};
|
||||
use plotters::style::Color;
|
||||
use rand::{Rng, seq::index::sample};
|
||||
|
||||
use crate::{
|
||||
bfsk::BFSKDem, fft::{dft::NaiveDFT, FFT}, filtering::{
|
||||
dc_block::DCBlocker,
|
||||
fir::FIRFilter,
|
||||
impulse_response::design::{self, frequency_response, ir_from_transfer_function},
|
||||
}, iq::IQSampler, ted::elg::ELGate, units::frequency::{self, hz_to_rad_per_sample}
|
||||
};
|
||||
|
||||
// Utilities
|
||||
fn map<T>(input: T, in_min: T, in_max: T, out_min: T, out_max: T) -> T
|
||||
where
|
||||
T: Clone + Add<Output = T> + Mul<Output = T> + Sub<Output = T> + Div<Output = T>,
|
||||
{
|
||||
((input - in_min.clone()) / (in_max - in_min)) * (out_max - out_min.clone()) + out_min
|
||||
}
|
||||
const BAUD_RATE: u32 = 1000;
|
||||
|
||||
fn main() {
|
||||
//modulate();
|
||||
//demodulate();
|
||||
//return;
|
||||
// Set up CPAL
|
||||
let host = cpal::default_host();
|
||||
|
||||
let device = host
|
||||
.default_input_device()
|
||||
.expect("No input device available");
|
||||
let mut config = device
|
||||
.supported_input_configs()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap()
|
||||
.with_sample_rate(SampleRate(48000));
|
||||
|
||||
// Channel to move samples from callback to main thread
|
||||
let (tx, rx) = sync_channel::<f32>(4096);
|
||||
|
||||
// Build input stream
|
||||
/*
|
||||
let stream = device
|
||||
.build_input_stream(
|
||||
&config.into(),
|
||||
move |data: &[f32], _| {
|
||||
for x in data.iter() {
|
||||
let _ = tx.send(*x * 30.); // non-blocking send
|
||||
}
|
||||
},
|
||||
move |err| eprintln!("Stream error: {}", err),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
stream.play().unwrap();
|
||||
*/
|
||||
|
||||
let (eye_tx, eye_rx) = mpsc::channel::<Vec<f32>>();
|
||||
let (ctx_tx, ctx_rx) = mpsc::channel::<Arc<egui::Context>>();
|
||||
std::thread::spawn(move || demodulator(rx, eye_tx, ctx_rx));
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let spec = hound::WavSpec {
|
||||
channels: 1,
|
||||
sample_rate: 48000,
|
||||
bits_per_sample: 16,
|
||||
sample_format: hound::SampleFormat::Int,
|
||||
};
|
||||
|
||||
let mut writer = hound::WavWriter::create("audio/noised.wav", spec).unwrap();
|
||||
|
||||
let mut reader = hound::WavReader::open("audio/rec.wav").unwrap();
|
||||
let mut rand = rand::rng();
|
||||
let samples = reader.samples::<i16>();
|
||||
for x in samples {
|
||||
let noise = rand.random::<f32>() * 2. - 1.;
|
||||
let sample = x.unwrap() as f32 / i16::MAX as f32 + noise * 0.9;
|
||||
let _ = tx.send(sample);
|
||||
writer
|
||||
.write_sample((sample * i16::MAX as f32) as i16)
|
||||
.unwrap();
|
||||
std::thread::sleep(Duration::from_micros(21));
|
||||
}
|
||||
writer.finalize().unwrap();
|
||||
});
|
||||
|
||||
let native_options = eframe::NativeOptions::default();
|
||||
let _ = eframe::run_native(
|
||||
"Egui",
|
||||
native_options,
|
||||
Box::new(|cc| Ok(Box::new(EguiApp::new(cc, eye_rx, ctx_tx)))),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
fn demodulator(
|
||||
rx: Receiver<f32>,
|
||||
eye_sender: Sender<Vec<f32>>,
|
||||
ctx_rx: Receiver<Arc<egui::Context>>,
|
||||
) {
|
||||
// Wait for egui context to request redraw
|
||||
let ctx = ctx_rx.recv().unwrap();
|
||||
|
||||
// Modulation parameters
|
||||
let frequency = 1700.;
|
||||
let deviation = 500.;
|
||||
|
||||
// Data parameters
|
||||
let sample_rate = 48000;
|
||||
let baud_rate = BAUD_RATE;
|
||||
let sample_per_symbol = sample_rate / baud_rate;
|
||||
|
||||
let mut iq_sampler = IQSampler::new(hz_to_rad_per_sample(frequency, sample_rate as f32));
|
||||
|
||||
// Corellators
|
||||
let mut nco_pos = Nco::new(hz_to_rad_per_sample(deviation, sample_rate as f32));
|
||||
let mut nco_neg = Nco::new(hz_to_rad_per_sample(-deviation, sample_rate as f32));
|
||||
let corellator_length = (sample_per_symbol as f32 * 1.5) as usize;
|
||||
let corellator_pos = (0..corellator_length)
|
||||
.map(|i| {
|
||||
nco_pos.step();
|
||||
nco_pos.cexp() * windows::blackmann(i as f32 / (corellator_length as f32))
|
||||
//nco_pos.cexp()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let corellator_neg = (0..corellator_length)
|
||||
.map(|i| {
|
||||
nco_neg.step();
|
||||
nco_neg.cexp() * windows::blackmann(i as f32 / (corellator_length as f32))
|
||||
//nco_neg.cexp()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut matched_filter_pos = FIRFilter::new(&corellator_pos);
|
||||
let mut matched_filter_neg = FIRFilter::new(&corellator_neg);
|
||||
matched_filter_pos.normalize_freq(hz_to_rad_per_sample(deviation,sample_rate as f32));
|
||||
matched_filter_neg.normalize_freq(hz_to_rad_per_sample(deviation,sample_rate as f32));
|
||||
|
||||
let loop_p = 0.003;
|
||||
let loop_i = 0.001;
|
||||
let mut matched_filter = FIRFilter::new(&[Complex32::new(1., 0.); 20]);
|
||||
matched_filter.normalize_dc();
|
||||
|
||||
let mut loop_filter_ir = vec![Complex32::new(loop_i, 0.); 30];
|
||||
let len = loop_filter_ir.len();
|
||||
//loop_filter_ir[0] = Complex32::new(loop_p + loop_i, 0.);
|
||||
loop_filter_ir[len - 1] = Complex32::new(loop_p + loop_i, 0.);
|
||||
|
||||
let mut loop_filter = FIRFilter::new(&loop_filter_ir);
|
||||
//loop_filter.normalize_dc();
|
||||
//loop_filter.normalize_sum();
|
||||
let mut elg = ELGate::new(sample_per_symbol as f32, loop_filter);
|
||||
|
||||
let mut dc_blocker = DCBlocker::new(0.999);
|
||||
|
||||
// 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);
|
||||
|
||||
// Perform corellation
|
||||
let neg_energy = matched_filter_neg.next(iq);
|
||||
let pos_energy = matched_filter_pos.next(iq);
|
||||
|
||||
let matched =
|
||||
matched_filter.next_real(dc_blocker.next_real(pos_energy.mag() - neg_energy.mag()));
|
||||
|
||||
if let Some((elg_sample, eye)) = elg.next_eye(matched) {
|
||||
let _ = eye_sender.send(eye);
|
||||
ctx.request_repaint();
|
||||
|
||||
//last >>= 1;
|
||||
//last |= (!bit as u8) << 7;
|
||||
let bit = elg_sample > 0.;
|
||||
if elg_sample * elg_sample > 0.005 {
|
||||
last >>= 1;
|
||||
last |= (bit as u8) << 7;
|
||||
//last <<= 1;
|
||||
//last |= ((bit) as u8);
|
||||
|
||||
if preamble_count >= 2 {
|
||||
bit_index += 1;
|
||||
if bit_index >= 8 {
|
||||
if last == 4 {
|
||||
print!(" -- EOT");
|
||||
println!();
|
||||
preamble_count = 0;
|
||||
bit_index = 0;
|
||||
last = 0;
|
||||
} else {
|
||||
print!("{}", last as char);
|
||||
bit_index = 0;
|
||||
let _ = stdout().flush();
|
||||
}
|
||||
}
|
||||
} else if last == 0xD8 {
|
||||
preamble_count += 1;
|
||||
if preamble_count == 2 {
|
||||
println!("Incoming: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#[derive(Default)]
|
||||
struct EguiApp {
|
||||
eye_rx: Receiver<Vec<f32>>,
|
||||
eyes: VecDeque<Vec<f32>>,
|
||||
}
|
||||
|
||||
impl EguiApp {
|
||||
fn new(
|
||||
cc: &eframe::CreationContext<'_>,
|
||||
eye_rx: Receiver<Vec<f32>>,
|
||||
ctx_tx: Sender<Arc<egui::Context>>,
|
||||
) -> Self {
|
||||
ctx_tx.send(Arc::new(cc.egui_ctx.clone())).unwrap();
|
||||
|
||||
Self {
|
||||
eye_rx,
|
||||
eyes: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for EguiApp {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
let max_eyes = 100;
|
||||
|
||||
while let Ok(eye) = self.eye_rx.try_recv() {
|
||||
self.eyes.push_back(eye);
|
||||
}
|
||||
|
||||
while self.eyes.len() > max_eyes {
|
||||
self.eyes.pop_front();
|
||||
}
|
||||
|
||||
let axis_hints = AxisHints::new_x().min_thickness(2.);
|
||||
|
||||
Plot::new("Eye")
|
||||
.legend(Legend::default())
|
||||
.show_axes(Vec2b::TRUE)
|
||||
.custom_x_axes(vec![axis_hints])
|
||||
.show(ui, |plot_ui| {
|
||||
//plot_ui.set_auto_bounds(Vec2b { x: false, y: false });
|
||||
plot_ui.hline(HLine::new("", 0.).color(Color32::DARK_RED).width(2.));
|
||||
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);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn demodulate() {
|
||||
let mut reader = hound::WavReader::open("audio/modulated.wav").unwrap();
|
||||
let samples = reader.samples::<i16>();
|
||||
|
||||
// Modulation parameters
|
||||
let frequency = 1700.;
|
||||
let deviation = 500.;
|
||||
|
||||
// Data parameters
|
||||
let sample_rate = 48000;
|
||||
let baud_rate = BAUD_RATE;
|
||||
let sample_per_symbol = sample_rate / baud_rate;
|
||||
|
||||
let mut iq_sampler = IQSampler::new(hz_to_rad_per_sample(frequency, sample_rate as f32));
|
||||
let iq = samples
|
||||
.map(|x| iq_sampler.sample(x.unwrap() as f32 / i16::MAX as f32))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut nco_pos = Nco::new(hz_to_rad_per_sample(deviation, sample_rate as f32));
|
||||
let mut nco_neg = Nco::new(hz_to_rad_per_sample(-deviation, sample_rate as f32));
|
||||
let corellator_pos = (0..(sample_per_symbol * 1))
|
||||
.map(|_| {
|
||||
nco_pos.step();
|
||||
nco_pos.cexp()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let corellator_neg = (0..(sample_per_symbol * 1))
|
||||
.map(|_| {
|
||||
nco_neg.step();
|
||||
nco_neg.cexp()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut matched_filter_pos = FIRFilter::new(&corellator_pos);
|
||||
let mut matched_filter_neg = FIRFilter::new(&corellator_neg);
|
||||
|
||||
let mut dem = vec![];
|
||||
|
||||
for x in &iq {
|
||||
let pos = matched_filter_pos.next(x.clone());
|
||||
let neg = matched_filter_neg.next(*x);
|
||||
dem.push(pos.mag() - neg.mag());
|
||||
}
|
||||
|
||||
// Symbol recovery
|
||||
|
||||
let mut bits = vec![];
|
||||
let delta = 0.5;
|
||||
let alpha = 0.01;
|
||||
let mut current_sps = sample_per_symbol as f32;
|
||||
let mut current_position = current_sps / 2.;
|
||||
|
||||
while current_position < dem.len() as f32 {
|
||||
// Sample before after
|
||||
let early_id = (current_position - (delta * current_sps)).max(0.).floor() as u32;
|
||||
let late_id = (current_position + (delta * current_sps)).max(0.).floor() as u32;
|
||||
if late_id as usize >= dem.len() {
|
||||
break;
|
||||
}
|
||||
let early = dem[early_id as usize];
|
||||
let late = dem[late_id as usize];
|
||||
let error = early * early - late * late;
|
||||
current_sps -= alpha * error;
|
||||
|
||||
bits.push(dem[current_position.floor() as usize] > 0.);
|
||||
|
||||
current_position += current_sps;
|
||||
}
|
||||
|
||||
//assert!(bits.len() % 8 == 0);
|
||||
|
||||
let mut out_file = File::create("out.txt").unwrap();
|
||||
let mut strip = 0;
|
||||
|
||||
let bit_slice = bits.as_slice();
|
||||
for i in 0..100 {
|
||||
let byte = bits_to_byte(&bit_slice[(i as usize)..(i as usize + 8)]);
|
||||
if byte == 0b01010111u8 {
|
||||
strip = i + 8;
|
||||
}
|
||||
}
|
||||
|
||||
for i in 0..strip {
|
||||
bits.remove(i as usize);
|
||||
}
|
||||
for x in bits.chunks(8) {
|
||||
if x.len() != 8 {
|
||||
break;
|
||||
}
|
||||
out_file.write_all(&[bits_to_byte(x)]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn modulate() {
|
||||
// Modulation parameters
|
||||
let frequency = 1700.;
|
||||
let deviation = 500.;
|
||||
|
||||
// Data parameter
|
||||
let sample_rate = 48000;
|
||||
let baud_rate = BAUD_RATE;
|
||||
|
||||
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();
|
||||
|
||||
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, 64)
|
||||
.chain(std::iter::repeat_n(0xD8, 2))
|
||||
.chain(buffer.bytes())
|
||||
.chain(std::iter::repeat_n(4u8, 32))
|
||||
.flat_map(byte_to_bits);
|
||||
|
||||
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::<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;
|
||||
}
|
||||
*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();
|
||||
}
|
||||
}
|
||||
|
||||
fn byte_to_bits(byte: u8) -> Vec<bool> {
|
||||
vec![
|
||||
byte & 1 == 1,
|
||||
(byte >> 1) & 1 == 1,
|
||||
(byte >> 2) & 1 == 1,
|
||||
(byte >> 3) & 1 == 1,
|
||||
(byte >> 4) & 1 == 1,
|
||||
(byte >> 5) & 1 == 1,
|
||||
(byte >> 6) & 1 == 1,
|
||||
(byte >> 7) & 1 == 1,
|
||||
]
|
||||
}
|
||||
|
||||
/*
|
||||
fn bits_to_byte(bits: &[bool]) -> u8 {
|
||||
bits[7] as u8 |
|
||||
bits[6] as u8 >> 1 |
|
||||
bits[5] as u8 >> 2 |
|
||||
bits[4] as u8 >> 3 |
|
||||
bits[3] as u8 >> 4 |
|
||||
bits[2] as u8 >> 5 |
|
||||
bits[1] as u8 >> 6 |
|
||||
bits[0] as u8 >> 7
|
||||
}
|
||||
*/
|
||||
|
||||
fn bits_to_byte(bits: &[bool]) -> u8 {
|
||||
bits[0] as u8
|
||||
| (bits[1] as u8) << 1
|
||||
| (bits[2] as u8) << 2
|
||||
| (bits[3] as u8) << 3
|
||||
| (bits[4] as u8) << 4
|
||||
| (bits[5] as u8) << 5
|
||||
| (bits[6] as u8) << 6
|
||||
| (bits[7] as u8) << 7
|
||||
}
|
||||
110
out.csv
110
out.csv
@ -1,110 +0,0 @@
|
||||
0.38777804,
|
||||
0.5346923,
|
||||
0.955388,
|
||||
1.733541,
|
||||
5.2373223,
|
||||
45.05751,
|
||||
44.103336,
|
||||
4.6842055,
|
||||
1.8379081,
|
||||
0.87091005,
|
||||
0.5719485,
|
||||
0.35533598,
|
||||
0.27624997,
|
||||
0.19268566,
|
||||
0.16302158,
|
||||
0.121304035,
|
||||
0.10800954,
|
||||
0.08377376,
|
||||
0.077206604,
|
||||
0.061651066,
|
||||
0.058252066,
|
||||
0.047531676,
|
||||
0.045770597,
|
||||
0.037980493,
|
||||
0.037127394,
|
||||
0.031228758,
|
||||
0.03090615,
|
||||
0.026285518,
|
||||
0.026280245,
|
||||
0.022565575,
|
||||
0.02275963,
|
||||
0.019703189,
|
||||
0.020024413,
|
||||
0.01745844,
|
||||
0.017861607,
|
||||
0.015673414,
|
||||
0.01613357,
|
||||
0.014235352,
|
||||
0.014733706,
|
||||
0.013069027,
|
||||
0.013593689,
|
||||
0.01211653,
|
||||
0.012661362,
|
||||
0.011337315,
|
||||
0.011897493,
|
||||
0.010705299,
|
||||
0.011277529,
|
||||
0.010171418,
|
||||
0.010757942,
|
||||
0.00974708,
|
||||
0.010348838,
|
||||
0.009411645,
|
||||
0.010026283,
|
||||
0.009147926,
|
||||
0.009779742,
|
||||
0.008949807,
|
||||
0.00960072,
|
||||
0.008821197,
|
||||
0.009495176,
|
||||
0.008750506,
|
||||
0.009448569,
|
||||
0.008736015,
|
||||
0.009464292,
|
||||
0.008779442,
|
||||
0.009542818,
|
||||
0.008887626,
|
||||
0.009689722,
|
||||
0.009043873,
|
||||
0.009894198,
|
||||
0.00927059,
|
||||
0.010178313,
|
||||
0.009571863,
|
||||
0.010547835,
|
||||
0.009952907,
|
||||
0.011006483,
|
||||
0.010420783,
|
||||
0.011571476,
|
||||
0.0110045895,
|
||||
0.012267068,
|
||||
0.011714736,
|
||||
0.013115023,
|
||||
0.012580418,
|
||||
0.014148514,
|
||||
0.013637692,
|
||||
0.015413456,
|
||||
0.014933306,
|
||||
0.01697256,
|
||||
0.016537804,
|
||||
0.018906314,
|
||||
0.01854057,
|
||||
0.021339945,
|
||||
0.021077268,
|
||||
0.024448153,
|
||||
0.024345227,
|
||||
0.02848497,
|
||||
0.028632956,
|
||||
0.033848535,
|
||||
0.03441413,
|
||||
0.04118385,
|
||||
0.042437002,
|
||||
0.05156152,
|
||||
0.05403404,
|
||||
0.066911034,
|
||||
0.071660355,
|
||||
0.09098071,
|
||||
0.100297675,
|
||||
0.13183416,
|
||||
0.1515972,
|
||||
0.20976184,
|
||||
0.25736627,
|
||||
|
1
out.jpg
1
out.jpg
@ -1 +0,0 @@
|
||||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
3
out.txt
3
out.txt
@ -1,3 +0,0 @@
|
||||
<EFBFBD><EFBFBD>ibidi Toilet[1],[2] est une web-série[3] machinima, créée par Alexey Gerasimov et diffusée sur sa chaîne YouTube DaFuq!?Boom! Produite à l'aide de Source Filmmaker, la série suit une guerre fictive entre des toilettes à tête humaine et des personnages humanoïdes dotés d'appareils électroniques à la place de la tête.
|
||||
|
||||
<10> 8<>a<EFBFBD>9<10>0<10>:1<><31><EFBFBD>0<EFBFBD><30>77<10>:8<><38><EFBFBD><EFBFBD>29<32><39><EFBFBD>:9:<3A><><EFBFBD>T:<3A><><EFBFBD>2<EFBFBD>27<10><>T;<3B><>29<18><16><><EFBFBD>4<EFBFBD>4<EFBFBD>4<10><>4<EFBFBD>2:<10>2<EFBFBD><32>27:<3A>:7<><37>aԶ2<D4B6>$7<>29<32>2:<10>4<EFBFBD>06<30><36>:9<10>4<EFBFBD>2<EFBFBD>9<10><>Թ<EFBFBD><D4B9>:<<3C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:<<16>27<10>09<30><39><EFBFBD>:<3A><>29<32><39>:<3A><><EFBFBD>47<10>2<10>0<EFBFBD><30><EFBFBD>T<EFBFBD><54>T<EFBFBD>0<EFBFBD><30>77<37> 68<36>0<10><>9<EFBFBD>1<EFBFBD>4<EFBFBD><34><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD>77:<10>:<10>0<EFBFBD>9<EFBFBD><39>2:<3A>2<EFBFBD><32><EFBFBD>T<EFBFBD><54>2<10>08<><38><EFBFBD><EFBFBD>aT<61>2<EFBFBD>4<EFBFBD><34>:<3A><><EFBFBD>77<10>2<10>0<EFBFBD><30><EFBFBD>T<EFBFBD><54>T<EFBFBD>0<EFBFBD><30>77<37> 68<36>0<10>0<EFBFBD>9<10>0<EFBFBD><30>:6<>:<3A>2<EFBFBD>$7<>29<32>2:<16>27<32><37>7<EFBFBD><37>:9<>2<EFBFBD><32>2<EFBFBD>0<EFBFBD><30>1<10>0<EFBFBD><30><EFBFBD>T<EFBFBD><54>T<EFBFBD>0<EFBFBD><30>77-8<><38>9<EFBFBD>aѳ<61><D1B3>2<05><><<3C>7<EFBFBD><37><EFBFBD>9<EFBFBD><39><EFBFBD>4<EFBFBD>4<EFBFBD>4<10><>4<EFBFBD>2:<10><><EFBFBD>77<37>2<10><>9<EFBFBD><39>T<EFBFBD><54>T<EFBFBD><54><EFBFBD>27<32>9<10><>:<3A>2<EFBFBD><32><EFBFBD>29<32>2<10><>1<EFBFBD>4<EFBFBD>2<EFBFBD>27:<3A>2<10><>9<10><><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD>aP<10>aU<61>2<10>2<EFBFBD><32><EFBFBD><EFBFBD><EFBFBD>T<EFBFBD>0<10>2<10><>:<3A><16>09<30><39>:9<><39>:<10>2<10><>T<EFBFBD><54>T<EFBFBD><54><EFBFBD><EFBFBD>77<16>2:<10><>9<EFBFBD><39><EFBFBD>4<EFBFBD>4<EFBFBD>4<10><>4<EFBFBD>2<EFBFBD>9<16>:<3A>2<10><><EFBFBD>2<EFBFBD>2<:<3A>0<EFBFBD>29<32><39>9:<3A>28<>2<EFBFBD>07:6q<36><71>08<30>0<EFBFBD>2<EFBFBD><32>2<10>2<10><>4<EFBFBD>2:<3A><>9<EFBFBD>0<EFBFBD><30>1<10><>9<10>aU<61><55>9<10><13><><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD><39>:<10>2<10><><EFBFBD><EFBFBD><EFBFBD>9<EFBFBD>2:<10><><EFBFBD><EFBFBD>07:<3A><><EFBFBD>2<EFBFBD><32><EFBFBD><EFBFBD><EFBFBD>2<10>0<EFBFBD><30><EFBFBD><EFBFBD>2<10>2<10>U<EFBFBD><55><EFBFBD>4<EFBFBD>4<EFBFBD>4<10>]<10>4<EFBFBD><34><EFBFBD><EFBFBD><EFBFBD>9<10>09<10>2<EFBFBD><32><16><>4<EFBFBD>2:<14>2<EFBFBD><32>77<37><37><EFBFBD>2<EFBFBD>4<EFBFBD>9<EFBFBD>4<EFBFBD><34>T<10>:<3A><><EFBFBD><EFBFBD>07<10>0<EFBFBD>9<10>0<EFBFBD><30><EFBFBD>T<EFBFBD><54>2<10>2<10><>:<<10>4<EFBFBD><34>Է9<10>06<30><16>4<EFBFBD><34>-<2D><><16>4<EFBFBD>9<EFBFBD>77:<3A><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32>6<EFBFBD>4<EFBFBD><34>77<10>2<EFBFBD><32>7<EFBFBD><37><EFBFBD><EFBFBD>T<EFBFBD>49<10>0<10>29<32>2<16>27<32><37>T<EFBFBD><54><EFBFBD>4<EFBFBD>07:<10><>:<3A>2<EFBFBD>78<37><38><EFBFBD>4<EFBFBD><34>7<EFBFBD><37><EFBFBD>.<2E>-<2D>.<17><><16><>4<EFBFBD>2:<16><><EFBFBD>4<EFBFBD><34>9:<3A><><EFBFBD><EFBFBD>9<10><>9<EFBFBD>792<39><32>9<10><>9<EFBFBD><39>9:<3A><><16><>4<EFBFBD>2<EFBFBD>9<16><>0<10><><EFBFBD>2<10><>7<EFBFBD><37><EFBFBD>4<EFBFBD>2<EFBFBD><32><EFBFBD>4<EFBFBD><34>2:<3A><>:<3A>2<10>0<EFBFBD>9<10><><EFBFBD>9<EFBFBD><39><EFBFBD>2<10><>4:<3A><>7<EFBFBD><37><EFBFBD><EFBFBD>T<EFBFBD>49<10>0<10>29<32>2<EFBFBD>0<EFBFBD><30>1<10><>0<EFBFBD><30><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD><EFBFBD>46<34>0<EFBFBD>1<EFBFBD><31><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32>:9<10>29<32>2<10>4<EFBFBD>4<EFBFBD>0<10>09<10>292<39>2<EFBFBD><32>0<EFBFBD><30>77<37><37>0<EFBFBD><30>2<EFBFBD><32>:<<3C><>9:<3A><>9<10><>]<5D>aP<61><50>0<10><>T<EFBFBD><54>4<EFBFBD>2<EFBFBD>aP<10><><EFBFBD>T<EFBFBD><54><EFBFBD>7<EFBFBD>2<EFBFBD><32><1B>2:<3A>aP<61><50>0<10><>9<EFBFBD>:<3A>2<EFBFBD>aP<10><><EFBFBD>T<EFBFBD><54><EFBFBD>7<EFBFBD>2<18>0<EFBFBD><30>1<10><>9<10><>:<<3C><>76<37>0<EFBFBD>9<10><><EFBFBD>T<EFBFBD>4<EFBFBD>2<10><>9<EFBFBD><39>9:<3A><>9<17>a@<10>09<30>49<10>2<10><><EFBFBD>T<EFBFBD><54><EFBFBD>7<EFBFBD>2<EFBFBD><10><>9<EFBFBD><39>9:<3A><>9<EFBFBD>77:<3A><><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD>T<EFBFBD>aP<61>27<32>0<EFBFBD>49<10>0<10>29<32>2<10><>9<EFBFBD><39><EFBFBD>4<EFBFBD>4<EFBFBD>4<10><>4<EFBFBD>2<EFBFBD>9<EFBFBD>2:<10><>06<30><36>0<EFBFBD><30>2<10><>77:<10><><EFBFBD>::<3A>2<EFBFBD>1<EFBFBD><31>4<<3C><><EFBFBD>2<10>2<EFBFBD><32><EFBFBD>06<30><36>29<10><>:9<10><>4<EFBFBD>1<EFBFBD>2<10><>9<EFBFBD><39>9:<3A><>9
|
||||
267
src/main.rs
267
src/main.rs
@ -11,16 +11,198 @@ mod windows;
|
||||
mod ted;
|
||||
mod math;
|
||||
|
||||
use cpal::Data;
|
||||
use eframe::egui;
|
||||
|
||||
use std::{collections::VecDeque, time::Duration};
|
||||
use tokio::{join, select, time::timeout};
|
||||
|
||||
use eframe::{egui, glow::SAMPLE_MASK_VALUE};
|
||||
use tokio::sync::mpsc::{Receiver, Sender, channel};
|
||||
use crate::{bfsk::BFSKMod, complex::Complex32, filtering::{dc_block::DCBlocker, fir::FIRFilter}, iq::IQSampler, nco::Nco, ted::elg::ELGate, units::frequency::hz_to_rad_per_sample};
|
||||
|
||||
const BAUD_RATE: u32 = 1000;
|
||||
const SAMPLE_RATE: u32 = 48000;
|
||||
|
||||
enum TransceiverState
|
||||
// Modulation parameters
|
||||
const CENTER_FREQ: f32 = 1700.;
|
||||
const DEVIATION: f32 = 500.;
|
||||
|
||||
pub trait SampleSender
|
||||
{
|
||||
Idle,
|
||||
Receiving,
|
||||
Transmitting,
|
||||
fn open_link(&mut self);
|
||||
fn send_samples(&mut self, samples: &[f32]);
|
||||
fn close_link(&mut self);
|
||||
}
|
||||
|
||||
struct Transceiver
|
||||
{
|
||||
data_receiver: Receiver<Vec<u8>>,
|
||||
data_sender: Sender<Vec<u8>>,
|
||||
samples_sender: Sender<f32>,
|
||||
}
|
||||
|
||||
impl Transceiver
|
||||
{
|
||||
pub async fn start<T: SampleSender>(sample_sender: T) -> Self
|
||||
{
|
||||
let (transmitter_tx, transmitter_rx) = channel::<Vec<u8>>(4096);
|
||||
let (acknowledged_tx, acknowledged_rx) = channel::<()>(32);
|
||||
let (ack_tx, ack_rx) = channel::<()>(32);
|
||||
let (samples_tx, samples_rx) = channel::<f32>(4096);
|
||||
|
||||
let (receiver_tx, receiver_rx) = channel::<Vec<u8>>(4096);
|
||||
join!(
|
||||
Self::transmitter(acknowledged_rx, transmitter_rx, ack_rx, sample_sender),
|
||||
Self::receiver(acknowledged_tx, samples_rx, receiver_tx, ack_tx)
|
||||
);
|
||||
|
||||
Self
|
||||
{
|
||||
data_receiver: receiver_rx,
|
||||
data_sender: transmitter_tx,
|
||||
samples_sender: samples_tx
|
||||
}
|
||||
}
|
||||
|
||||
async fn transmitter<T: SampleSender>(mut acknowledged: Receiver<()>, mut data_receiver: Receiver<Vec<u8>>, mut ack_receiver: Receiver<()>, mut samples_sender: T)
|
||||
{
|
||||
let mut send_queue: VecDeque<Frame> = VecDeque::new();
|
||||
|
||||
loop
|
||||
{
|
||||
if !send_queue.is_empty()
|
||||
{
|
||||
let to_send = send_queue.pop_front().unwrap();
|
||||
|
||||
// Create modulation
|
||||
let bytes = to_send.bytes();
|
||||
let mut bit_stream = bytes.iter().flat_map(|x| byte_to_bits(*x));
|
||||
let mut 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 mut up_lo = Nco::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32));
|
||||
|
||||
let mut sample_buffer = vec![];
|
||||
for (m, up) in modulator.zip(up_lo)
|
||||
{
|
||||
let sample = m * up;
|
||||
sample_buffer.push(sample.re); // Project IQ
|
||||
}
|
||||
|
||||
samples_sender.open_link();
|
||||
samples_sender.send_samples(&sample_buffer);
|
||||
samples_sender.close_link();
|
||||
|
||||
if let Frame::Data(_) = to_send
|
||||
{
|
||||
// Wait for ack
|
||||
while !acknowledged.is_empty()
|
||||
{
|
||||
let _ = acknowledged.blocking_recv();
|
||||
}
|
||||
|
||||
let ack_timout = timeout(Duration::from_secs(2), acknowledged.recv()).await;
|
||||
if let Ok(Some(())) = ack_timout
|
||||
{
|
||||
// ACK Received : Ok
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try again
|
||||
send_queue.push_front(to_send);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
let new = select!
|
||||
{
|
||||
Some(x) = data_receiver.recv() => Frame::Data(x),
|
||||
Some(()) = ack_receiver.recv() => Frame::Ack,
|
||||
};
|
||||
|
||||
match new
|
||||
{
|
||||
Frame::Ack => send_queue.push_front(Frame::Ack), // Highest importance
|
||||
Frame::Data(x) => send_queue.push_back(Frame::Data(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn receiver(acknowledged: Sender<()>, mut samples: Receiver<f32>, data_sender: Sender<Vec<u8>>, ack_sender: Sender<()>)
|
||||
{
|
||||
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(|_| {pos_nco.step(); pos_nco.cexp()});
|
||||
let neg_ir = (0..correllator_length).map(|_| {neg_nco.step(); neg_nco.cexp()});
|
||||
let mut pos_correllator = FIRFilter::new(&pos_ir.collect::<Vec<_>>());
|
||||
let mut neg_correllator = FIRFilter::new(&neg_ir.collect::<Vec<_>>());
|
||||
|
||||
let mut matched_lowpass = FIRFilter::new(&vec![Complex32::new(1., 0.); samples_per_symbol as usize]);
|
||||
let mut dc_block = DCBlocker::new(0.995);
|
||||
|
||||
let loop_i = 0.1;
|
||||
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) = samples.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;
|
||||
bit_count = bit_count.map(|x| x + 1);
|
||||
|
||||
if 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);
|
||||
if let Ok(None) = frame_opt
|
||||
{
|
||||
bit_count = Some(0);
|
||||
}
|
||||
|
||||
if let Ok(Some(Frame::Ack)) = frame_opt
|
||||
{
|
||||
bit_count = None;
|
||||
acknowledged.send(()).await.unwrap(); // Send acknowledgement to transmitter
|
||||
}
|
||||
|
||||
if let Ok(Some(Frame::Data(ref frame_data))) = frame_opt
|
||||
{
|
||||
bit_count = None;
|
||||
data_sender.send(frame_data.to_vec()).await.unwrap();
|
||||
ack_sender.send(()).await.unwrap();
|
||||
}
|
||||
|
||||
if let Err(()) = frame_opt
|
||||
{
|
||||
bit_count = None; // Erroneous frame, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Frame
|
||||
@ -29,6 +211,76 @@ enum Frame
|
||||
Ack
|
||||
}
|
||||
|
||||
type FrameConstructionError = ();
|
||||
pub struct FrameConstructor
|
||||
{
|
||||
frame: Vec<u8>,
|
||||
frame_countdown: Option<u16>,
|
||||
checksum: u8,
|
||||
}
|
||||
|
||||
impl FrameConstructor
|
||||
{
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self
|
||||
{
|
||||
frame: Vec::new(),
|
||||
frame_countdown: None,
|
||||
checksum: 0u8,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_byte(&mut self, byte: u8) -> Result<Option<Frame>, FrameConstructionError>
|
||||
{
|
||||
if self.frame.is_empty() && byte != 0xC4 && byte != 0x4C
|
||||
{
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if self.frame.is_empty() && byte == 0xC4
|
||||
{
|
||||
return Ok(Some(Frame::Ack));
|
||||
}
|
||||
|
||||
if self.frame.is_empty() && byte == 0x4C
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
self.frame.push(byte);
|
||||
|
||||
// Retrieve length
|
||||
if self.frame.len() == 1
|
||||
{
|
||||
self.frame_countdown = Some(self.frame[0] as u16);
|
||||
return Ok(None);
|
||||
}
|
||||
if self.frame.len() == 2
|
||||
{
|
||||
*self.frame_countdown.as_mut().unwrap() |= (self.frame[1] as u16) << 8;
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if self.frame_countdown.unwrap() == 0
|
||||
{
|
||||
// All data has been received
|
||||
if self.checksum == byte
|
||||
{
|
||||
return Ok(Some(Frame::Data(self.frame.iter().skip(2).copied().collect())));
|
||||
}
|
||||
|
||||
return Err(());
|
||||
}
|
||||
|
||||
self.frame.push(byte);
|
||||
self.checksum ^= byte;
|
||||
*self.frame_countdown.as_mut().unwrap() -= 1;
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Frame
|
||||
{
|
||||
pub fn bytes(&self) -> Vec<u8>
|
||||
@ -51,6 +303,7 @@ impl Frame
|
||||
|
||||
assert!(x.len() < 65536, "Data size over MTU");
|
||||
let len_u16 = x.len() as u16;
|
||||
output_bytes.push(0x4C); // DATA FRAME
|
||||
output_bytes.push((len_u16 & 0xFF).try_into().unwrap());
|
||||
output_bytes.push(((len_u16 >> 8) & 0xFF).try_into().unwrap());
|
||||
|
||||
@ -60,7 +313,7 @@ impl Frame
|
||||
}
|
||||
Frame::Ack =>
|
||||
{
|
||||
output_bytes.push(0xC4);
|
||||
output_bytes.push(0xC4); // ACK FRAME
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user