Skip to content
Draft
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
93bac53
add payload mode
yudataguy Nov 26, 2025
e027055
update sdd
yudataguy Nov 26, 2025
f8336e0
Update FprimeZephyrReference/Components/ModeManager/docs/sdd.md
yudataguy Nov 26, 2025
2809b15
Update FprimeZephyrReference/Components/ModeManager/docs/sdd.md
yudataguy Nov 26, 2025
1e8d449
fix restore payload - face issues, update sdd
yudataguy Nov 26, 2025
b4ce7d4
resolve conflict sdd
yudataguy Nov 26, 2025
62a100c
consistency
yudataguy Nov 26, 2025
05ff516
remove component calling safe mode
yudataguy Nov 26, 2025
fddb10f
change mode enum values
yudataguy Nov 27, 2025
a7d5508
fix the safe mode emit spam
yudataguy Nov 27, 2025
5b0cc7e
update ci run group to sam (temp)
yudataguy Nov 29, 2025
286cd57
rever runner group
yudataguy Nov 29, 2025
4886c64
Merge branch 'main' of github.com:Open-Source-Space-Foundation/proves…
ineskhou Nov 29, 2025
3981691
update hibernation mode
yudataguy Nov 30, 2025
cba9372
fix test force exit issue
yudataguy Nov 30, 2025
ae69c62
fix test force exit issue
yudataguy Nov 30, 2025
569e0ea
fix some issue
yudataguy Nov 30, 2025
b931205
Update FprimeZephyrReference/Components/ModeManager/PicoSleep.cpp
yudataguy Nov 30, 2025
941a068
Update FprimeZephyrReference/Components/ModeManager/PicoSleep.cpp
yudataguy Nov 30, 2025
4faabc9
Update FprimeZephyrReference/Components/ModeManager/PicoSleep.cpp
yudataguy Nov 30, 2025
1122b30
Update FprimeZephyrReference/Components/ModeManager/docs/sdd.md
yudataguy Nov 30, 2025
d9d3d4c
Update FprimeZephyrReference/Components/ModeManager/PicoSleep.cpp
yudataguy Nov 30, 2025
57f963a
Update FprimeZephyrReference/Components/ModeManager/PicoSleep.cpp
yudataguy Nov 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ register_fprime_library(
"${CMAKE_CURRENT_LIST_DIR}/ModeManager.fpp"
SOURCES
"${CMAKE_CURRENT_LIST_DIR}/ModeManager.cpp"
"${CMAKE_CURRENT_LIST_DIR}/PicoSleep.cpp"
# DEPENDS
# MyPackage_MyOtherModule
)
403 changes: 389 additions & 14 deletions FprimeZephyrReference/Components/ModeManager/ModeManager.cpp

Large diffs are not rendered by default.

