Full encoding chain is working
This commit is contained in:
parent
39d4c602f4
commit
3d994125a1
|
@ -1,14 +1,183 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
||||
|
||||
[[package]]
|
||||
name = "libpulse-binding"
|
||||
version = "2.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35b35c3c377b537d044107ff0830b4e5ae32a5c106289977a04b3387a143e994"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libpulse-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libpulse-simple-binding"
|
||||
version = "2.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4ef3ce750cdbce60fc96aac1f6dad84d67419d2307a05a27b73700f1f5d33e0"
|
||||
dependencies = [
|
||||
"libpulse-binding",
|
||||
"libpulse-simple-sys",
|
||||
"libpulse-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libpulse-simple-sys"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a48e779375c1d6e8b8d2fcbca67cc2f3208d447f17215f8ea600d6a58ccc6a56"
|
||||
dependencies = [
|
||||
"libpulse-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libpulse-sys"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa9559e91871e5f820c3b4e181b8c8f3ebd0b7839c92943802caf0f1477fdc27"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab3e176191bc4faad357e3122c4747aa098ac880e88b168f106386128736cf4a"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05ad05bd8977050b171b3f6b48175fea6e0565b7981059b486075e1026a9fb5"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||
|
||||
[[package]]
|
||||
name = "rusty-dsp"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libpulse-binding",
|
||||
"libpulse-simple-binding",
|
||||
"num",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusty-tty"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"rusty-dsp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
|
@ -8,3 +8,4 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
lazy_static = "*"
|
||||
rusty-dsp = {path = "../rusty-dsp"}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
extern crate rusty_dsp;
|
||||
|
||||
use rusty_dsp::error::DspError;
|
||||
|
||||
const LETTERS: &[u8] = b"\0E\nA SIU\rDRJNFCKTZLWHYPQOBG\0MXV\0";
|
||||
const FIGURES: &[u8] = b"\03\n- \x0787\r\x054',!:(5\")2#6019?&\0./;\0";
|
||||
|
||||
|
@ -50,7 +54,7 @@ enum ShiftState {
|
|||
Figures,
|
||||
}
|
||||
|
||||
struct Encoder<'a> {
|
||||
pub struct Encoder<'a> {
|
||||
shift_state: ShiftState,
|
||||
buffer: Option<u8>,
|
||||
iterator: Box<dyn Iterator<Item = u8> + 'a>,
|
||||
|
@ -70,7 +74,7 @@ impl<'a> Encoder<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Iterator for Encoder<'a> {
|
||||
type Item = Result<u8, u8>;
|
||||
type Item = Result<u8, DspError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(c) = self.buffer {
|
||||
|
@ -108,17 +112,20 @@ impl<'a> Iterator for Encoder<'a> {
|
|||
|
||||
Some(Ok(SHIFT_FIGURES))
|
||||
}
|
||||
(None, None, _) => Some(Err(byte)),
|
||||
(None, None, _) => Some(Err(DspError::Error(format!(
|
||||
"Unable to decode symbol: {:?}",
|
||||
&byte
|
||||
)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(msg: &str) -> Result<Vec<u8>, u8> {
|
||||
pub fn encode(msg: &str) -> Result<Vec<u8>, DspError> {
|
||||
let encoder = Encoder::from(msg.to_ascii_uppercase().into_bytes().into_iter());
|
||||
encoder.collect()
|
||||
}
|
||||
|
||||
struct Decoder<'a> {
|
||||
pub struct Decoder<'a> {
|
||||
shift_state: ShiftState,
|
||||
iterator: Box<dyn Iterator<Item = u8> + 'a>,
|
||||
}
|
||||
|
@ -138,7 +145,7 @@ impl<'a> Decoder<'a> {
|
|||
impl<'a> Iterator for Decoder<'a> {
|
||||
// Option<Result<u8, u8>> for nice error handling if somebody wants to use collect
|
||||
// See https://doc.rust-lang.org/stable/rust-by-example/error/iter_result.html
|
||||
type Item = Result<u8, u8>;
|
||||
type Item = Result<u8, DspError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut byte = match self.iterator.next() {
|
||||
|
@ -167,18 +174,24 @@ impl<'a> Iterator for Decoder<'a> {
|
|||
match (byte, self.shift_state) {
|
||||
(c, ShiftState::Letters) => match letter_from_code(c) {
|
||||
Some(l) => Some(Ok(l)),
|
||||
None => Some(Err(c)),
|
||||
None => Some(Err(DspError::Error(format!(
|
||||
"Unable to decode symbol: {:?}",
|
||||
c
|
||||
)))),
|
||||
},
|
||||
(c, ShiftState::Figures) => match figure_from_code(c) {
|
||||
Some(f) => Some(Ok(f)),
|
||||
None => Some(Err(c)),
|
||||
None => Some(Err(DspError::Error(format!(
|
||||
"Unable to decode symbol: {:?}",
|
||||
c
|
||||
)))),
|
||||
},
|
||||
(_, ShiftState::None) => panic!("Shift state is expectedly None"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(msg: &[u8]) -> Result<String, u8> {
|
||||
pub fn decode(msg: &[u8]) -> Result<String, DspError> {
|
||||
let decoder = Decoder::from(msg.iter().copied());
|
||||
match decoder.collect() {
|
||||
Ok(v) => Ok(String::from_utf8(v).unwrap()),
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
extern crate rusty_dsp;
|
||||
|
||||
use rusty_dsp::error::DspError;
|
||||
|
||||
pub struct BitGenerator<'a> {
|
||||
bit_pos: usize,
|
||||
current_byte: u8,
|
||||
iterator: Box<dyn Iterator<Item = Result<u8, DspError>> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> BitGenerator<'a> {
|
||||
pub fn from<I>(iterator: I) -> BitGenerator<'a>
|
||||
where
|
||||
I: Iterator<Item = Result<u8, DspError>> + 'a,
|
||||
{
|
||||
BitGenerator {
|
||||
bit_pos: 0,
|
||||
current_byte: 0,
|
||||
iterator: Box::new(iterator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BitGenerator<'a> {
|
||||
type Item = Result<bool, DspError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.bit_pos == 0 {
|
||||
let byte = match self.iterator.next() {
|
||||
None => return None,
|
||||
Some(Err(e)) => return Some(Err(e)),
|
||||
Some(Ok(b)) => b,
|
||||
};
|
||||
|
||||
self.current_byte = 0b11000000 | (byte << 1);
|
||||
};
|
||||
|
||||
let bit = (self.current_byte & (1 << self.bit_pos)) != 0;
|
||||
self.bit_pos = (self.bit_pos + 1) % 8;
|
||||
|
||||
Some(Ok(bit))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_bitgenerator() {
|
||||
let input = vec![0b11111, 0b01010, 0b00000];
|
||||
|
||||
let generator = BitGenerator::from(input.into_iter().map(|x| Ok(x)));
|
||||
|
||||
let result_data: Result<Vec<bool>, DspError> = generator.collect();
|
||||
assert_eq!(
|
||||
result_data,
|
||||
Ok(vec![
|
||||
true, true, true, true, true, true, true, true, true, false, true, false, true,
|
||||
false, true, true, true, false, false, false, false, false, true, true
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
extern crate rusty_dsp;
|
||||
|
||||
use rusty_dsp::error::DspError;
|
||||
|
||||
pub struct BitUpsampler<'a> {
|
||||
bit_length: f64,
|
||||
current_bit_length: usize,
|
||||
pos: usize,
|
||||
residual_error: f64,
|
||||
current_bit: bool,
|
||||
iterator: Box<dyn Iterator<Item = Result<bool, DspError>> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> BitUpsampler<'a> {
|
||||
pub fn from<I>(iterator: I, sampling_rate: f64, baud_rate: f64) -> BitUpsampler<'a>
|
||||
where
|
||||
I: Iterator<Item = Result<bool, DspError>> + 'a,
|
||||
{
|
||||
BitUpsampler {
|
||||
bit_length: sampling_rate / baud_rate,
|
||||
current_bit_length: 0,
|
||||
residual_error: 0.0,
|
||||
pos: 0,
|
||||
current_bit: false,
|
||||
iterator: Box::new(iterator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BitUpsampler<'a> {
|
||||
type Item = Result<bool, DspError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.pos >= self.current_bit_length {
|
||||
self.current_bit = match self.iterator.next() {
|
||||
None => return None,
|
||||
Some(Err(e)) => return Some(Err(e)),
|
||||
Some(Ok(b)) => b,
|
||||
};
|
||||
|
||||
self.current_bit_length = self.bit_length.floor() as usize;
|
||||
self.residual_error += self.bit_length - self.bit_length.floor();
|
||||
if self.residual_error >= 1.0 {
|
||||
self.residual_error -= 1.0;
|
||||
self.current_bit_length += 1;
|
||||
}
|
||||
|
||||
self.pos = 0;
|
||||
}
|
||||
|
||||
self.pos += 1;
|
||||
Some(Ok(self.current_bit))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_baurate_error_correction() {
|
||||
let input = vec![true, false, true, false];
|
||||
|
||||
let upsampler = BitUpsampler::from(input.into_iter().map(|x| Ok(x)), 10.0, 4.0);
|
||||
|
||||
let result_data: Result<Vec<bool>, DspError> = upsampler.collect();
|
||||
assert_eq!(
|
||||
result_data,
|
||||
Ok(vec![
|
||||
true, true, false, false, false, true, true, false, false, false
|
||||
])
|
||||
);
|
||||
}
|
||||
}
|
20
src/main.rs
20
src/main.rs
|
@ -1,8 +1,26 @@
|
|||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate rusty_dsp;
|
||||
|
||||
use rusty_dsp::multiply::MultiplyConst;
|
||||
use rusty_dsp::sinks::SoundCardSink;
|
||||
use rusty_dsp::sources::VFOSource;
|
||||
|
||||
mod baudot;
|
||||
mod bitgenerator;
|
||||
mod bitupsampler;
|
||||
mod symbolgenerator;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
let data = " kaufen sie jede woche vier gute bequeme pelze xy 1234567890 ";
|
||||
|
||||
let encoder = baudot::Encoder::from(data.to_ascii_uppercase().into_bytes().into_iter());
|
||||
let bitgenerator = bitgenerator::BitGenerator::from(encoder);
|
||||
let bitresampler = bitupsampler::BitUpsampler::from(bitgenerator, 48000.0, 45.5);
|
||||
let symbolgenerator = symbolgenerator::SymbolGenerator::from(bitresampler, 2125.0, 1955.0);
|
||||
let source = VFOSource::new(symbolgenerator, 48000.0);
|
||||
let mult = MultiplyConst::from(source, 0.3);
|
||||
let mut sink = SoundCardSink::from(mult, 48000);
|
||||
|
||||
sink.start().unwrap();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
extern crate rusty_dsp;
|
||||
|
||||
use rusty_dsp::error::DspError;
|
||||
|
||||
pub struct SymbolGenerator<'a> {
|
||||
space_freq: f32,
|
||||
mark_freq: f32,
|
||||
iterator: Box<dyn Iterator<Item = Result<bool, DspError>> + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> SymbolGenerator<'a> {
|
||||
pub fn from<I>(iterator: I, space_freq: f32, mark_freq: f32) -> SymbolGenerator<'a>
|
||||
where
|
||||
I: Iterator<Item = Result<bool, DspError>> + 'a,
|
||||
{
|
||||
SymbolGenerator {
|
||||
space_freq: space_freq,
|
||||
mark_freq: mark_freq,
|
||||
iterator: Box::new(iterator),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SymbolGenerator<'a> {
|
||||
type Item = Result<f32, DspError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iterator.next() {
|
||||
Some(Ok(b)) => {
|
||||
if b {
|
||||
Some(Ok(self.mark_freq))
|
||||
} else {
|
||||
Some(Ok(self.space_freq))
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
Some(Err(e)) => Some(Err(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_symbolgenerator() {
|
||||
let input = vec![true, false, true];
|
||||
|
||||
let generator = SymbolGenerator::from(input.into_iter().map(|x| Ok(x)), 23000.0, 42000.0);
|
||||
|
||||
let result_data: Result<Vec<f32>, DspError> = generator.collect();
|
||||
assert_eq!(result_data, Ok(vec![42000.0, 23000.0, 42000.0]));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue