From 86e6d3764e872a9b8b3ec2d5d161476067608127 Mon Sep 17 00:00:00 2001 From: linuswck Date: Mon, 9 Sep 2024 17:38:02 +0800 Subject: [PATCH] laser: check pd_mon params & pwr limit before set - Design to prevent Issue #47 on hardware kirdy repo from happening - responsitivity, i_dark & transconductance determine the pwr limit range - when "ApplyPdParams" and "SetLdPwrLimit" are called, pwr limit range is checked before applying new parameter - Send out a "InvalidSettings" response with error message if settings cannot be applied - Add settable power range to settings json object --- src/laser_diode/laser_diode.rs | 61 +++++++++++++++++++------ src/laser_diode/ld_pwr_exc_protector.rs | 27 ++++++++--- src/laser_diode/pd_mon_params.rs | 10 +++- src/net/cmd_handler.rs | 36 +++++++++++++-- 4 files changed, 107 insertions(+), 27 deletions(-) diff --git a/src/laser_diode/laser_diode.rs b/src/laser_diode/laser_diode.rs index 9d1229b..be024f6 100644 --- a/src/laser_diode/laser_diode.rs +++ b/src/laser_diode/laser_diode.rs @@ -2,6 +2,7 @@ use core::marker::PhantomData; use log::info; use miniconf::Tree; +use num_traits::Zero; use serde::{Deserialize, Serialize}; use stm32f4xx_hal::{pac::{ADC3, TIM2}, timer::CounterUs}; @@ -42,6 +43,7 @@ struct Settings { pd_mon_params: pd_mon_params::Parameters, ld_pwr_limit: Power, ld_terms_short: bool, + incoming_pd_mon_params: pd_mon_params::Parameters, } impl Default for Settings { @@ -51,6 +53,7 @@ impl Default for Settings { default_pwr_on: false, ld_drive_current: ElectricCurrent::new::(0.0), pd_mon_params: pd_mon_params::Parameters::default(), + incoming_pd_mon_params: pd_mon_params::Parameters::default(), ld_pwr_limit: Power::new::(0.0), ld_terms_short: false, } @@ -181,24 +184,51 @@ impl LdDrive { } pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) { - self.settings.pd_mon_params.set(responsitivity); - self.set_ld_power_limit(self.settings.ld_pwr_limit) + self.settings.incoming_pd_mon_params.set_responsitivity(responsitivity); } pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) { - self.settings.pd_mon_params.set_i_dark(i_dark); - self.set_ld_power_limit(self.settings.ld_pwr_limit) + self.settings.incoming_pd_mon_params.set_i_dark(i_dark); } - pub fn set_ld_power_limit(&mut self, pwr_limit: Power) { - LdPwrExcProtector::set_trigger_threshold_v( + pub fn apply_pd_params(&mut self) -> bool { + let prev_pd_params = self.settings.pd_mon_params; + self.settings.incoming_pd_mon_params.transconductance = self.settings.pd_mon_params.transconductance; + self.settings.pd_mon_params = self.settings.incoming_pd_mon_params; + + let max_settable_pwr = self.get_ld_power_limit_range(); + let is_legal = self.settings.ld_pwr_limit <= max_settable_pwr; + if is_legal { + self.set_ld_power_limit(self.settings.ld_pwr_limit); + } else { + self.settings.pd_mon_params = prev_pd_params; + } + is_legal + } + + pub fn set_ld_power_limit(&mut self, pwr_limit: Power) -> bool { + let is_legal = LdPwrExcProtector::set_trigger_threshold_v( self.settings.pd_mon_params.get_pd_i_from_ld_pwr(pwr_limit) / self.settings.pd_mon_params.transconductance, ); - self.settings.ld_pwr_limit = pwr_limit; + if is_legal { + self.settings.ld_pwr_limit = pwr_limit; + } + is_legal } - pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) { - LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance); + pub fn get_ld_power_limit_range(&mut self) -> Power { + let v_range = LdPwrExcProtector::get_settable_volt_range(); + let i_range = self.settings.pd_mon_params.get_pd_i_from_pd_v(v_range); + let max_settable_pwr = self.settings.pd_mon_params.get_ld_pwr_from_ld_i(i_range); + if max_settable_pwr.is_nan() || max_settable_pwr.is_infinite() { + Power::zero() + } else { + max_settable_pwr + } + } + + pub fn set_pd_i_limit(&mut self, i: ElectricCurrent) -> bool { + return LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance); } pub fn set_default_pwr_on(&mut self, pwr_on: bool) { @@ -234,7 +264,10 @@ impl LdDrive { max: Settings::LD_CURRENT_MAX, }, pd_mon_params: settings.pd_mon_params, - ld_pwr_limit: settings.ld_pwr_limit, + ld_pwr_limit: LdSettingsSummaryField { + value: settings.ld_pwr_limit, + max: self.get_ld_power_limit_range(), + }, ld_terms_short: settings.ld_terms_short, } } @@ -243,10 +276,10 @@ impl LdDrive { self.power_down(); self.settings.ld_drive_current = settings.ld_drive_current.value; self.settings.pd_mon_params = settings.pd_mon_params; - self.settings.ld_pwr_limit = settings.ld_pwr_limit; + let max_pwr_limit = self.get_ld_power_limit_range(); + self.settings.ld_pwr_limit = settings.ld_pwr_limit.value.min(max_pwr_limit); self.settings.default_pwr_on = settings.default_pwr_on; - - self.set_ld_power_limit(settings.ld_pwr_limit); + self.set_ld_power_limit(self.settings.ld_pwr_limit); if self.settings.ld_terms_short { self.ld_short(); @@ -267,7 +300,7 @@ pub struct LdSettingsSummary { default_pwr_on: bool, ld_drive_current: LdSettingsSummaryField, pd_mon_params: pd_mon_params::Parameters, - ld_pwr_limit: Power, + ld_pwr_limit: LdSettingsSummaryField, ld_terms_short: bool, } diff --git a/src/laser_diode/ld_pwr_exc_protector.rs b/src/laser_diode/ld_pwr_exc_protector.rs index 01eaec3..1494909 100644 --- a/src/laser_diode/ld_pwr_exc_protector.rs +++ b/src/laser_diode/ld_pwr_exc_protector.rs @@ -1,4 +1,4 @@ -use num_traits::Zero; +use num_traits::{Float, Zero}; use stm32f4xx_hal::{adc::{config::{self, AdcConfig}, Adc}, gpio::{gpioa::PA3, gpiod::PD9, Analog, Output, PushPull}, @@ -167,14 +167,18 @@ impl LdPwrExcProtector { ElectricPotential::new::(0.0) } - pub fn set_trigger_threshold_v(htr: ElectricPotential) { + pub fn set_trigger_threshold_v(htr: ElectricPotential) -> bool { if let Some(ref mut wdg) = LdPwrExcProtector::get() { - let code: u32 = ((((htr / (ElectricPotential::new::(wdg.calibrated_vdda as f32))).get::() - * (MAX_SAMPLE as f32)) as u32) - + wdg.offset) - .min(MAX_SAMPLE as u32); - wdg.pac.htr.write(|w| unsafe { w.bits(code) }); + let code: u32 = (((htr / (ElectricPotential::new::(wdg.calibrated_vdda as f32))).get::() + * (MAX_SAMPLE as f32)) + .ceil() as u32) + + wdg.offset; + if code <= MAX_SAMPLE as u32 { + wdg.pac.htr.write(|w| unsafe { w.bits(code) }); + return true; + } } + false } pub fn set_calibrated_vdda(val: u32) { @@ -209,6 +213,15 @@ impl LdPwrExcProtector { Status::default() } + pub fn get_settable_volt_range() -> ElectricPotential { + if let Some(ref mut wdg) = LdPwrExcProtector::get() { + return ElectricPotential::new::(wdg.calibrated_vdda as f32) + * ((MAX_SAMPLE as u32 - wdg.offset) as f32) + / MAX_SAMPLE as f32; + } + ElectricPotential::zero() + } + pub fn pwr_on_and_arm_protection() { if let Some(ref mut wdg) = LdPwrExcProtector::get() { if !wdg.alarm_status.pwr_excursion { diff --git a/src/laser_diode/pd_mon_params.rs b/src/laser_diode/pd_mon_params.rs index 12ffd9a..0e27b07 100644 --- a/src/laser_diode/pd_mon_params.rs +++ b/src/laser_diode/pd_mon_params.rs @@ -33,14 +33,22 @@ impl Parameters { (v * self.transconductance).max(ElectricCurrent::zero()) } - pub fn set(&mut self, responsitivity: ResponsitivityUnit) { + pub fn set_responsitivity(&mut self, responsitivity: ResponsitivityUnit) { self.responsitivity = responsitivity; } + pub fn get_responsitivity(&mut self) -> ResponsitivityUnit { + self.responsitivity + } + pub fn set_i_dark(&mut self, i_dark: ElectricCurrent) { self.i_dark = i_dark; } + pub fn get_i_dark(&mut self) -> ElectricCurrent { + self.i_dark + } + pub fn set_transconductance(&mut self, transconductance: ElectricalConductance) { self.transconductance = transconductance; } diff --git a/src/net/cmd_handler.rs b/src/net/cmd_handler.rs index fc5728a..a6b943b 100644 --- a/src/net/cmd_handler.rs +++ b/src/net/cmd_handler.rs @@ -29,6 +29,7 @@ pub enum ResponseEnum { HwRev, Acknowledge, InvalidDatatype, + InvalidSettings, InvalidCmd, HardReset, Dfu, @@ -89,6 +90,7 @@ enum LdCmdEnum { // PD Mon Related SetPdResponsitivity, SetPdDarkCurrent, + ApplyPdParams, SetLdPwrLimit, ClearAlarm, } @@ -135,6 +137,8 @@ const ERR_MSG_MISSING_SINC5SINC1ODR: &str = "Required field \"sinc5sinc1odr\" do const ERR_MSG_MISSING_SINC3ODR: &str = "Required field \"sinc3odr\" does not exist"; const ERR_MSG_MISSING_POSTFILTER: &str = "Required field \"PostFilter\" does not exist"; const ERR_MSG_MISSING_SINC3FINEODR: &str = "Required field \"sinc3fineodr\" does not exist"; +const ERR_MSG_INVALID_PDMON_SETTINGS: &str = "Invalid PD Mon Parameter Setting(s)"; +const ERR_MSG_INVALID_LD_PWR_LIMIT_SETTING: &str = "Invalid LD Power Limit Setting"; #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)] pub struct CmdJsonObj { @@ -453,12 +457,12 @@ pub fn execute_cmd( }, Some(LdCmdEnum::SetPdResponsitivity) => match cmd.json.data_f32 { Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); laser.set_pd_responsitivity(ResponsitivityUnit { dimension: PhantomData, units: PhantomData, value: val, - }) + }); + send_response(buffer, ResponseEnum::Acknowledge, None, socket); } None => { send_response( @@ -471,8 +475,8 @@ pub fn execute_cmd( }, Some(LdCmdEnum::SetPdDarkCurrent) => match cmd.json.data_f32 { Some(val) => { + laser.set_pd_dark_current(ElectricCurrent::new::(val)); send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_pd_dark_current(ElectricCurrent::new::(val)) } None => { send_response( @@ -483,10 +487,32 @@ pub fn execute_cmd( ); } }, + Some(LdCmdEnum::ApplyPdParams) => { + let is_legal = laser.apply_pd_params(); + if is_legal { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + } else { + send_response( + buffer, + ResponseEnum::InvalidSettings, + Some(ERR_MSG_INVALID_PDMON_SETTINGS), + socket, + ) + } + } Some(LdCmdEnum::SetLdPwrLimit) => match cmd.json.data_f32 { Some(val) => { - send_response(buffer, ResponseEnum::Acknowledge, None, socket); - laser.set_ld_power_limit(Power::new::(val)) + let is_legal = laser.set_ld_power_limit(Power::new::(val)); + if is_legal { + send_response(buffer, ResponseEnum::Acknowledge, None, socket); + } else { + send_response( + buffer, + ResponseEnum::InvalidSettings, + Some(ERR_MSG_INVALID_LD_PWR_LIMIT_SETTING), + socket, + ) + } } None => { send_response(