91 changes: 90 additions & 1 deletion FprimeZephyrReference/Components/ModeManager/ModeManager.fpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ module Components {

@ System mode enumeration
enum SystemMode {
NORMAL = 0 @< Normal operational mode
HIBERNATION_MODE = 0 @< Ultra-low-power hibernation with periodic wake windows
SAFE_MODE = 1 @< Safe mode with non-critical components powered off
NORMAL = 2 @< Normal operational mode
PAYLOAD_MODE = 3 @< Payload mode with payload power and battery enabled
}

@ Port for notifying about mode changes
Expand Down Expand Up @@ -57,6 +59,28 @@ module Components {
@ Only succeeds if currently in safe mode
sync command EXIT_SAFE_MODE()

@ Command to enter payload mode
@ Only succeeds if currently in normal mode
sync command ENTER_PAYLOAD_MODE()

@ Command to exit payload mode
@ Only succeeds if currently in payload mode
sync command EXIT_PAYLOAD_MODE()

@ Command to enter hibernation mode (only from SAFE_MODE)
@ Uses RP2350 dormant mode with RTC alarm wake
@ sleepDurationSec: Duration of each sleep cycle in seconds (default 3600 = 60 min)
@ wakeDurationSec: Duration of each wake window in seconds (default 60 = 1 min)
sync command ENTER_HIBERNATION(
sleepDurationSec: U32 @< Sleep cycle duration in seconds (0 = default 3600)
wakeDurationSec: U32 @< Wake window duration in seconds (0 = default 60)
)

@ Command to exit hibernation mode
@ Only succeeds if currently in hibernation mode wake window
@ Transitions to SAFE_MODE
sync command EXIT_HIBERNATION()

# ----------------------------------------------------------------------
# Events
# ----------------------------------------------------------------------
Expand All @@ -83,6 +107,22 @@ module Components {
severity warning high \
format "External fault detected - external component forced safe mode"

@ Event emitted when entering payload mode
event EnteringPayloadMode(
reason: string size 100 @< Reason for entering payload mode
) \
severity activity high \
format "ENTERING PAYLOAD MODE: {}"

@ Event emitted when exiting payload mode
event ExitingPayloadMode() \
severity activity high \
format "Exiting payload mode"

@ Event emitted when payload mode is manually commanded
event ManualPayloadModeEntry() \
severity activity high \
format "Payload mode entry commanded manually"

@ Event emitted when command validation fails
event CommandValidationFailed(
Expand All @@ -100,6 +140,46 @@ module Components {
severity warning low \
format "State persistence {} failed with status {}"

@ Event emitted when entering hibernation mode
event EnteringHibernation(
reason: string size 100 @< Reason for entering hibernation
sleepDurationSec: U32 @< Sleep cycle duration in seconds
wakeDurationSec: U32 @< Wake window duration in seconds
) \
severity warning high \
format "ENTERING HIBERNATION: {} (sleep={}s, wake={}s)"

@ Event emitted when exiting hibernation mode
event ExitingHibernation(
cycleCount: U32 @< Total hibernation cycles completed
totalSeconds: U32 @< Total time spent in hibernation
) \
severity activity high \
format "Exiting hibernation after {} cycles ({}s total)"

@ Event emitted when hibernation wake window starts
event HibernationWakeWindow(
cycleNumber: U32 @< Current wake cycle number
) \
severity activity low \
format "Hibernation wake window #{}"

@ Event emitted when starting a new hibernation sleep cycle
event HibernationSleepCycle(
cycleNumber: U32 @< Sleep cycle number starting
) \
severity activity low \
format "Hibernation sleep cycle #{} starting"

@ Event emitted when hibernation dormant sleep entry fails
@ CRITICAL: Ground already received OK response before this failure
@ Mode reverts to SAFE_MODE, counters are rolled back
event HibernationEntryFailed(
reason: string size 100 @< Reason for failure
) \
severity warning high \
format "HIBERNATION ENTRY FAILED (command ack'd OK but dormant failed): {}"

# ----------------------------------------------------------------------
# Telemetry
# ----------------------------------------------------------------------
Expand All @@ -110,6 +190,15 @@ module Components {
@ Number of times safe mode has been entered
telemetry SafeModeEntryCount: U32

@ Number of times payload mode has been entered
telemetry PayloadModeEntryCount: U32

@ Number of hibernation sleep/wake cycles completed
telemetry HibernationCycleCount: U32

@ Total time spent in hibernation (seconds)
telemetry HibernationTotalSeconds: U32


###############################################################################
# Standard AC Ports: Required for Channels, Events, Commands, and Parameters #
Expand Down
85 changes: 78 additions & 7 deletions FprimeZephyrReference/Components/ModeManager/ModeManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,28 @@ class ModeManager : public ModeManagerComponentBase {
U32 cmdSeq //!< The command sequence number
) override;

//! Handler implementation for command ENTER_PAYLOAD_MODE
void ENTER_PAYLOAD_MODE_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq //!< The command sequence number
) override;

//! Handler implementation for command EXIT_PAYLOAD_MODE
void EXIT_PAYLOAD_MODE_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq //!< The command sequence number
) override;

//! Handler implementation for command ENTER_HIBERNATION
void ENTER_HIBERNATION_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq, //!< The command sequence number
U32 sleepDurationSec, //!< Sleep cycle duration in seconds
U32 wakeDurationSec //!< Wake window duration in seconds
) override;

//! Handler implementation for command EXIT_HIBERNATION
void EXIT_HIBERNATION_cmdHandler(FwOpcodeType opCode, //!< The opcode
U32 cmdSeq //!< The command sequence number
) override;

private:
// ----------------------------------------------------------------------
// Private helper methods
Expand All @@ -87,9 +109,21 @@ class ModeManager : public ModeManagerComponentBase {
//! Exit safe mode
void exitSafeMode();

//! Enter payload mode with optional reason override
void enterPayloadMode(const char* reason = nullptr);

//! Exit payload mode
void exitPayloadMode();

//! Turn off non-critical components
void turnOffNonCriticalComponents();

//! Turn on payload (load switches 6 & 7)
void turnOnPayload();

//! Turn off payload (load switches 6 & 7)
void turnOffPayload();

//! Turn on components (restore normal operation)
void turnOnComponents();

Expand All @@ -99,26 +133,63 @@ class ModeManager : public ModeManagerComponentBase {
//! \return Current voltage (only valid if valid parameter is set to true)
F32 getCurrentVoltage(bool& valid);

//! Enter hibernation mode with configurable durations
//! \param sleepDurationSec Duration of each sleep cycle in seconds
//! \param wakeDurationSec Duration of each wake window in seconds
//! \param reason Reason for entering hibernation
void enterHibernation(U32 sleepDurationSec, U32 wakeDurationSec, const char* reason = nullptr);

//! Exit hibernation mode (transitions to SAFE_MODE)
void exitHibernation();

//! Enter dormant sleep (calls PicoSleep, does not return on success)
void enterDormantSleep();

//! Start wake window after dormant wake
void startWakeWindow();

//! Handle wake window tick (called from run_handler at 1Hz)
void handleWakeWindowTick();

// ----------------------------------------------------------------------
// Private enums and types
// ----------------------------------------------------------------------

//! System mode enumeration
enum class SystemMode : U8 { NORMAL = 0, SAFE_MODE = 1 };
enum class SystemMode : U8 {
HIBERNATION_MODE = 0, //!< Ultra-low-power hibernation with periodic wake windows
SAFE_MODE = 1, //!< Safe mode with non-critical components powered off
NORMAL = 2, //!< Normal operational mode
PAYLOAD_MODE = 3 //!< Payload mode with payload power and battery enabled
};

//! Persistent state structure
//! Persistent state structure (version 2 with hibernation support)
struct PersistentState {
U8 mode; //!< Current mode (SystemMode)
U32 safeModeEntryCount; //!< Number of times safe mode entered
U8 mode; //!< Current mode (SystemMode)
U32 safeModeEntryCount; //!< Number of times safe mode entered
U32 payloadModeEntryCount; //!< Number of times payload mode entered
U32 hibernationCycleCount; //!< Number of hibernation sleep/wake cycles
U32 hibernationTotalSeconds; //!< Total time spent in hibernation (seconds)
U32 sleepDurationSec; //!< Configured sleep cycle duration (for resume)
U32 wakeDurationSec; //!< Configured wake window duration (for resume)
};
Comment on lines +166 to 175
Copy link

Copilot AI Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Persistent state structure (version 2 with hibernation support)" but there's no version field in the struct itself, and the code doesn't handle migration from version 1 gracefully. When loading state from an old version 1 file (without the new hibernation fields), bytesRead will be less than sizeof(PersistentState), causing the code to fall through to the default initialization branch (line 277-287). While this works, it loses the old safeModeEntryCount. Consider documenting this migration behavior or adding an explicit version field to enable proper migration logic.

Copilot uses AI. Check for mistakes.

// ----------------------------------------------------------------------
// Private member variables
// ----------------------------------------------------------------------

SystemMode m_mode; //!< Current system mode
U32 m_safeModeEntryCount; //!< Counter for safe mode entries
U32 m_runCounter; //!< Counter for run handler calls (1Hz)
SystemMode m_mode; //!< Current system mode
U32 m_safeModeEntryCount; //!< Counter for safe mode entries
U32 m_payloadModeEntryCount; //!< Counter for payload mode entries
U32 m_runCounter; //!< Counter for run handler calls (1Hz)

// Hibernation state variables
bool m_inHibernationWakeWindow; //!< True if currently in wake window
U32 m_wakeWindowCounter; //!< Seconds elapsed in current wake window
U32 m_hibernationCycleCount; //!< Total hibernation cycles completed
U32 m_hibernationTotalSeconds; //!< Total seconds spent in hibernation
U32 m_sleepDurationSec; //!< Configured sleep cycle duration
U32 m_wakeDurationSec; //!< Configured wake window duration

static constexpr const char* STATE_FILE_PATH = "/mode_state.bin"; //!< State file path
};
Expand Down
55 changes: 55 additions & 0 deletions FprimeZephyrReference/Components/ModeManager/PicoSleep.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// ======================================================================
// \title PicoSleep.cpp
// \brief Implementation of RP2350 dormant mode wrapper
// ======================================================================

#include "FprimeZephyrReference/Components/ModeManager/PicoSleep.hpp"

#include <zephyr/kernel.h>
#include <zephyr/sys/reboot.h>

namespace Components {

bool PicoSleep::sleepForSeconds(U32 seconds) {
// Note: The actual RP2350 dormant mode implementation requires:
// 1. Configure RTC alarm for the specified duration
// 2. Configure POWMAN wake source to use RTC alarm
// 3. Enter dormant mode via POWMAN peripheral
//
// For now, we use sys_reboot() to simulate the sleep/wake cycle.
// The state file indicates we're in hibernation mode, so on reboot
// the system will enter the wake window and listen for EXIT_HIBERNATION.
//
// TODO: Implement actual RP2350 dormant mode using POWMAN peripheral
// when hardware testing is available.

// The seconds parameter is stored in the persistent state and would be
// used to configure the RTC alarm in a full implementation.
(void)seconds;

#if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) || defined(CONFIG_ARCH_POSIX)
// Native/simulation builds: Return false to exercise the failure handling path
// This allows CI to test HibernationEntryFailed event emission, counter rollback,
// and mode reversion to SAFE_MODE without actually rebooting.
return false;
#else
// Real hardware: Perform system reboot - the state file will indicate we're
// in hibernation and on next boot, the system will enter the wake window
sys_reboot(SYS_REBOOT_COLD);

// Should never reach here on real hardware
return false;
#endif
}

bool PicoSleep::isSupported() {
#if defined(CONFIG_BOARD_NATIVE_POSIX) || defined(CONFIG_BOARD_NATIVE_SIM) || defined(CONFIG_ARCH_POSIX)
// Native/simulation: dormant mode is not supported (returns false to exercise failure path)
return false;
#else
// RP2350 supports dormant mode, but our implementation uses reboot as placeholder
return true;
#endif
}

} // namespace Components
52 changes: 52 additions & 0 deletions FprimeZephyrReference/Components/ModeManager/PicoSleep.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// ======================================================================
// \title PicoSleep.hpp
// \brief Wrapper for RP2350 dormant mode using RTC alarm wake
// ======================================================================

#ifndef Components_PicoSleep_HPP
#define Components_PicoSleep_HPP

#include "Fw/Types/BasicTypes.hpp"

namespace Components {

/**
* @brief Wrapper class for RP2350 Pico SDK dormant mode functionality
*
* The RP2350's dormant mode puts the chip into an ultra-low-power state
* where only the RTC continues running. When the RTC alarm fires, the
* system reboots (not resumes).
*
* IMPORTANT: sleepForSeconds() does NOT return. The system will reboot
* when the RTC alarm fires. State must be persisted before calling.
*/
class PicoSleep {
public:
/**
* @brief Enter dormant mode for specified duration
*
* Configures the RTC alarm and enters RP2350 dormant mode.
* This function does NOT return - the system will reboot when
* the RTC alarm fires.
*
* @param seconds Duration to sleep in seconds
* @return false if dormant mode entry failed (function returns),
* true is never returned (system reboots on success)
*/
static bool sleepForSeconds(U32 seconds);

/**
* @brief Check if dormant mode is supported on this platform
*
* @return true if dormant mode is available
*/
static bool isSupported();

private:
// Prevent instantiation
PicoSleep() = delete;
};

} // namespace Components

#endif
Loading
Loading