readability improvements

This commit is contained in:
Robin Mueller
2026-09-23 18:01:50 +02:00
parent 5363e8d529
commit d66ee8df6e
2 changed files with 68 additions and 41 deletions
+3 -3
View File
@@ -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 {
+65 -38
View File
@@ -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
}