initial commit

This commit is contained in:
Sebastien Bourdeauducq 2019-08-22 16:07:12 +08:00
commit da1c2a94c9
7 changed files with 259 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
**/*.rs.bk

101
Cargo.lock generated Normal file
View File

@ -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"

11
Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "noptica-rs"
version = "0.1.0"
authors = ["Sebastien Bourdeauducq <sb@m-labs.hk>"]
edition = "2018"
[dependencies]
num-traits = "0.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"

10
config.json Normal file
View File

@ -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
}

18
simulate.py Normal file
View File

@ -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]))

43
src/main.rs Normal file
View File

@ -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<P: AsRef<Path>>(path: P) -> Result<Config, Box<Error>> {
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());
})
}

74
src/noptica.rs Normal file
View File

@ -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;
}
}