use std::{any::type_name, collections::BTreeMap};
use core::fmt::Debug;
use super::calc::*;
use deimos_shared::{
peripherals::{ModelNumber, model_numbers},
states::*,
};
pub mod analog_i_rev_2;
pub use analog_i_rev_2::AnalogIRev2;
pub mod analog_i_rev_3;
pub use analog_i_rev_3::AnalogIRev3;
pub mod analog_i_rev_4;
pub use analog_i_rev_4::AnalogIRev4;
pub mod deimos_daq_rev5;
pub use deimos_daq_rev5::DeimosDaqRev5;
pub mod deimos_daq_rev6;
pub use deimos_daq_rev6::DeimosDaqRev6;
pub mod deimos_daq_rev7;
pub use deimos_daq_rev7::DeimosDaqRev7;
pub mod hootl;
pub use hootl::{HootlDriver, HootlPeripheral, HootlRunHandle, HootlTransport};
pub use deimos_shared::peripherals::PeripheralId;
#[macro_export]
macro_rules! py_peripheral_methods {
($ty:ident) => {
$crate::py_json_methods!(
$ty,
$crate::peripheral::Peripheral,
#[new]
fn py_new(serial_number: u64) -> PyResult<Self> {
Ok(Self { serial_number })
},
#[getter]
fn serial_number(&self) -> u64 {
self.serial_number
}
);
};
}
pub type PluginFn = dyn Fn(&BindingOutput) -> Box<dyn Peripheral> + Send + Sync;
pub type PluginMap<'a> = BTreeMap<ModelNumber, &'a PluginFn>;
impl Clone for Box<dyn Peripheral> {
fn clone(&self) -> Box<dyn Peripheral> {
let new: Box<dyn Peripheral> =
serde_json::from_str(&serde_json::to_string(&self).unwrap()).unwrap();
new
}
}
#[typetag::serde(tag = "type")]
pub trait Peripheral: Send + Sync + Debug {
fn id(&self) -> PeripheralId;
fn input_names(&self) -> Vec<String>;
fn output_names(&self) -> Vec<String>;
fn operating_roundtrip_input_size(&self) -> usize;
fn operating_roundtrip_output_size(&self) -> usize;
fn emit_operating_roundtrip(
&self,
id: u64,
period_delta_ns: i64,
phase_delta_ns: i64,
inputs: &[f64],
bytes: &mut [u8],
);
fn parse_operating_roundtrip(&self, bytes: &[u8], outputs: &mut [f64]) -> OperatingMetrics;
fn configuring_input_size(&self) -> usize {
ConfiguringInput::BYTE_LEN
}
fn configuring_output_size(&self) -> usize {
ConfiguringOutput::BYTE_LEN
}
fn emit_configuring(&self, base_config: ConfiguringInput, bytes: &mut [u8]) {
let num_to_write = self.configuring_input_size();
base_config.write_bytes(&mut bytes[..num_to_write]);
}
fn parse_configuring(&self, bytes: &[u8]) -> Result<(), String> {
let resp = ConfiguringOutput::read_bytes(bytes);
match resp.acknowledge {
AcknowledgeConfiguration::Ack => Ok(()),
x => Err(format!("{x:?}")),
}
}
fn standard_calcs(&self, name: String) -> BTreeMap<String, Box<dyn Calc>>;
fn kind(&self) -> String {
type_name::<Self>().split(":").last().unwrap().into()
}
}
pub fn parse_binding(
msg: &BindingOutput,
plugins: &Option<PluginMap>,
) -> Result<Box<dyn Peripheral>, String> {
let m = msg.peripheral_id.model_number;
if let Some(plugins) = plugins {
if let Some(f) = plugins.get(&m) {
return Ok(f(msg));
}
}
match m {
model_numbers::ANALOG_I_REV_2_MODEL_NUMBER => Ok(Box::new(AnalogIRev2 {
serial_number: msg.peripheral_id.serial_number,
})),
model_numbers::ANALOG_I_REV_3_MODEL_NUMBER => Ok(Box::new(AnalogIRev3 {
serial_number: msg.peripheral_id.serial_number,
})),
model_numbers::ANALOG_I_REV_4_MODEL_NUMBER => Ok(Box::new(AnalogIRev4 {
serial_number: msg.peripheral_id.serial_number,
})),
model_numbers::DEIMOS_DAQ_REV_5_MODEL_NUMBER => Ok(Box::new(DeimosDaqRev5 {
serial_number: msg.peripheral_id.serial_number,
})),
model_numbers::DEIMOS_DAQ_REV_6_MODEL_NUMBER => Ok(Box::new(DeimosDaqRev6 {
serial_number: msg.peripheral_id.serial_number,
})),
model_numbers::DEIMOS_DAQ_REV_7_MODEL_NUMBER => Ok(Box::new(DeimosDaqRev7 {
serial_number: msg.peripheral_id.serial_number,
})),
_ => Err(format!("Unrecognized model number {m}").to_owned()),
}
}