readability improvements
This commit is contained in:
@@ -38,10 +38,10 @@ pub const SPI_FAULT_DECREMENT_AFTER: Duration = Duration::from_secs(30);
|
||||
|
||||
// FDIR configuration for power cycle recoveries. A second recovery before the counter was
|
||||
// decremented again marks the component faulty.
|
||||
pub const RECOVERY_THRESHOLD: u32 = 1;
|
||||
pub const RECOVERY_DECREMENT_AFTER: Duration = Duration::from_secs(30 * 60);
|
||||
pub const RECOVERY_THRESHOLD: u32 = 2;
|
||||
pub const RECOVERY_DECREMENT_AFTER: Duration = Duration::from_secs(60);
|
||||
/// Time the device stays unpowered during a power cycle, so it can fully discharge.
|
||||
pub const RECOVERY_OFF_DURATION: Duration = Duration::from_secs(1);
|
||||
pub const RECOVERY_OFF_DURATION: Duration = Duration::from_millis(500);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum MgmId {
|
||||
|
||||
@@ -29,6 +29,12 @@ enum SwitchTransitionState {
|
||||
Done,
|
||||
}
|
||||
|
||||
/// Outcome of a single power switch transition.
|
||||
enum SwitchOutcome {
|
||||
Reached(Option<satrs::spacepackets::CcsdsPacketIdAndPsc>),
|
||||
Failed(Option<satrs::spacepackets::CcsdsPacketIdAndPsc>),
|
||||
}
|
||||
|
||||
/// Dedicated states for power cycling a device.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum PowerCycleState<Mode> {
|
||||
@@ -64,7 +70,7 @@ pub struct SwitchAndModeHelper<Mode: PowerSwitchedMode> {
|
||||
mode_helper: satrs_example::ModeHelper<Mode, SwitchTransitionState>,
|
||||
switch_helper: PowerSwitchHelper,
|
||||
switch_id: SwitchId,
|
||||
power_cycle: PowerCycleState<Mode>,
|
||||
power_cycle_state: PowerCycleState<Mode>,
|
||||
power_cycle_off_duration: Duration,
|
||||
}
|
||||
|
||||
@@ -79,7 +85,7 @@ impl<Mode: PowerSwitchedMode> SwitchAndModeHelper<Mode> {
|
||||
mode_helper: satrs_example::ModeHelper::new(init_mode, timeout),
|
||||
switch_helper,
|
||||
switch_id,
|
||||
power_cycle: PowerCycleState::Idle,
|
||||
power_cycle_state: PowerCycleState::Idle,
|
||||
power_cycle_off_duration: Duration::ZERO,
|
||||
}
|
||||
}
|
||||
@@ -97,7 +103,7 @@ impl<Mode: PowerSwitchedMode> SwitchAndModeHelper<Mode> {
|
||||
/// Mode which should be reported to other components. A power cycle is hidden from them,
|
||||
/// so this is the mode which is restored after the power cycle while one is active.
|
||||
pub fn reported_mode(&self) -> Mode {
|
||||
match self.power_cycle {
|
||||
match self.power_cycle_state {
|
||||
PowerCycleState::SwitchingOff { restore_mode }
|
||||
| PowerCycleState::WaitingOff { restore_mode, .. }
|
||||
| PowerCycleState::SwitchingOn { restore_mode } => restore_mode,
|
||||
@@ -107,7 +113,7 @@ impl<Mode: PowerSwitchedMode> SwitchAndModeHelper<Mode> {
|
||||
|
||||
#[inline]
|
||||
pub fn power_cycle_active(&self) -> bool {
|
||||
self.power_cycle != PowerCycleState::Idle
|
||||
self.power_cycle_state != PowerCycleState::Idle
|
||||
}
|
||||
|
||||
/// Starts a new transition, aborting a running power cycle.
|
||||
@@ -116,14 +122,14 @@ impl<Mode: PowerSwitchedMode> SwitchAndModeHelper<Mode> {
|
||||
target_mode: Mode,
|
||||
tc_commander: Option<satrs::spacepackets::CcsdsPacketIdAndPsc>,
|
||||
) {
|
||||
self.power_cycle = PowerCycleState::Idle;
|
||||
self.power_cycle_state = PowerCycleState::Idle;
|
||||
self.start_transition_internal(target_mode, tc_commander);
|
||||
}
|
||||
|
||||
/// Switches the device off, keeps it off for `off_duration` and then restores the current
|
||||
/// mode. Reaching the intermediate off mode does not generate an event.
|
||||
pub fn start_power_cycle(&mut self, off_duration: Duration) {
|
||||
self.power_cycle = PowerCycleState::SwitchingOff {
|
||||
self.power_cycle_state = PowerCycleState::SwitchingOff {
|
||||
restore_mode: self.mode(),
|
||||
};
|
||||
self.power_cycle_off_duration = off_duration;
|
||||
@@ -140,43 +146,64 @@ impl<Mode: PowerSwitchedMode> SwitchAndModeHelper<Mode> {
|
||||
}
|
||||
|
||||
/// This is the main API that the periodic handler of a device handler should call.
|
||||
///
|
||||
/// It handles the switch commanding and returns relevant events.
|
||||
pub fn handle_mode_transition(&mut self) -> Option<ModeTransitionEvent> {
|
||||
if let PowerCycleState::WaitingOff {
|
||||
restore_mode,
|
||||
since,
|
||||
} = self.power_cycle
|
||||
&& since.elapsed() >= self.power_cycle_off_duration
|
||||
{
|
||||
self.power_cycle = PowerCycleState::SwitchingOn { restore_mode };
|
||||
self.start_transition_internal(restore_mode, None);
|
||||
// The most probable case: Nothing to do.
|
||||
if self.target().is_none() && !self.power_cycle_active() {
|
||||
return None;
|
||||
}
|
||||
let event = self.handle_switch_transition()?;
|
||||
if self.power_cycle == PowerCycleState::Idle {
|
||||
return Some(event);
|
||||
// Handle this as an extra step so the switch transition after this can proceed.
|
||||
self.handle_waiting_for_off_when_power_cycling();
|
||||
// Core logic: Command the switches, check whether target switch state was reached.
|
||||
// Note the ?: if a switch transition is on-going, we might do an early return.
|
||||
let outcome = self.handle_switch_transition()?;
|
||||
// Regular mode transition without power cycling.
|
||||
if self.power_cycle_state == PowerCycleState::Idle {
|
||||
return Some(match outcome {
|
||||
SwitchOutcome::Reached(tc_commander) => ModeTransitionEvent::Reached(tc_commander),
|
||||
SwitchOutcome::Failed(tc_commander) => ModeTransitionEvent::Failed(tc_commander),
|
||||
});
|
||||
}
|
||||
match event {
|
||||
ModeTransitionEvent::Reached(_) => match self.power_cycle {
|
||||
PowerCycleState::SwitchingOff { restore_mode } => {
|
||||
self.power_cycle = PowerCycleState::WaitingOff {
|
||||
restore_mode,
|
||||
since: Instant::now(),
|
||||
};
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
self.power_cycle = PowerCycleState::Idle;
|
||||
Some(ModeTransitionEvent::PowerCycleDone)
|
||||
}
|
||||
},
|
||||
ModeTransitionEvent::Failed(_) => {
|
||||
self.power_cycle = PowerCycleState::Idle;
|
||||
Some(ModeTransitionEvent::PowerCycleFailed)
|
||||
// Power cycling, where a bit more logic is required.
|
||||
// Handle the error case first.
|
||||
if let SwitchOutcome::Failed(_) = outcome {
|
||||
self.power_cycle_state = PowerCycleState::Idle;
|
||||
return Some(ModeTransitionEvent::PowerCycleFailed);
|
||||
}
|
||||
// At this point: The switching was succesfull, so we only match on the
|
||||
// power cycle state.
|
||||
match self.power_cycle_state {
|
||||
// No switching going on for thse cases.
|
||||
PowerCycleState::Idle | PowerCycleState::WaitingOff { .. } => None,
|
||||
PowerCycleState::SwitchingOff { restore_mode } => {
|
||||
self.power_cycle_state = PowerCycleState::WaitingOff {
|
||||
restore_mode,
|
||||
since: Instant::now(),
|
||||
};
|
||||
None
|
||||
}
|
||||
PowerCycleState::SwitchingOn { .. } => {
|
||||
// Power is back and we are done.
|
||||
self.power_cycle_state = PowerCycleState::Idle;
|
||||
Some(ModeTransitionEvent::PowerCycleDone)
|
||||
}
|
||||
event => Some(event),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_switch_transition(&mut self) -> Option<ModeTransitionEvent> {
|
||||
fn handle_waiting_for_off_when_power_cycling(&mut self) {
|
||||
if let PowerCycleState::WaitingOff {
|
||||
restore_mode,
|
||||
since,
|
||||
} = self.power_cycle_state
|
||||
&& since.elapsed() >= self.power_cycle_off_duration
|
||||
{
|
||||
self.power_cycle_state = PowerCycleState::SwitchingOn { restore_mode };
|
||||
self.start_transition_internal(restore_mode, None);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_switch_transition(&mut self) -> Option<SwitchOutcome> {
|
||||
let target_mode = self.mode_helper.target?;
|
||||
let switch_target_on = target_mode.requires_power();
|
||||
if self.mode_helper.transition_state == SwitchTransitionState::Idle {
|
||||
@@ -199,11 +226,11 @@ impl<Mode: PowerSwitchedMode> SwitchAndModeHelper<Mode> {
|
||||
log::info!("switch is {}", if switch_target_on { "on" } else { "off" });
|
||||
self.mode_helper.transition_state = SwitchTransitionState::Done;
|
||||
} else if self.mode_helper.timed_out() {
|
||||
return Some(ModeTransitionEvent::Failed(self.mode_helper.finish(false)));
|
||||
return Some(SwitchOutcome::Failed(self.mode_helper.finish(false)));
|
||||
}
|
||||
}
|
||||
if self.mode_helper.transition_state == SwitchTransitionState::Done {
|
||||
return Some(ModeTransitionEvent::Reached(self.mode_helper.finish(true)));
|
||||
return Some(SwitchOutcome::Reached(self.mode_helper.finish(true)));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user