use crate::bladerf1::hardware::lms6002d::dc_calibration::DcCals;
use crate::bladerf1::hardware::lms6002d::dc_calibration::{AgcDcCorrection, DcPair};
use crate::error::Result;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct DcCalEntry {
pub freq: u32,
pub dc: DcPair,
pub max_dc: DcPair,
pub mid_dc: DcPair,
pub min_dc: DcPair,
}
impl DcCalEntry {
pub fn new(freq: u32, dc: DcPair) -> Self {
Self {
freq,
dc,
max_dc: DcPair::default(),
mid_dc: DcPair::default(),
min_dc: DcPair::default(),
}
}
pub fn with_agc(mut self, max_dc: DcPair, mid_dc: DcPair, min_dc: DcPair) -> Self {
self.max_dc = max_dc;
self.mid_dc = mid_dc;
self.min_dc = min_dc;
self
}
}
impl From<&DcCalEntry> for AgcDcCorrection {
fn from(e: &DcCalEntry) -> Self {
Self {
max: e.max_dc,
mid: e.mid_dc,
min: e.min_dc,
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DcCalTable {
reg_vals: DcCals,
entries: Vec<DcCalEntry>,
}
impl DcCalTable {
pub fn new(reg_vals: DcCals, entries: Vec<DcCalEntry>) -> Self {
Self { reg_vals, entries }
}
pub fn reg_vals(&self) -> &DcCals {
&self.reg_vals
}
pub fn entries(&self) -> &[DcCalEntry] {
&self.entries
}
pub fn load(path: &Path) -> Result<Self> {
let buf = std::fs::read_to_string(path)?;
Ok(serde_json::from_str(&buf)?)
}
pub fn save(&self, path: &Path) -> Result<()> {
let json = serde_json::to_string_pretty(self)?;
Ok(std::fs::write(path, json)?)
}
fn lookup_index(&self, freq: u32) -> usize {
if self.entries.is_empty() {
return 0;
}
self.entries
.partition_point(|e| e.freq <= freq)
.saturating_sub(1)
}
pub fn lookup(&self, freq: u64) -> DcCalEntry {
if self.entries.is_empty() {
return DcCalEntry {
freq: freq as u32,
dc: DcPair::default(),
max_dc: DcPair::default(),
mid_dc: DcPair::default(),
min_dc: DcPair::default(),
};
}
let f = freq as u32;
let idx = self.lookup_index(f);
if self.entries[idx].freq == f {
return self.entries[idx];
}
if idx == 0 && f < self.entries[0].freq {
return self.entries[0];
}
if idx == self.entries.len() - 1 && f > self.entries[idx].freq {
return self.entries[idx];
}
let (idx_low, idx_high) = if idx == self.entries.len() - 1 {
(idx - 1, idx)
} else {
(idx, idx + 1)
};
let f_low = self.entries[idx_low].freq;
let f_high = self.entries[idx_high].freq;
DcCalEntry {
freq: f,
dc: DcPair::interp(
f_low,
self.entries[idx_low].dc,
f_high,
self.entries[idx_high].dc,
f,
),
max_dc: DcPair::interp(
f_low,
self.entries[idx_low].max_dc,
f_high,
self.entries[idx_high].max_dc,
f,
),
mid_dc: DcPair::interp(
f_low,
self.entries[idx_low].mid_dc,
f_high,
self.entries[idx_high].mid_dc,
f,
),
min_dc: DcPair::interp(
f_low,
self.entries[idx_low].min_dc,
f_high,
self.entries[idx_high].min_dc,
f,
),
}
}
}