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
This commit is contained in:
parent
1111967a7b
commit
86e6d3764e
@ -2,6 +2,7 @@ use core::marker::PhantomData;
|
|||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use miniconf::Tree;
|
use miniconf::Tree;
|
||||||
|
use num_traits::Zero;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use stm32f4xx_hal::{pac::{ADC3, TIM2},
|
use stm32f4xx_hal::{pac::{ADC3, TIM2},
|
||||||
timer::CounterUs};
|
timer::CounterUs};
|
||||||
@ -42,6 +43,7 @@ struct Settings {
|
|||||||
pd_mon_params: pd_mon_params::Parameters,
|
pd_mon_params: pd_mon_params::Parameters,
|
||||||
ld_pwr_limit: Power,
|
ld_pwr_limit: Power,
|
||||||
ld_terms_short: bool,
|
ld_terms_short: bool,
|
||||||
|
incoming_pd_mon_params: pd_mon_params::Parameters,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
@ -51,6 +53,7 @@ impl Default for Settings {
|
|||||||
default_pwr_on: false,
|
default_pwr_on: false,
|
||||||
ld_drive_current: ElectricCurrent::new::<milliampere>(0.0),
|
ld_drive_current: ElectricCurrent::new::<milliampere>(0.0),
|
||||||
pd_mon_params: pd_mon_params::Parameters::default(),
|
pd_mon_params: pd_mon_params::Parameters::default(),
|
||||||
|
incoming_pd_mon_params: pd_mon_params::Parameters::default(),
|
||||||
ld_pwr_limit: Power::new::<milliwatt>(0.0),
|
ld_pwr_limit: Power::new::<milliwatt>(0.0),
|
||||||
ld_terms_short: false,
|
ld_terms_short: false,
|
||||||
}
|
}
|
||||||
@ -181,24 +184,51 @@ impl LdDrive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) {
|
pub fn set_pd_responsitivity(&mut self, responsitivity: pd_mon_params::ResponsitivityUnit) {
|
||||||
self.settings.pd_mon_params.set(responsitivity);
|
self.settings.incoming_pd_mon_params.set_responsitivity(responsitivity);
|
||||||
self.set_ld_power_limit(self.settings.ld_pwr_limit)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) {
|
pub fn set_pd_dark_current(&mut self, i_dark: ElectricCurrent) {
|
||||||
self.settings.pd_mon_params.set_i_dark(i_dark);
|
self.settings.incoming_pd_mon_params.set_i_dark(i_dark);
|
||||||
self.set_ld_power_limit(self.settings.ld_pwr_limit)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ld_power_limit(&mut self, pwr_limit: Power) {
|
pub fn apply_pd_params(&mut self) -> bool {
|
||||||
LdPwrExcProtector::set_trigger_threshold_v(
|
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.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) {
|
pub fn get_ld_power_limit_range(&mut self) -> Power {
|
||||||
LdPwrExcProtector::set_trigger_threshold_v(i / self.settings.pd_mon_params.transconductance);
|
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) {
|
pub fn set_default_pwr_on(&mut self, pwr_on: bool) {
|
||||||
@ -234,7 +264,10 @@ impl LdDrive {
|
|||||||
max: Settings::LD_CURRENT_MAX,
|
max: Settings::LD_CURRENT_MAX,
|
||||||
},
|
},
|
||||||
pd_mon_params: settings.pd_mon_params,
|
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,
|
ld_terms_short: settings.ld_terms_short,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -243,10 +276,10 @@ impl LdDrive {
|
|||||||
self.power_down();
|
self.power_down();
|
||||||
self.settings.ld_drive_current = settings.ld_drive_current.value;
|
self.settings.ld_drive_current = settings.ld_drive_current.value;
|
||||||
self.settings.pd_mon_params = settings.pd_mon_params;
|
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.settings.default_pwr_on = settings.default_pwr_on;
|
||||||
|
self.set_ld_power_limit(self.settings.ld_pwr_limit);
|
||||||
self.set_ld_power_limit(settings.ld_pwr_limit);
|
|
||||||
|
|
||||||
if self.settings.ld_terms_short {
|
if self.settings.ld_terms_short {
|
||||||
self.ld_short();
|
self.ld_short();
|
||||||
@ -267,7 +300,7 @@ pub struct LdSettingsSummary {
|
|||||||
default_pwr_on: bool,
|
default_pwr_on: bool,
|
||||||
ld_drive_current: LdSettingsSummaryField<ElectricCurrent>,
|
ld_drive_current: LdSettingsSummaryField<ElectricCurrent>,
|
||||||
pd_mon_params: pd_mon_params::Parameters,
|
pd_mon_params: pd_mon_params::Parameters,
|
||||||
ld_pwr_limit: Power,
|
ld_pwr_limit: LdSettingsSummaryField<Power>,
|
||||||
ld_terms_short: bool,
|
ld_terms_short: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use num_traits::Zero;
|
use num_traits::{Float, Zero};
|
||||||
use stm32f4xx_hal::{adc::{config::{self, AdcConfig},
|
use stm32f4xx_hal::{adc::{config::{self, AdcConfig},
|
||||||
Adc},
|
Adc},
|
||||||
gpio::{gpioa::PA3, gpiod::PD9, Analog, Output, PushPull},
|
gpio::{gpioa::PA3, gpiod::PD9, Analog, Output, PushPull},
|
||||||
@ -167,14 +167,18 @@ impl LdPwrExcProtector {
|
|||||||
ElectricPotential::new::<millivolt>(0.0)
|
ElectricPotential::new::<millivolt>(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() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
let code: u32 = ((((htr / (ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32))).get::<ratio>()
|
let code: u32 = (((htr / (ElectricPotential::new::<millivolt>(wdg.calibrated_vdda as f32))).get::<ratio>()
|
||||||
* (MAX_SAMPLE as f32)) as u32)
|
* (MAX_SAMPLE as f32))
|
||||||
+ wdg.offset)
|
.ceil() as u32)
|
||||||
.min(MAX_SAMPLE as u32);
|
+ wdg.offset;
|
||||||
wdg.pac.htr.write(|w| unsafe { w.bits(code) });
|
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) {
|
pub fn set_calibrated_vdda(val: u32) {
|
||||||
@ -209,6 +213,15 @@ impl LdPwrExcProtector {
|
|||||||
Status::default()
|
Status::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_settable_volt_range() -> ElectricPotential {
|
||||||
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
|
return ElectricPotential::new::<millivolt>(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() {
|
pub fn pwr_on_and_arm_protection() {
|
||||||
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
if let Some(ref mut wdg) = LdPwrExcProtector::get() {
|
||||||
if !wdg.alarm_status.pwr_excursion {
|
if !wdg.alarm_status.pwr_excursion {
|
||||||
|
@ -33,14 +33,22 @@ impl Parameters {
|
|||||||
(v * self.transconductance).max(ElectricCurrent::zero())
|
(v * self.transconductance).max(ElectricCurrent::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, responsitivity: ResponsitivityUnit) {
|
pub fn set_responsitivity(&mut self, responsitivity: ResponsitivityUnit) {
|
||||||
self.responsitivity = responsitivity;
|
self.responsitivity = responsitivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_responsitivity(&mut self) -> ResponsitivityUnit {
|
||||||
|
self.responsitivity
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_i_dark(&mut self, i_dark: ElectricCurrent) {
|
pub fn set_i_dark(&mut self, i_dark: ElectricCurrent) {
|
||||||
self.i_dark = i_dark;
|
self.i_dark = i_dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_i_dark(&mut self) -> ElectricCurrent {
|
||||||
|
self.i_dark
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_transconductance(&mut self, transconductance: ElectricalConductance) {
|
pub fn set_transconductance(&mut self, transconductance: ElectricalConductance) {
|
||||||
self.transconductance = transconductance;
|
self.transconductance = transconductance;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ pub enum ResponseEnum {
|
|||||||
HwRev,
|
HwRev,
|
||||||
Acknowledge,
|
Acknowledge,
|
||||||
InvalidDatatype,
|
InvalidDatatype,
|
||||||
|
InvalidSettings,
|
||||||
InvalidCmd,
|
InvalidCmd,
|
||||||
HardReset,
|
HardReset,
|
||||||
Dfu,
|
Dfu,
|
||||||
@ -89,6 +90,7 @@ enum LdCmdEnum {
|
|||||||
// PD Mon Related
|
// PD Mon Related
|
||||||
SetPdResponsitivity,
|
SetPdResponsitivity,
|
||||||
SetPdDarkCurrent,
|
SetPdDarkCurrent,
|
||||||
|
ApplyPdParams,
|
||||||
SetLdPwrLimit,
|
SetLdPwrLimit,
|
||||||
ClearAlarm,
|
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_SINC3ODR: &str = "Required field \"sinc3odr\" does not exist";
|
||||||
const ERR_MSG_MISSING_POSTFILTER: &str = "Required field \"PostFilter\" 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_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)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default, Tree)]
|
||||||
pub struct CmdJsonObj {
|
pub struct CmdJsonObj {
|
||||||
@ -453,12 +457,12 @@ pub fn execute_cmd(
|
|||||||
},
|
},
|
||||||
Some(LdCmdEnum::SetPdResponsitivity) => match cmd.json.data_f32 {
|
Some(LdCmdEnum::SetPdResponsitivity) => match cmd.json.data_f32 {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
|
||||||
laser.set_pd_responsitivity(ResponsitivityUnit {
|
laser.set_pd_responsitivity(ResponsitivityUnit {
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
units: PhantomData,
|
units: PhantomData,
|
||||||
value: val,
|
value: val,
|
||||||
})
|
});
|
||||||
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
send_response(
|
send_response(
|
||||||
@ -471,8 +475,8 @@ pub fn execute_cmd(
|
|||||||
},
|
},
|
||||||
Some(LdCmdEnum::SetPdDarkCurrent) => match cmd.json.data_f32 {
|
Some(LdCmdEnum::SetPdDarkCurrent) => match cmd.json.data_f32 {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
|
laser.set_pd_dark_current(ElectricCurrent::new::<ampere>(val));
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
||||||
laser.set_pd_dark_current(ElectricCurrent::new::<ampere>(val))
|
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
send_response(
|
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(LdCmdEnum::SetLdPwrLimit) => match cmd.json.data_f32 {
|
||||||
Some(val) => {
|
Some(val) => {
|
||||||
send_response(buffer, ResponseEnum::Acknowledge, None, socket);
|
let is_legal = laser.set_ld_power_limit(Power::new::<watt>(val));
|
||||||
laser.set_ld_power_limit(Power::new::<watt>(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 => {
|
None => {
|
||||||
send_response(
|
send_response(
|
||||||
|
Loading…
Reference in New Issue
Block a user