288 lines
9.2 KiB
Rust
288 lines
9.2 KiB
Rust
use core::marker::PhantomData;
|
|
|
|
use miniconf::Tree;
|
|
use serde::{Deserialize, Serialize};
|
|
use stm32f4xx_hal::{pac::{ADC3, TIM2},
|
|
timer::CounterUs};
|
|
use uom::{si::{electric_current::{ampere, milliampere},
|
|
f32::{ElectricCurrent, ElectricPotential, Power},
|
|
power::milliwatt,
|
|
Quantity, ISQ, SI},
|
|
typenum::*};
|
|
|
|
use crate::{device::sys_timer::sleep,
|
|
laser_diode::{ld_ctrl::{Impedance, LdCtrl},
|
|
ld_current_out_ctrl_timer::LdCurrentOutCtrlTimer,
|
|
ld_pwr_exc_protector::{self, LdPwrExcProtector},
|
|
pd_mon_params}};
|
|
|
|
// Volt / Ampere
|
|
pub type TransimpedanceUnit = Quantity<ISQ<P2, P1, N3, N2, Z0, Z0, Z0>, SI<f32>, f32>;
|
|
// Ampere / Volt
|
|
type TransconductanceUnit = Quantity<ISQ<N2, N1, P3, P2, Z0, Z0, Z0>, SI<f32>, f32>;
|
|
|
|
impl Settings {
|
|
pub const LD_CURRENT_MAX: ElectricCurrent = ElectricCurrent {
|
|
dimension: PhantomData,
|
|
units: PhantomData,
|
|
value: 0.3,
|
|
};
|
|
pub const DAC_OUT_V_MAX: ElectricPotential = ElectricPotential {
|
|
dimension: PhantomData,
|
|
units: PhantomData,
|
|
value: 4.096,
|
|
};
|
|
|
|
// Unit: A/V
|
|
const PD_MON_TRANSCONDUCTANCE: TransconductanceUnit = TransconductanceUnit {
|
|
dimension: PhantomData,
|
|
units: PhantomData,
|
|
value: 0.001,
|
|
};
|
|
|
|
const LD_DRIVE_TRANSIMPEDANCE: TransimpedanceUnit = TransimpedanceUnit {
|
|
dimension: PhantomData,
|
|
units: PhantomData,
|
|
value: 10.0 / 0.75,
|
|
};
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Clone, Copy, Debug, Tree)]
|
|
struct Settings {
|
|
pwr_on: bool,
|
|
default_pwr_on: bool,
|
|
ld_drive_current: ElectricCurrent,
|
|
ld_drive_current_limit: ElectricCurrent,
|
|
pd_mon_params: pd_mon_params::Parameters,
|
|
ld_pwr_limit: Power,
|
|
ld_terms_short: bool,
|
|
}
|
|
|
|
impl Default for Settings {
|
|
fn default() -> Self {
|
|
Self {
|
|
pwr_on: false,
|
|
default_pwr_on: false,
|
|
ld_drive_current: ElectricCurrent::new::<milliampere>(0.0),
|
|
ld_drive_current_limit: ElectricCurrent::new::<milliampere>(0.0),
|
|
pd_mon_params: pd_mon_params::Parameters::default(),
|
|
ld_pwr_limit: Power::new::<milliwatt>(0.0),
|
|
ld_terms_short: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
|
pub struct StatusReport {
|
|
pwr_on: bool,
|
|
pwr_excursion: bool,
|
|
ld_i_set: ElectricCurrent,
|
|
pd_i: ElectricCurrent,
|
|
pd_pwr: Power,
|
|
term_status: Impedance,
|
|
}
|
|
|
|
pub struct LdDrive {
|
|
ctrl: LdCtrl,
|
|
settings: Settings,
|
|
}
|
|
|
|
impl LdDrive {
|
|
pub fn new(
|
|
current_source: LdCtrl,
|
|
pins_adc: ADC3,
|
|
tim2: CounterUs<TIM2>,
|
|
phy: ld_pwr_exc_protector::LdPwrExcProtectorPhy,
|
|
) -> Self {
|
|
LdPwrExcProtector::setup(pins_adc, phy);
|
|
LdCurrentOutCtrlTimer::setup(tim2);
|
|
|
|
LdDrive {
|
|
ctrl: current_source,
|
|
settings: Settings::default(),
|
|
}
|
|
}
|
|
|
|
pub fn setup(&mut self) {
|
|
LdPwrExcProtector::pwr_off();
|
|
self.ctrl.set_i(
|
|
ElectricCurrent::new::<milliampere>(0.0),
|
|
Settings::LD_DRIVE_TRANSIMPEDANCE,
|
|
Settings::DAC_OUT_V_MAX,
|
|
);
|
|
self.set_ld_drive_current_limit(Settings::LD_CURRENT_MAX);
|
|
LdCurrentOutCtrlTimer::reset();
|
|
self.ld_short();
|
|
}
|
|
|
|
pub fn set_ld_drive_current_limit(&mut self, i_limit: ElectricCurrent) {
|
|
self.settings.ld_drive_current_limit = i_limit.min(Settings::LD_CURRENT_MAX);
|
|
}
|
|
|
|
pub fn ld_short(&mut self) {
|
|
self.ctrl.ld_short_enable();
|
|
self.settings.ld_terms_short = true;
|
|
}
|
|
|
|
pub fn ld_open(&mut self) {
|
|
self.ctrl.ld_short_disable();
|
|
self.settings.ld_terms_short = false;
|
|
}
|
|
|
|
pub fn power_up(&mut self) {
|
|
let prev_i_set = self.settings.ld_drive_current;
|
|
LdCurrentOutCtrlTimer::reset();
|
|
let _ = self.ctrl.set_i(
|
|
ElectricCurrent::new::<milliampere>(0.0),
|
|
Settings::LD_DRIVE_TRANSIMPEDANCE,
|
|
Settings::DAC_OUT_V_MAX,
|
|
);
|
|
// Wait for the DAC to reset its voltage back to 0V
|
|
sleep(35);
|
|
LdPwrExcProtector::pwr_on_and_arm_protection();
|
|
// Wait for LD Power Supply to start up before driving current to laser diode
|
|
sleep(30);
|
|
self.ld_set_i(prev_i_set);
|
|
self.settings.pwr_on = true;
|
|
}
|
|
|
|
pub fn power_down(&mut self) {
|
|
LdPwrExcProtector::pwr_off();
|
|
self.settings.pwr_on = false;
|
|
}
|
|
|
|
pub fn get_pd_i(&mut self) -> ElectricCurrent {
|
|
LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE
|
|
}
|
|
|
|
pub fn get_pd_pwr(&mut self) -> Power {
|
|
self.settings
|
|
.pd_mon_params
|
|
.get_ld_pwr_from_ld_i(LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE)
|
|
}
|
|
|
|
pub fn ld_set_i(&mut self, i: ElectricCurrent) {
|
|
self.settings.ld_drive_current = i.min(self.settings.ld_drive_current_limit);
|
|
LdCurrentOutCtrlTimer::set_target_i_and_listen_irq(self.settings.ld_drive_current, self.ctrl.get_i_set());
|
|
}
|
|
|
|
pub fn poll_and_update_output_current(&mut self) -> ElectricCurrent {
|
|
match LdCurrentOutCtrlTimer::get_irq_status() {
|
|
Some(i_set) => {
|
|
let i_set = self
|
|
.ctrl
|
|
.set_i(i_set, Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX);
|
|
LdCurrentOutCtrlTimer::clear_alarm_and_resume_listening();
|
|
i_set
|
|
}
|
|
None => ElectricCurrent::new::<ampere>(0.0),
|
|
}
|
|
}
|
|
|
|
// Set the calibrated VDDA value obtained from ADC1 calibration
|
|
pub fn set_pd_mon_calibrated_vdda(&mut self, val_cal: u32) {
|
|
LdPwrExcProtector::set_calibrated_vdda(val_cal)
|
|
}
|
|
|
|
pub fn pd_mon_clear_alarm(&mut self) {
|
|
LdPwrExcProtector::clear_alarm_status();
|
|
}
|
|
|
|
pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) {
|
|
self.settings.pd_mon_params.set(responsitivity);
|
|
}
|
|
|
|
pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) {
|
|
self.settings.pd_mon_params.set_i_dark(i_dark);
|
|
}
|
|
|
|
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) {
|
|
LdPwrExcProtector::set_trigger_threshold_v(
|
|
self.settings.pd_mon_params.get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE,
|
|
);
|
|
self.settings.ld_pwr_limit = pwr_limit;
|
|
}
|
|
|
|
pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) {
|
|
LdPwrExcProtector::set_trigger_threshold_v(i / Settings::PD_MON_TRANSCONDUCTANCE);
|
|
}
|
|
|
|
pub fn set_default_pwr_on(&mut self, pwr_on: bool) {
|
|
self.settings.default_pwr_on = pwr_on;
|
|
}
|
|
|
|
pub fn get_term_status(&mut self) -> Impedance {
|
|
self.ctrl.get_lf_mod_in_impedance()
|
|
}
|
|
|
|
pub fn get_status_report(&mut self) -> StatusReport {
|
|
let ld_i_set = if LdPwrExcProtector::get_status().pwr_engaged {
|
|
self.ctrl.get_i_set()
|
|
} else {
|
|
ElectricCurrent::new::<ampere>(0.0)
|
|
};
|
|
StatusReport {
|
|
pwr_on: LdPwrExcProtector::get_status().pwr_engaged,
|
|
pwr_excursion: LdPwrExcProtector::get_status().pwr_excursion,
|
|
ld_i_set: ld_i_set,
|
|
pd_i: self.get_pd_i(),
|
|
pd_pwr: self.get_pd_pwr(),
|
|
term_status: self.get_term_status(),
|
|
}
|
|
}
|
|
|
|
pub fn get_settings_summary(&mut self) -> LdSettingsSummary {
|
|
let settings = self.settings;
|
|
LdSettingsSummary {
|
|
default_pwr_on: self.settings.default_pwr_on,
|
|
ld_drive_current: LdSettingsSummaryField {
|
|
value: settings.ld_drive_current,
|
|
max: Settings::LD_CURRENT_MAX,
|
|
},
|
|
ld_drive_current_limit: LdSettingsSummaryField {
|
|
value: settings.ld_drive_current_limit,
|
|
max: Settings::LD_CURRENT_MAX,
|
|
},
|
|
pd_mon_params: settings.pd_mon_params,
|
|
ld_pwr_limit: settings.ld_pwr_limit,
|
|
ld_terms_short: settings.ld_terms_short,
|
|
}
|
|
}
|
|
|
|
pub fn load_settings_from_summary(&mut self, settings: LdSettingsSummary) {
|
|
self.power_down();
|
|
self.settings.ld_drive_current = settings.ld_drive_current.value;
|
|
self.settings.ld_drive_current_limit = settings.ld_drive_current_limit.value;
|
|
self.settings.pd_mon_params = settings.pd_mon_params;
|
|
self.settings.ld_pwr_limit = settings.ld_pwr_limit;
|
|
self.settings.default_pwr_on = settings.default_pwr_on;
|
|
if self.settings.ld_terms_short {
|
|
self.ld_short();
|
|
} else {
|
|
self.ld_open();
|
|
}
|
|
|
|
if settings.default_pwr_on {
|
|
self.power_up();
|
|
} else {
|
|
self.power_down();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
|
pub struct LdSettingsSummary {
|
|
default_pwr_on: bool,
|
|
ld_drive_current: LdSettingsSummaryField<ElectricCurrent>,
|
|
ld_drive_current_limit: LdSettingsSummaryField<ElectricCurrent>,
|
|
pd_mon_params: pd_mon_params::Parameters,
|
|
ld_pwr_limit: Power,
|
|
ld_terms_short: bool,
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)]
|
|
pub struct LdSettingsSummaryField<T> {
|
|
value: T,
|
|
max: T,
|
|
}
|