port more from osmocom
This commit is contained in:
@@ -1,17 +1,19 @@
|
||||
const FSK_MAX_BITS: i32 = 1032;
|
||||
|
||||
enum DSPMode {
|
||||
OFF, // Channel not active
|
||||
AUDIO_RX_AUDIO_TX, // stream audio
|
||||
AUDIO_RX_FRAME_TX, // stream audio and send frames
|
||||
AUDIO_RX_SILENCE_TX, // stream audio and send silence
|
||||
FRAME_RX_FRAME_TX, // send and receive frames
|
||||
AudioRxAudioTx, // stream audio
|
||||
AudioRxFrameTx, // stream audio and send frames
|
||||
AudioRxSilenceTx, // stream audio and send silence
|
||||
FrameRxFrameTx, // send and receive frames
|
||||
}
|
||||
|
||||
enum AMPSChannelType {
|
||||
CC, // control channel
|
||||
PC, // paging channel
|
||||
CC_PC, // combined control+paging
|
||||
CcPc, // combined control+paging
|
||||
VC, // voice channel
|
||||
CC_PC_VC, // combined control+paging+voice
|
||||
CcPcVc, // combined control+paging+voice
|
||||
}
|
||||
|
||||
enum AMPSState {
|
||||
@@ -20,7 +22,7 @@ enum AMPSState {
|
||||
BUSY, // channel busy (call in progress)
|
||||
}
|
||||
|
||||
enum FSK_RX_Sync {
|
||||
enum FSKRxSync {
|
||||
NONE, // not in sync, waiting for valid dotting sequence
|
||||
DOTTING, // received a valid dotting sequence, check for sync sequence
|
||||
POSITIVE, // valid sync, read all bits from the frame
|
||||
|
||||
13
cellular/src/display.rs
Normal file
13
cellular/src/display.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Stub for display
|
||||
#[derive(Clone)]
|
||||
pub struct DispWav;
|
||||
#[derive(Clone)]
|
||||
pub struct DispMeas;
|
||||
|
||||
impl DispWav {
|
||||
pub fn new() -> Self { DispWav }
|
||||
}
|
||||
|
||||
impl DispMeas {
|
||||
pub fn new() -> Self { DispMeas }
|
||||
}
|
||||
57
cellular/src/emphasis.rs
Normal file
57
cellular/src/emphasis.rs
Normal file
@@ -0,0 +1,57 @@
|
||||
use crate::iir_filter::IIRFilter;
|
||||
|
||||
type Sample = f64;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Emphasis {
|
||||
pub pre_filter: IIRFilter,
|
||||
pub de_filter: IIRFilter,
|
||||
}
|
||||
|
||||
impl Emphasis {
|
||||
pub fn new() -> Self {
|
||||
Emphasis {
|
||||
pre_filter: IIRFilter {
|
||||
iter: 0,
|
||||
a0: 0.0,
|
||||
a1: 0.0,
|
||||
a2: 0.0,
|
||||
b1: 0.0,
|
||||
b2: 0.0,
|
||||
z1: Vec::new(),
|
||||
z2: Vec::new(),
|
||||
},
|
||||
de_filter: IIRFilter {
|
||||
iter: 0,
|
||||
a0: 0.0,
|
||||
a1: 0.0,
|
||||
a2: 0.0,
|
||||
b1: 0.0,
|
||||
b2: 0.0,
|
||||
z1: Vec::new(),
|
||||
z2: Vec::new(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, samplerate: i32, pre_emphasis: i32, de_emphasis: i32) {
|
||||
if pre_emphasis != 0 {
|
||||
self.pre_filter.highpass_init(300.0, samplerate, 1); // Boost highs
|
||||
}
|
||||
if de_emphasis != 0 {
|
||||
self.de_filter.lowpass_init(3000.0, samplerate, 1); // Cut highs
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_pre(&mut self, samples: &mut [Sample]) {
|
||||
if self.pre_filter.iter > 0 {
|
||||
self.pre_filter.process(samples);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_de(&mut self, samples: &mut [Sample]) {
|
||||
if self.de_filter.iter > 0 {
|
||||
self.de_filter.process(samples);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +1,130 @@
|
||||
struct IIRFilter {
|
||||
iter: i32,
|
||||
a0: f64,
|
||||
a1: f64,
|
||||
a2: f64,
|
||||
b1: f64,
|
||||
b2: f64,
|
||||
z1: f64,
|
||||
z2: f64,
|
||||
type Sample = f64;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct IIRFilter {
|
||||
pub iter: i32,
|
||||
pub a0: f64,
|
||||
pub a1: f64,
|
||||
pub a2: f64,
|
||||
pub b1: f64,
|
||||
pub b2: f64,
|
||||
pub z1: Vec<f64>, // Changed to Vec for iterations
|
||||
pub z2: Vec<f64>, // Changed to Vec for iterations
|
||||
}
|
||||
|
||||
impl IIRFilter {
|
||||
pub fn lowpass_init(&mut self, frequency: f64, samplerate: i32, iterations: i32) {
|
||||
|
||||
if iterations > 64 {
|
||||
panic!("Too many iterations, please fix!");
|
||||
}
|
||||
let sr = samplerate as f64;
|
||||
let fc = frequency / sr; // Normalized frequency
|
||||
let q = (0.5f64).sqrt().powf(1.0 / iterations as f64); // Q factor for iterations
|
||||
let k = (std::f64::consts::PI * fc).tan();
|
||||
let norm = 1.0 / (1.0 + k / q + k * k);
|
||||
self.a0 = k * k * norm;
|
||||
self.a1 = 2.0 * self.a0;
|
||||
self.a2 = self.a0;
|
||||
self.b1 = 2.0 * (k * k - 1.0) * norm;
|
||||
self.b2 = (1.0 - k / q + k * k) * norm;
|
||||
self.iter = iterations;
|
||||
self.z1 = vec![0.0; iterations as usize];
|
||||
self.z2 = vec![0.0; iterations as usize];
|
||||
}
|
||||
|
||||
pub fn highpass_init(&mut self, frequency: f64, samplerate: i32, iterations: i32) {
|
||||
|
||||
if iterations > 64 {
|
||||
panic!("Too many iterations, please fix!");
|
||||
}
|
||||
let sr = samplerate as f64;
|
||||
let fc = frequency / sr;
|
||||
let q = (0.5f64).sqrt().powf(1.0 / iterations as f64);
|
||||
let k = (std::f64::consts::PI * fc).tan();
|
||||
let norm = 1.0 / (1.0 + k / q + k * k);
|
||||
self.a0 = 1.0 * norm;
|
||||
self.a1 = -2.0 * self.a0;
|
||||
self.a2 = self.a0;
|
||||
self.b1 = 2.0 * (k * k - 1.0) * norm;
|
||||
self.b2 = (1.0 - k / q + k * k) * norm;
|
||||
self.iter = iterations;
|
||||
self.z1 = vec![0.0; iterations as usize];
|
||||
self.z2 = vec![0.0; iterations as usize];
|
||||
}
|
||||
|
||||
pub fn bandpass_init(&mut self, frequency: f64, samplerate: i32, iterations: i32) {
|
||||
|
||||
if iterations > 64 {
|
||||
panic!("Too many iterations, please fix!");
|
||||
}
|
||||
let sr = samplerate as f64;
|
||||
let fc = frequency / sr;
|
||||
let q = (0.5f64).sqrt().powf(1.0 / iterations as f64);
|
||||
let k = (std::f64::consts::PI * fc).tan();
|
||||
let norm = 1.0 / (1.0 + k / q + k * k);
|
||||
self.a0 = k / q * norm;
|
||||
self.a1 = 0.0;
|
||||
self.a2 = -self.a0;
|
||||
self.b1 = 2.0 * (k * k - 1.0) * norm;
|
||||
self.b2 = (1.0 - k / q + k * k) * norm;
|
||||
self.iter = iterations;
|
||||
self.z1 = vec![0.0; iterations as usize];
|
||||
self.z2 = vec![0.0; iterations as usize];
|
||||
}
|
||||
|
||||
pub fn notch_init(&mut self, frequency: f64, samplerate: i32, iterations: i32, Q: f64) {
|
||||
|
||||
pub fn notch_init(&mut self, frequency: f64, samplerate: i32, iterations: i32, q: f64) {
|
||||
if iterations > 64 {
|
||||
panic!("Too many iterations, please fix!");
|
||||
}
|
||||
let sr = samplerate as f64;
|
||||
let fc = frequency / sr;
|
||||
let k = (std::f64::consts::PI * fc).tan();
|
||||
let norm = 1.0 / (1.0 + k / q + k * k);
|
||||
self.a0 = (1.0 + k * k) * norm;
|
||||
self.a1 = 2.0 * (k * k - 1.0) * norm;
|
||||
self.a2 = self.a0;
|
||||
self.b1 = self.a1;
|
||||
self.b2 = (1.0 - k / q + k * k) * norm;
|
||||
self.iter = iterations;
|
||||
self.z1 = vec![0.0; iterations as usize];
|
||||
self.z2 = vec![0.0; iterations as usize];
|
||||
}
|
||||
|
||||
pub fn process(&mut self, samples: Sample, length: i32) {
|
||||
pub fn process(&mut self, samples: &mut [Sample]) {
|
||||
let a0 = self.a0;
|
||||
let a1 = self.a1;
|
||||
let a2 = self.a2;
|
||||
let b1 = self.b1;
|
||||
let b2 = self.b2;
|
||||
let iterations = self.iter as usize;
|
||||
|
||||
for sample in samples.iter_mut() {
|
||||
let mut input = *sample + 0.000000001; // As in C
|
||||
for j in 0..iterations {
|
||||
let out = input * a0 + self.z1[j];
|
||||
self.z1[j] = input * a1 + self.z2[j] - b1 * out;
|
||||
self.z2[j] = input * a2 - b2 * out;
|
||||
input = out;
|
||||
}
|
||||
*sample = input;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_baseband(&mut self, filter: IIRFilter, baseband: f64, length: i32) {
|
||||
pub fn process_baseband(&mut self, baseband: &mut [f32], length: i32) {
|
||||
let a0 = self.a0;
|
||||
let a1 = self.a1;
|
||||
let a2 = self.a2;
|
||||
let b1 = self.b1;
|
||||
let b2 = self.b2;
|
||||
let iterations = self.iter as usize;
|
||||
|
||||
for i in 0..length as usize {
|
||||
let mut input = baseband[i * 2] as f64 + 0.000000001; // Process real part
|
||||
for j in 0..iterations {
|
||||
let out = input * a0 + self.z1[j];
|
||||
self.z1[j] = input * a1 + self.z2[j] - b1 * out;
|
||||
self.z2[j] = input * a2 - b2 * out;
|
||||
input = out;
|
||||
}
|
||||
baseband[i * 2] = input as f32;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
cellular/src/jitter.rs
Normal file
41
cellular/src/jitter.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
type Sample = f64;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Jitter {
|
||||
pub buffer: Vec<Sample>,
|
||||
pub read_pos: usize,
|
||||
pub write_pos: usize,
|
||||
pub size: usize,
|
||||
}
|
||||
|
||||
impl Jitter {
|
||||
pub fn new(size: usize) -> Self {
|
||||
Jitter {
|
||||
buffer: vec![0.0; size],
|
||||
read_pos: 0,
|
||||
write_pos: 0,
|
||||
size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, samples: &[Sample]) {
|
||||
for &sample in samples {
|
||||
self.buffer[self.write_pos] = sample;
|
||||
self.write_pos = (self.write_pos + 1) % self.size;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&mut self, output: &mut [Sample]) -> usize {
|
||||
let mut count = 0;
|
||||
for i in 0..output.len() {
|
||||
if self.read_pos != self.write_pos {
|
||||
output[i] = self.buffer[self.read_pos];
|
||||
self.read_pos = (self.read_pos + 1) % self.size;
|
||||
count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,34 @@
|
||||
use std::ffi::{c_void, CStr, c_char};
|
||||
use crate::emphasis::Emphasis;
|
||||
use crate::jitter::Jitter;
|
||||
use crate::wave::{WaveRec, WavePlay};
|
||||
use crate::display::{DispWav, DispMeas};
|
||||
use crate::samplerate::SampleRate;
|
||||
|
||||
// Type aliases
|
||||
type Sample = f64;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
enum PagingSignal {
|
||||
NONE = 0,
|
||||
TONE,
|
||||
NOTONE,
|
||||
POSITIVE,
|
||||
NEGATIVE,
|
||||
None = 0,
|
||||
Tone,
|
||||
NoTone,
|
||||
Positive,
|
||||
Negative,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Sender {
|
||||
// System Info
|
||||
channel: char,
|
||||
send_freq: f64,
|
||||
recv_freq: f64,
|
||||
next: *mut Sender,
|
||||
slave: *mut Sender,
|
||||
master: *mut Sender,
|
||||
|
||||
// System info
|
||||
kanal: String,
|
||||
sendefrequenz: f64,
|
||||
empfangsfrequenz: f64,
|
||||
ruffrequenz: f64,
|
||||
|
||||
// FM/AM levels
|
||||
am: i32,
|
||||
@@ -21,25 +39,168 @@ struct Sender {
|
||||
max_display: f64,
|
||||
|
||||
// Audio
|
||||
audio: void,
|
||||
device: char,
|
||||
audio_open: void,
|
||||
audio_start: i32,
|
||||
audio_close: void,
|
||||
audio_write: i32,
|
||||
audio_get_tosend: i32,
|
||||
audio: *mut c_void,
|
||||
device: String,
|
||||
audio_open: Option<fn(i32, *const std::ffi::c_char, *mut f64, *mut f64, *mut i32, i32, f64, i32, i32, f64, f64, f64, f64) -> *mut c_void>,
|
||||
audio_start: Option<fn(*mut c_void) -> i32>,
|
||||
audio_close: Option<fn(*mut c_void)>,
|
||||
audio_write: Option<fn(*mut c_void, *mut *mut Sample, *mut *mut u8, i32, *mut PagingSignal, *mut i32, i32) -> i32>,
|
||||
audio_read: Option<fn(*mut c_void, *mut *mut Sample, i32, i32, *mut f64) -> i32>,
|
||||
audio_get_tosend: Option<fn(*mut c_void, i32) -> i32>,
|
||||
samplerate: i32,
|
||||
samplerate_state: SampleRate,
|
||||
srstate: SampleRate,
|
||||
rx_gain: f64,
|
||||
tx_gain: f64,
|
||||
pre_emphasis: i32,
|
||||
de_emphasis: i32,
|
||||
epmphasis_state: EmphasisState,
|
||||
estate: Emphasis,
|
||||
|
||||
// Loopback
|
||||
// Loopback test
|
||||
loopback: i32,
|
||||
|
||||
// Record & Playback
|
||||
// Record and playback
|
||||
write_rx_wave: Option<String>,
|
||||
write_tx_wave: Option<String>,
|
||||
read_rx_wave: Option<String>,
|
||||
read_tx_wave: Option<String>,
|
||||
wave_rx_rec: WaveRec,
|
||||
wave_tx_rec: WaveRec,
|
||||
wave_rx_play: WavePlay,
|
||||
wave_tx_play: WavePlay,
|
||||
|
||||
// Audio buffer for audio to send to transmitter
|
||||
dejitter: Jitter,
|
||||
loop_dejitter: Jitter,
|
||||
loop_sequence: u16,
|
||||
loop_timestamp: u32,
|
||||
|
||||
// Audio buffer for audio to send to caller (20ms = 160 samples @ 8000Hz)
|
||||
rxbuf: [Sample; 160],
|
||||
rxbuf_pos: i32,
|
||||
|
||||
// Paging tone
|
||||
paging_signal: PagingSignal,
|
||||
paging_on: i32,
|
||||
|
||||
// Display wave
|
||||
dispwav: DispWav,
|
||||
|
||||
// Display measurements
|
||||
dispmeas: DispMeas,
|
||||
}
|
||||
|
||||
// Global variables
|
||||
pub static mut SENDER_HEAD: *mut Sender = std::ptr::null_mut();
|
||||
pub static mut CANT_RECOVER: i32 = 0;
|
||||
pub static mut CHECK_CHANNEL: i32 = 0;
|
||||
|
||||
// Function stubs (to be implemented)
|
||||
pub fn sender_create(
|
||||
sender: *mut Sender,
|
||||
kanal: *const c_char,
|
||||
sendefrequenz: f64,
|
||||
empfangsfrequenz: f64,
|
||||
device: *const c_char,
|
||||
use_sdr: i32,
|
||||
samplerate: i32,
|
||||
rx_gain: f64,
|
||||
tx_gain: f64,
|
||||
pre_emphasis: i32,
|
||||
de_emphasis: i32,
|
||||
write_rx_wave: *const c_char,
|
||||
write_tx_wave: *const c_char,
|
||||
read_rx_wave: *const c_char,
|
||||
read_tx_wave: *const c_char,
|
||||
loopback: i32,
|
||||
paging_signal: PagingSignal,
|
||||
) -> i32 {
|
||||
unsafe {
|
||||
if sender.is_null() {
|
||||
return -1;
|
||||
}
|
||||
let s = &mut *sender;
|
||||
s.kanal = CStr::from_ptr(kanal).to_string_lossy().into_owned();
|
||||
s.sendefrequenz = sendefrequenz;
|
||||
s.empfangsfrequenz = empfangsfrequenz;
|
||||
s.device = CStr::from_ptr(device).to_string_lossy().into_owned();
|
||||
s.samplerate = samplerate;
|
||||
s.rx_gain = rx_gain;
|
||||
s.tx_gain = tx_gain;
|
||||
s.pre_emphasis = pre_emphasis;
|
||||
s.de_emphasis = de_emphasis;
|
||||
s.write_rx_wave = if !write_rx_wave.is_null() {
|
||||
Some(CStr::from_ptr(write_rx_wave).to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
s.write_tx_wave = if !write_tx_wave.is_null() {
|
||||
Some(CStr::from_ptr(write_tx_wave).to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
s.read_rx_wave = if !read_rx_wave.is_null() {
|
||||
Some(CStr::from_ptr(read_rx_wave).to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
s.read_tx_wave = if !read_tx_wave.is_null() {
|
||||
Some(CStr::from_ptr(read_tx_wave).to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
s.loopback = loopback;
|
||||
s.paging_signal = paging_signal;
|
||||
// Initialize dependencies
|
||||
s.estate = Emphasis::new();
|
||||
s.dejitter = Jitter::new(1600); // 10 * 160
|
||||
s.loop_dejitter = Jitter::new(1600);
|
||||
s.wave_rx_rec = WaveRec::new();
|
||||
s.wave_tx_rec = WaveRec::new();
|
||||
s.wave_rx_play = WavePlay::new();
|
||||
s.wave_tx_play = WavePlay::new();
|
||||
s.dispwav = DispWav::new();
|
||||
s.dispmeas = DispMeas::new();
|
||||
// TODO: Initialize srstate
|
||||
// s.srstate = SampleRate::new(...);
|
||||
// TODO: Initialize audio_open etc.
|
||||
s.audio_open = None; // Stub
|
||||
s.audio_start = None;
|
||||
s.audio_close = None;
|
||||
s.audio_write = None;
|
||||
s.audio_read = None;
|
||||
s.audio_get_tosend = None;
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sender_destroy(sender: *mut Sender) {
|
||||
if !sender.is_null() {
|
||||
// TODO: Clean up resources
|
||||
// For now, just deallocate if using Box or something, but since *mut, assume caller handles
|
||||
}
|
||||
}
|
||||
|
||||
// Stub implementations for other functions
|
||||
pub fn sender_set_fm(_sender: *mut Sender, _max_deviation: f64, _max_modulation: f64, _speech_deviation: f64, _max_display: f64) {}
|
||||
pub fn sender_set_am(_sender: *mut Sender, _max_modulation: f64, _speech_deviation: f64, _max_display: f64, _modulation_index: f64) {}
|
||||
pub fn sender_open_audio(_buffer_size: i32, _interval: f64) -> i32 { 0 }
|
||||
pub fn sender_start_audio() -> i32 { 0 }
|
||||
pub fn process_sender_audio(_sender: *mut Sender, _quit: *mut i32, _samples: *mut *mut Sample, _power: *mut *mut u8, _buffer_size: i32) {}
|
||||
pub fn sender_send(_sender: *mut Sender, _samples: *mut Sample, _power: *mut u8, _count: i32) {}
|
||||
pub fn sender_receive(_sender: *mut Sender, _samples: *mut Sample, _count: i32, _rf_level_db: f64) {}
|
||||
pub fn sender_paging(_sender: *mut Sender, _on: i32) {}
|
||||
|
||||
pub fn get_sender_by_empfangsfrequenz(freq: f64) -> *mut Sender {
|
||||
unsafe {
|
||||
let mut current = SENDER_HEAD;
|
||||
while !current.is_null() {
|
||||
if (*current).empfangsfrequenz == freq {
|
||||
return current;
|
||||
}
|
||||
current = (*current).next;
|
||||
}
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sender_conceal(_spl: *mut u8, _len: i32, _priv: *mut c_void) {}
|
||||
@@ -6,6 +6,10 @@ mod amps;
|
||||
mod libmobile_sender;
|
||||
mod iir_filter;
|
||||
mod samplerate;
|
||||
mod emphasis;
|
||||
mod jitter;
|
||||
mod wave;
|
||||
mod display;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let stdout = stdout();
|
||||
|
||||
@@ -1,40 +1,149 @@
|
||||
struct SampleRate {
|
||||
factor: f64,
|
||||
filter_cutoff: f64,
|
||||
down: DownSampler,
|
||||
up: UpSampler,
|
||||
use crate::iir_filter::IIRFilter;
|
||||
|
||||
type Sample = f64;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SampleRate {
|
||||
pub factor: f64,
|
||||
pub filter_cutoff: f64,
|
||||
pub down: DownSampler,
|
||||
pub up: UpSampler,
|
||||
}
|
||||
|
||||
struct DownSampler {
|
||||
lp: IIRFilter,
|
||||
last_sample: Sample,
|
||||
in_index: f64,
|
||||
#[derive(Clone)]
|
||||
pub struct DownSampler {
|
||||
pub lp: IIRFilter,
|
||||
pub last_sample: Sample,
|
||||
pub in_index: f64,
|
||||
}
|
||||
|
||||
struct UpSampler {
|
||||
lp: IIRFilter,
|
||||
current_sample: Sample,
|
||||
last_sample: Sample,
|
||||
in_index: f64,
|
||||
#[derive(Clone)]
|
||||
pub struct UpSampler {
|
||||
pub lp: IIRFilter,
|
||||
pub current_sample: Sample,
|
||||
pub last_sample: Sample,
|
||||
pub in_index: f64,
|
||||
}
|
||||
|
||||
impl SampleRate {
|
||||
pub fn init(&mut self, low_samplerate: f64, high_samplerate: f64, filter_cutoff: f64) -> Result<(), i32> {
|
||||
// Implementation goes here
|
||||
// clear state
|
||||
self.factor = 0.0;
|
||||
self.filter_cutoff = 0.0;
|
||||
|
||||
Ok(())
|
||||
// or Err(error_code) if there's an error
|
||||
self.factor = high_samplerate / low_samplerate;
|
||||
if self.factor < 1.0 {
|
||||
eprintln!("Software error: Low sample rate must be lower than high sample rate, aborting!");
|
||||
return Err(-1);
|
||||
}
|
||||
|
||||
pub fn downsample(&mut self, state: SampleRate, samples: Sample, input_num: i32) -> Result<(), i32> {
|
||||
self.filter_cutoff = filter_cutoff;
|
||||
if self.filter_cutoff > 0.0 {
|
||||
self.up.lp.lowpass_init(filter_cutoff, high_samplerate as i32, 2);
|
||||
self.down.lp.lowpass_init(filter_cutoff, high_samplerate as i32, 2);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn upsample_input_num(&mut self, state: SampleRate, output_num: i32) -> Result<(), i32> {
|
||||
Ok(())
|
||||
pub fn downsample_input_num(&mut self, output_num: i32) -> i32 {
|
||||
let factor = self.factor;
|
||||
let mut in_index = self.down.in_index;
|
||||
let mut idx = 0;
|
||||
|
||||
for _ in 0..output_num {
|
||||
in_index += factor;
|
||||
idx = in_index as i32;
|
||||
}
|
||||
|
||||
pub fn upsample_output_num(&mut self, state: SampleRate, input_num: i32) -> Result<(), i32> {
|
||||
idx
|
||||
}
|
||||
|
||||
pub fn downsample_output_num(&mut self, input_num: i32) -> i32 {
|
||||
let factor = self.factor;
|
||||
let mut in_index = self.down.in_index;
|
||||
let mut output_num = 0;
|
||||
let mut idx;
|
||||
|
||||
loop {
|
||||
idx = in_index as i32;
|
||||
if idx >= input_num {
|
||||
break;
|
||||
}
|
||||
output_num += 1;
|
||||
in_index += factor;
|
||||
}
|
||||
|
||||
output_num
|
||||
}
|
||||
|
||||
pub fn downsample(&mut self, samples: &mut [Sample], input_num: i32) -> i32 {
|
||||
let factor = self.factor;
|
||||
let mut output_num = 0;
|
||||
let mut in_index = self.down.in_index;
|
||||
let mut last_sample = self.down.last_sample;
|
||||
let mut idx;
|
||||
let mut diff;
|
||||
|
||||
// filter down if cutoff is set
|
||||
if self.filter_cutoff > 0.0 {
|
||||
self.down.lp.process(&mut samples[..input_num as usize]);
|
||||
}
|
||||
|
||||
// allocate output buffer w/ safety margin
|
||||
let output_size = ((input_num as f64) / factor + 0.5) as usize + 10;
|
||||
let mut output = vec![0.0; output_size];
|
||||
|
||||
for i in 0.. {
|
||||
idx = in_index as i32;
|
||||
if idx >= input_num {
|
||||
break;
|
||||
}
|
||||
diff = in_index - idx as f64;
|
||||
if idx > 0 {
|
||||
output[i] = samples[(idx-1) as usize] * (1.0 - diff) + samples[idx as usize] * diff;
|
||||
} else {
|
||||
output[i] = last_sample * (1.0 - diff) + samples[idx as usize] * diff;
|
||||
}
|
||||
output_num += 1;
|
||||
in_index += factor;
|
||||
}
|
||||
|
||||
// store last sample
|
||||
if input_num > 0 {
|
||||
self.down.last_sample = samples[(input_num -1) as usize];
|
||||
}
|
||||
|
||||
// adjust in_index
|
||||
in_index -= input_num as f64;
|
||||
if (in_index as i32) < 0 {
|
||||
in_index = 0.0;
|
||||
}
|
||||
self.down.in_index = in_index;
|
||||
|
||||
// copy output back to samples
|
||||
for i in 0..output_num {
|
||||
samples[i as usize] = output[i as usize];
|
||||
}
|
||||
|
||||
output_num
|
||||
}
|
||||
|
||||
pub fn upsample_input_num(&mut self, output_num: i32) -> i32 {
|
||||
let factor = 1.0 / self.factor;
|
||||
let mut in_index = self.up.in_index;
|
||||
let mut idx = 0;
|
||||
|
||||
for _ in 0..output_num {
|
||||
in_index += factor;
|
||||
if in_index >= 1.0 {
|
||||
idx += 1;
|
||||
in_index -= 1.0;
|
||||
}
|
||||
}
|
||||
idx
|
||||
}
|
||||
|
||||
pub fn upsample_output_num(&mut self, input_num: i32) -> i32 {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,12 @@ impl SdrTransmitter {
|
||||
// Helper function to create Args for a specific device
|
||||
pub fn device_args(driver: &str, serial: Option<&str>) -> Args {
|
||||
match serial {
|
||||
Some(serial) => Args::from(&format!("driver={},serial={}", driver, serial)),
|
||||
None => Args::from(&format!("driver={}", driver)),
|
||||
Some(serial) => Args::from(format!("driver={},serial={}", driver, serial).as_str()),
|
||||
None => Args::from(format!("driver={}", driver).as_str()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_device() -> Result<Args, Box<dyn std::error::Error>> {
|
||||
// Stub: return default device args
|
||||
Ok(device_args("hackrf", None))
|
||||
}
|
||||
13
cellular/src/wave.rs
Normal file
13
cellular/src/wave.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
// Stub for wave recording/playback
|
||||
#[derive(Clone)]
|
||||
pub struct WaveRec;
|
||||
#[derive(Clone)]
|
||||
pub struct WavePlay;
|
||||
|
||||
impl WaveRec {
|
||||
pub fn new() -> Self { WaveRec }
|
||||
}
|
||||
|
||||
impl WavePlay {
|
||||
pub fn new() -> Self { WavePlay }
|
||||
}
|
||||
Reference in New Issue
Block a user