use miniconf::Tree; use stm32f4xx_hal::timer::CounterUs; use stm32f4xx_hal::pac::{ADC3, TIM2}; use uom::si::electric_current::ampere; use uom::si::power::milliwatt; use crate::laser_diode::ld_ctrl::{LdCtrl, Impedance}; use crate::laser_diode::ld_pwr_exc_protector::{LdPwrExcProtector, self}; use crate::laser_diode::pd_responsitivity; use crate::laser_diode::ld_current_out_ctrl_timer::LdCurrentOutCtrlTimer; use core::marker::PhantomData; use crate::device::sys_timer::sleep; use serde::{Deserialize, Serialize}; use uom::si::{ electric_current::milliampere, f32::{ElectricPotential, ElectricCurrent, Power}, }; use uom::{si::{ISQ, SI, Quantity}, typenum::*}; // Volt / Ampere pub type TransimpedanceUnit = Quantity, SI, f32>; // Ampere / Volt type TransconductanceUnit = Quantity, SI, 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_responsitivity: pd_responsitivity::Parameters, ld_pwr_limit: Power, } impl Default for Settings { fn default() -> Self { Self { pwr_on: false, default_pwr_on: false, ld_drive_current: ElectricCurrent::new::(0.0), ld_drive_current_limit: ElectricCurrent::new::(0.0), pd_responsitivity: pd_responsitivity::Parameters::default(), ld_pwr_limit: Power::new::(0.0), } } } #[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, 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::(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 get_ld_drive_current(&mut self) -> ElectricCurrent{ self.settings.ld_drive_current } 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(); } pub fn ld_open(&mut self) { self.ctrl.ld_short_disable(); } pub fn power_up(&mut self){ LdCurrentOutCtrlTimer::reset(); let _ = self.ctrl.set_i(ElectricCurrent::new::(0.0), Settings::LD_DRIVE_TRANSIMPEDANCE, Settings::DAC_OUT_V_MAX); 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(self.settings.ld_drive_current); 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_responsitivity.get_ld_pwr_from_ld_i(LdPwrExcProtector::get_status().v * Settings::PD_MON_TRANSCONDUCTANCE) } pub fn ld_set_i(&mut self, i: ElectricCurrent){ LdCurrentOutCtrlTimer::set_target_i_and_listen_irq(i, self.settings.ld_drive_current); } 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); self.settings.ld_drive_current = i_set; LdCurrentOutCtrlTimer::clear_alarm_and_resume_listening(); i_set } None => { ElectricCurrent::new::(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_status(&mut self) -> ld_pwr_exc_protector::Status { LdPwrExcProtector::get_status() } pub fn pd_mon_clear_alarm(&mut self) { LdPwrExcProtector::clear_alarm_status(); } pub fn set_pd_responsitivity(&mut self, responsitivity: pd_responsitivity::ResponsitivityUnit){ self.settings.pd_responsitivity.set(responsitivity); } pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent){ self.settings.pd_responsitivity.set_i_dark(i_dark); } pub fn set_ld_power_limit(&mut self, pwr_limit: Power){ LdPwrExcProtector::set_trigger_threshold_v(self.settings.pd_responsitivity .get_ld_i_from_ld_pwr(pwr_limit) / Settings::PD_MON_TRANSCONDUCTANCE ); } 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 { StatusReport { pwr_on: LdPwrExcProtector::get_status().pwr_engaged, pwr_excursion: LdPwrExcProtector::get_status().pwr_excursion, ld_i_set: self.settings.ld_drive_current, 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_responsitivity: settings.pd_responsitivity, ld_pwr_limit: settings.ld_pwr_limit, } } } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] pub struct LdSettingsSummary { default_pwr_on: bool, ld_drive_current: LdSettingsSummaryField, ld_drive_current_limit: LdSettingsSummaryField, pd_responsitivity: pd_responsitivity::Parameters, ld_pwr_limit: Power, } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Tree)] pub struct LdSettingsSummaryField { value: T, max: T, }