pub mod clockswitch;
pub mod controller;
pub mod hmcad1511;
pub mod lmx;
use self::{
clockswitch::{
ClockSwitch,
Source,
},
controller::{
Adc16,
ChannelInput,
ChipSelect,
},
hmcad1511::{
LvdsDriveStrength,
LvdsTermination,
},
lmx::Synth,
};
use crate::transport::Transport;
use std::sync::{
Mutex,
Weak,
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
Transport(#[from] crate::transport::Error),
#[error(transparent)]
Controller(#[from] controller::Error),
#[error(transparent)]
Clockswitch(#[from] clockswitch::Error),
#[error("Invalid number of SNAP inputs from the fpg file")]
BadSnapInputs,
#[error("Only the 8 bit resolution HMCAD1511 is supported - PRs welcome :)")]
BadAdcResolution,
#[error("Bad sample rate from the fpg file")]
BadSampleRate,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AdcMode {
Single,
Dual,
Quad,
}
#[derive(Debug)]
pub struct SnapAdc<T> {
transport: Weak<Mutex<T>>,
pub sample_rate: f64,
pub mode: AdcMode,
pub source: Source,
pub clksw: ClockSwitch<T>,
pub synth: Synth<T>,
pub controller: Adc16<T>,
_name: String,
}
impl<T> SnapAdc<T>
where
T: Transport,
{
const RAM0_NAME: &'static str = "adc16_wb_ram0";
const RAM1_NAME: &'static str = "adc16_wb_ram1";
const RAM2_NAME: &'static str = "adc16_wb_ram2";
pub fn from_fpg(
transport: Weak<Mutex<T>>,
reg_name: &str,
adc_resolution: &str,
sample_rate: &str,
snap_inputs: &str,
clock_src: &str,
) -> Result<Self, Error> {
let mode = match snap_inputs {
"12" => AdcMode::Quad,
"6" => AdcMode::Dual,
"3" => AdcMode::Single,
_ => return Err(Error::BadSnapInputs),
};
if adc_resolution != "8" {
return Err(Error::BadAdcResolution);
}
let clksw = ClockSwitch::new(transport.clone());
let synth = Synth::new(transport.clone());
let controller = Adc16::new(transport.clone());
let source = match clock_src {
"sys_clk" => Source::Internal,
_ => Source::External,
};
Ok(Self {
transport,
sample_rate: sample_rate.parse().map_err(|_| Error::BadSampleRate)?,
mode,
clksw,
synth,
controller,
_name: reg_name.to_string(),
source,
})
}
#[allow(clippy::missing_panics_doc)]
pub fn snapshot(&self, chip: SnapAdcChip) -> Result<[u8; 1024], Error> {
self.controller.snap_req()?;
let tarc = self.transport.upgrade().unwrap();
let mut transport = (*tarc).lock().unwrap();
Ok(transport.read_bytes(
match chip {
SnapAdcChip::A => Self::RAM0_NAME,
SnapAdcChip::B => Self::RAM1_NAME,
SnapAdcChip::C => Self::RAM2_NAME,
},
0,
)?)
}
#[allow(clippy::missing_panics_doc)]
pub fn initialize(&mut self) -> Result<(), Error> {
self.controller.reset()?;
self.controller.chip_select(&ChipSelect::select_all());
self.clksw.set_source(self.source)?;
if self.source == Source::Internal {
todo!()
}
self.controller.init(self.mode, self.sample_rate)?;
self.controller.chip_select(&ChipSelect {
b: true,
c: true,
..Default::default()
});
self.controller.set_terminations(
LvdsTermination::_94,
LvdsTermination::_94,
LvdsTermination::default(),
)?;
self.controller.set_drive_strength(
LvdsDriveStrength::_0_5,
LvdsDriveStrength::_0_5,
LvdsDriveStrength::default(),
)?;
self.controller.chip_select(&ChipSelect::select_all());
self.controller.set_demux(match self.mode {
AdcMode::Single => controller::DemuxMode::SingleChannel,
AdcMode::Dual => controller::DemuxMode::DualChannel,
AdcMode::Quad => controller::DemuxMode::QuadChannel,
})?;
Ok(())
}
pub fn select_inputs(&self, inputs: ChannelInput) -> Result<(), Error> {
match self.mode {
AdcMode::Single => assert!(matches!(inputs, ChannelInput::Single(_))),
AdcMode::Dual => assert!(matches!(inputs, ChannelInput::Dual(_, _))),
AdcMode::Quad => assert!(matches!(inputs, ChannelInput::Quad(_, _, _, _))),
};
Ok(self.controller.input_select(inputs)?)
}
}
#[derive(Debug, Copy, Clone)]
pub enum SnapAdcChip {
A = 0,
B = 1,
C = 2,
}