2019-08-22 16:07:12 +08:00
|
|
|
use std::io::{BufReader, Read};
|
|
|
|
use num_traits::clamp;
|
|
|
|
|
|
|
|
pub struct Dpll {
|
|
|
|
ftw_min: i64,
|
|
|
|
ftw_max: i64,
|
|
|
|
ki: i64,
|
|
|
|
kp: i64,
|
|
|
|
|
|
|
|
ftw: i64,
|
|
|
|
integrator: i64,
|
|
|
|
|
|
|
|
phase: i64,
|
|
|
|
phase_unwrapped: i64,
|
2019-11-04 14:46:04 +08:00
|
|
|
|
|
|
|
was_locked: bool,
|
|
|
|
wait_lock: Option<u32>
|
2019-08-22 16:07:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Dpll {
|
2019-10-23 23:01:15 +08:00
|
|
|
pub const TURN: i64 = 0x100000000; // One turn in DPLL phase units.
|
|
|
|
|
2019-08-22 16:07:12 +08:00
|
|
|
pub fn new(ftw_min: i64, ftw_max: i64, ki: i64, kp: i64) -> Dpll {
|
2019-10-23 23:01:15 +08:00
|
|
|
assert!(ftw_min < Dpll::TURN/2);
|
|
|
|
assert!(ftw_max < Dpll::TURN/2);
|
|
|
|
assert!(Dpll::TURN & (Dpll::TURN - 1) == 0); // must be a power of 2
|
2019-08-22 16:07:12 +08:00
|
|
|
let init_ftw = (ftw_min + ftw_max)/2;
|
|
|
|
Dpll {
|
|
|
|
ftw_min: ftw_min,
|
|
|
|
ftw_max: ftw_max,
|
|
|
|
ki: ki,
|
|
|
|
kp: kp,
|
|
|
|
ftw: init_ftw,
|
|
|
|
integrator: init_ftw,
|
|
|
|
phase: 0,
|
2019-11-04 14:46:04 +08:00
|
|
|
phase_unwrapped: 0,
|
|
|
|
was_locked: false,
|
|
|
|
wait_lock: Some(0)
|
2019-08-22 16:07:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn frequency_to_ftw(frequency: f64, sample_rate: f64) -> i64 {
|
2019-10-23 23:01:15 +08:00
|
|
|
(frequency*(Dpll::TURN as f64)/sample_rate) as i64
|
2019-08-22 16:07:12 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn tick(&mut self, edge: bool) {
|
2019-10-23 23:01:15 +08:00
|
|
|
self.phase = (self.phase + self.ftw) & (Dpll::TURN - 1);
|
2019-08-22 16:07:12 +08:00
|
|
|
self.phase_unwrapped = self.phase_unwrapped.wrapping_add(self.ftw);
|
|
|
|
if edge {
|
2019-10-23 23:01:15 +08:00
|
|
|
let pe = Dpll::TURN/2 - self.phase;
|
2019-08-22 16:07:12 +08:00
|
|
|
self.integrator = clamp(self.integrator + (pe*self.ki >> 32),
|
|
|
|
self.ftw_min, self.ftw_max);
|
|
|
|
self.ftw = clamp(self.integrator + (pe*self.kp >> 32),
|
|
|
|
self.ftw_min, self.ftw_max);
|
2019-11-04 14:46:04 +08:00
|
|
|
|
|
|
|
if pe.abs() <= (self.ftw + self.ftw/3) {
|
|
|
|
if let Some(wait_lock) = self.wait_lock {
|
|
|
|
if wait_lock < 1000000 {
|
|
|
|
self.wait_lock = Some(wait_lock + 1);
|
|
|
|
} else {
|
|
|
|
self.wait_lock = None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.wait_lock = Some(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.locked() & !self.was_locked {
|
|
|
|
eprintln!("DPLL locked");
|
|
|
|
}
|
|
|
|
if !self.locked() & self.was_locked {
|
|
|
|
eprintln!("DPLL lost lock");
|
|
|
|
}
|
|
|
|
self.was_locked = self.locked();
|
2019-08-22 16:07:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_phase_unwrapped(&self) -> i64 {
|
|
|
|
self.phase_unwrapped
|
|
|
|
}
|
2019-11-04 14:46:04 +08:00
|
|
|
|
|
|
|
pub fn locked(&self) -> bool {
|
|
|
|
self.wait_lock.is_none()
|
|
|
|
}
|
2019-08-22 16:07:12 +08:00
|
|
|
}
|
|
|
|
|
2019-10-23 18:35:39 +08:00
|
|
|
pub struct PositionTracker {
|
2019-08-26 16:05:40 +08:00
|
|
|
last_phase: i64,
|
|
|
|
current_position: i64
|
|
|
|
}
|
|
|
|
|
2019-10-23 18:35:39 +08:00
|
|
|
impl PositionTracker {
|
|
|
|
pub fn new() -> PositionTracker {
|
|
|
|
PositionTracker {
|
2019-08-26 16:05:40 +08:00
|
|
|
last_phase: 0,
|
|
|
|
current_position: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn edge(&mut self, phase: i64) -> i64 {
|
|
|
|
let phase_diff = phase.wrapping_sub(self.last_phase);
|
|
|
|
self.last_phase = phase;
|
2019-10-23 23:01:15 +08:00
|
|
|
self.current_position += Dpll::TURN - phase_diff;
|
2019-08-26 16:05:40 +08:00
|
|
|
self.current_position
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-04 16:13:59 +08:00
|
|
|
pub struct Decimator<T> {
|
|
|
|
accumulator: T,
|
2019-08-26 16:05:40 +08:00
|
|
|
current_count: u32,
|
|
|
|
max_count: u32
|
|
|
|
}
|
|
|
|
|
2019-11-04 16:13:59 +08:00
|
|
|
impl<T> Decimator<T> {
|
|
|
|
pub fn new(max_count: u32) -> Decimator<T> where T: std::convert::From<u32> {
|
2019-08-26 16:05:40 +08:00
|
|
|
Decimator {
|
2019-11-04 16:13:59 +08:00
|
|
|
accumulator: T::from(0),
|
2019-08-26 16:05:40 +08:00
|
|
|
current_count: 0,
|
|
|
|
max_count: max_count
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-04 16:13:59 +08:00
|
|
|
pub fn input(&mut self, data: T) -> Option<T>
|
|
|
|
where T: Copy +
|
|
|
|
std::convert::From<u32> +
|
|
|
|
std::convert::From<<T as std::ops::Div>::Output> +
|
|
|
|
std::ops::AddAssign +
|
|
|
|
std::ops::Div {
|
2019-08-26 16:05:40 +08:00
|
|
|
self.accumulator += data;
|
|
|
|
self.current_count += 1;
|
|
|
|
if self.current_count == self.max_count {
|
2019-11-04 16:13:59 +08:00
|
|
|
let average = T::from(self.accumulator/T::from(self.current_count));
|
|
|
|
self.accumulator = T::from(0);
|
2019-08-26 16:05:40 +08:00
|
|
|
self.current_count = 0;
|
|
|
|
Some(average)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-22 16:07:12 +08:00
|
|
|
|
|
|
|
pub fn sample(command: &str, mut callback: impl FnMut(u8, u8)) {
|
|
|
|
let child = std::process::Command::new("sh")
|
|
|
|
.arg("-c")
|
|
|
|
.arg(command)
|
|
|
|
.stdout(std::process::Stdio::piped())
|
|
|
|
.spawn()
|
|
|
|
.unwrap();
|
|
|
|
let mut reader = BufReader::new(child.stdout.unwrap());
|
2019-08-28 15:56:54 +08:00
|
|
|
let mut buffer = [0; 1];
|
2019-08-22 16:07:12 +08:00
|
|
|
let mut last_sample = 0;
|
|
|
|
loop {
|
2019-08-28 15:56:54 +08:00
|
|
|
reader.read_exact(&mut buffer).unwrap();
|
2019-10-08 20:08:25 +08:00
|
|
|
for shift in [4u8, 0u8].iter() {
|
|
|
|
let sample = (buffer[0] >> shift) & 0x0f;
|
2019-08-28 15:56:54 +08:00
|
|
|
let rising = sample & !last_sample;
|
|
|
|
let falling = !sample & last_sample;
|
|
|
|
callback(rising, falling);
|
|
|
|
last_sample = sample;
|
|
|
|
}
|
2019-08-22 16:07:12 +08:00
|
|
|
}
|
|
|
|
}
|