From da1c2a94c966014113a5448afc887b81844fcdbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Aug 2019 16:07:12 +0800 Subject: [PATCH] initial commit --- .gitignore | 2 + Cargo.lock | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 11 ++++++ config.json | 10 +++++ simulate.py | 18 +++++++++ src/main.rs | 43 +++++++++++++++++++++ src/noptica.rs | 74 ++++++++++++++++++++++++++++++++++++ 7 files changed, 259 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 config.json create mode 100644 simulate.py create mode 100644 src/main.rs create mode 100644 src/noptica.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..800c675 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,101 @@ +[[package]] +name = "autocfg" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "noptica-rs" +version = "0.1.0" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum syn 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "158521e6f544e7e3dcfc370ac180794aa38cb34a1b1e07609376d4adcf429b93" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..453acf7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "noptica-rs" +version = "0.1.0" +authors = ["Sebastien Bourdeauducq "] +edition = "2018" + +[dependencies] +num-traits = "0.2" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" diff --git a/config.json b/config.json new file mode 100644 index 0000000..f7c2e13 --- /dev/null +++ b/config.json @@ -0,0 +1,10 @@ +{ + "sample_command": "sudo sigrok-cli -O binary -d fx2lafw --config samplerate=8000000 --continuous", + "sample_rate": 8e6, + "freq_min": 1.9e6, + "freq_max": 2.1e6, + "bit_ref": 0, + + "refpll_ki": 4294967, + "refpll_kl": 85899345 +} diff --git a/simulate.py b/simulate.py new file mode 100644 index 0000000..5929ac6 --- /dev/null +++ b/simulate.py @@ -0,0 +1,18 @@ +import sys, os + +sample_rate = 24e6 +ref_frequency = 2.0e6 + + +ref_phase = 0 +ref_ftw = int(ref_frequency*2**32/sample_rate) + +fp = os.fdopen(sys.stdout.fileno(), "wb") + +while True: + ref_phase = (ref_phase + ref_ftw) & 0xffffffff + + sample = 0 + if ref_phase >= 0x80000000: + sample |= 0x01 + fp.write(bytes([sample])) diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..a4ed169 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,43 @@ +extern crate num_traits; +extern crate serde_derive; +extern crate serde_json; + +use serde_derive::Deserialize; + +use std::error::Error; +use std::fs::File; +use std::io::BufReader; +use std::path::Path; + +mod noptica; + +#[derive(Deserialize, Debug)] +struct Config { + sample_command: String, + sample_rate: f64, + freq_min: f64, + freq_max: f64, + bit_ref: u8, + refpll_ki: i64, + refpll_kl: i64 +} + +fn read_config_from_file>(path: P) -> Result> { + let file = File::open(path)?; + let reader = BufReader::new(file); + let u = serde_json::from_reader(reader)?; + Ok(u) +} + +fn main() { + let config = read_config_from_file("config.json").unwrap(); + let mut refpll = noptica::Dpll::new( + noptica::Dpll::frequency_to_ftw(config.freq_min, config.sample_rate), + noptica::Dpll::frequency_to_ftw(config.freq_max, config.sample_rate), + config.refpll_ki, + config.refpll_kl); + noptica::sample(&config.sample_command, |rising, _falling| { + refpll.tick(rising & (1 << config.bit_ref) != 0); +// println!("{}", refpll.get_phase_unwrapped()); + }) +} diff --git a/src/noptica.rs b/src/noptica.rs new file mode 100644 index 0000000..f7ad262 --- /dev/null +++ b/src/noptica.rs @@ -0,0 +1,74 @@ +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, +} + +impl Dpll { + pub fn new(ftw_min: i64, ftw_max: i64, ki: i64, kp: i64) -> Dpll { + assert!(ftw_min < 0x80000000); + assert!(ftw_max < 0x80000000); + 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, + phase_unwrapped: 0 + } + } + + pub fn frequency_to_ftw(frequency: f64, sample_rate: f64) -> i64 { + (frequency*(u32::max_value() as f64)/sample_rate) as i64 + } + + pub fn tick(&mut self, edge: bool) { + self.phase = (self.phase + self.ftw) & 0xffffffff; + self.phase_unwrapped = self.phase_unwrapped.wrapping_add(self.ftw); + if edge { + let pe = 0x80000000 - self.phase; + 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); + } + } + + pub fn get_phase_unwrapped(&self) -> i64 { + self.phase_unwrapped + } +} + + +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()); + let mut br_sample = [0; 1]; + let mut last_sample = 0; + loop { + reader.read_exact(&mut br_sample).unwrap(); + let sample = br_sample[0]; + let rising = sample & !last_sample; + let falling = !sample & last_sample; + callback(rising, falling); + last_sample = sample; + } +}