continue with subsystem

This commit is contained in:
Robin Mueller
2026-05-12 13:01:23 +02:00
parent a0382a2f27
commit 5a2a070c48
6 changed files with 120 additions and 53 deletions
+3 -3
View File
@@ -207,13 +207,13 @@ fn main() -> anyhow::Result<()> {
if let Some(mode) = mgm_assembly_args.mode {
let assembly_mode = match mode {
AssemblyModeSelect::NoModeKeeping => {
models::acs::mgm_assembly::AssemblyMode::NoModeKeeping
models::acs::mgm_assembly::Mode::NoModeKeeping
}
AssemblyModeSelect::Off => {
models::acs::mgm_assembly::AssemblyMode::Device(models::DeviceMode::Off)
models::acs::mgm_assembly::Mode::Device(models::DeviceMode::Off)
}
AssemblyModeSelect::Normal => {
models::acs::mgm_assembly::AssemblyMode::Device(
models::acs::mgm_assembly::Mode::Device(
models::DeviceMode::Normal,
)
}
+23 -1
View File
@@ -1,6 +1,28 @@
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum ControllerMode {
pub enum Mode {
Passive,
Safe,
Idle,
}
pub mod request {
use super::Mode;
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ModeRequest {
SetMode(Mode),
ReadMode,
}
}
pub mod response {
use super::Mode;
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ModeReport {
/// Mode of the assembly.
Mode(super::Mode),
/// Children are in wrong mode after commanding.
WrongMode([Option<Mode>; 2]),
}
}
+9 -9
View File
@@ -3,7 +3,7 @@ use core::str::FromStr;
use crate::DeviceMode;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssemblyMode {
pub enum Mode {
/// The assembly mode ressembles the modes of the devices it controls. It also tries to keep
/// the children in the correct mode by re-commanding them into the correct mode.
Device(DeviceMode),
@@ -11,22 +11,22 @@ pub enum AssemblyMode {
NoModeKeeping,
}
impl FromStr for AssemblyMode {
impl FromStr for Mode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"off" => Ok(AssemblyMode::Device(DeviceMode::Off)),
"on" => Ok(AssemblyMode::Device(DeviceMode::On)),
"normal" => Ok(AssemblyMode::Device(DeviceMode::Normal)),
"no_mode_keeping" => Ok(AssemblyMode::NoModeKeeping),
"off" => Ok(Mode::Device(DeviceMode::Off)),
"on" => Ok(Mode::Device(DeviceMode::On)),
"normal" => Ok(Mode::Device(DeviceMode::Normal)),
"no_mode_keeping" => Ok(Mode::NoModeKeeping),
_ => Err(()),
}
}
}
pub mod request {
use crate::{HkRequestType, Message, acs::mgm_assembly::AssemblyMode};
use crate::{HkRequestType, Message, acs::mgm_assembly::Mode};
#[derive(Debug, PartialEq, Eq, Clone, Copy, serde::Serialize, serde::Deserialize)]
pub enum HkId {
@@ -35,7 +35,7 @@ pub mod request {
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ModeRequest {
SetMode(AssemblyMode),
SetMode(Mode),
ReadMode,
}
@@ -77,7 +77,7 @@ pub mod response {
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ModeReport {
/// Mode of the assembly.
Mode(super::AssemblyMode),
Mode(super::Mode),
/// Timeout failure setting the children modes.
SetModeTimeout([Option<DeviceMode>; 2]),
/// Children are in wrong mode after commanding.
+23 -1
View File
@@ -1,5 +1,27 @@
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum MgtMode {
pub enum Mode {
Off,
Normal,
}
pub mod request {
use super::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ModeRequest {
SetMode(Mode),
ReadMode,
}
}
pub mod response {
use super::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ModeReport {
/// Mode of the assembly.
Mode(super::Mode),
/// Children are in wrong mode after commanding.
WrongMode([Option<Mode>; 2]),
}
}
+26 -26
View File
@@ -2,7 +2,7 @@ use std::{sync::mpsc, time::Duration};
use models::{
ComponentId, DeviceMode,
acs::mgm_assembly::{AssemblyMode, request, response},
acs::mgm_assembly::{Mode, request, response},
};
use satrs::spacepackets::CcsdsPacketIdAndPsc;
use satrs_example::{ModeHelper, TmtcQueues};
@@ -35,7 +35,7 @@ pub struct MgmInfo {
/// MGM assembly component.
pub struct Assembly {
mode_helper: ModeHelper<AssemblyMode, TransitionState>,
mode_helper: ModeHelper<Mode, TransitionState>,
/// This boolean is used for the distinction between transitions commanded by the parent
/// or by ground, and transitions which were commanded autonomously as part of children
/// mode keeping.
@@ -56,7 +56,7 @@ impl Assembly {
mode_timeout: Duration,
) -> Self {
Self {
mode_helper: ModeHelper::new(AssemblyMode::NoModeKeeping, mode_timeout),
mode_helper: ModeHelper::new(Mode::NoModeKeeping, mode_timeout),
mode_keeping_transition: false,
tmtc_queues,
mgm_modes: [MgmInfo::default(); 2],
@@ -136,11 +136,11 @@ impl Assembly {
match self.parent_queues.request_rx.try_recv() {
Ok(request) => match request {
request::ModeRequest::SetMode(assembly_mode) => match assembly_mode {
AssemblyMode::Device(_device_mode) => {
Mode::Device(_device_mode) => {
self.start_transition(false, assembly_mode, None);
}
AssemblyMode::NoModeKeeping => {
self.mode_helper.current = AssemblyMode::NoModeKeeping;
Mode::NoModeKeeping => {
self.mode_helper.current = Mode::NoModeKeeping;
}
},
request::ModeRequest::ReadMode => self
@@ -191,7 +191,7 @@ impl Assembly {
// Transition is active, check for completion.
if self.mode_helper.transition_active()
&& self.mgm_modes.iter().all(|i| i.reply_received)
&& let AssemblyMode::Device(device_mode) = self.mode_helper.target.unwrap()
&& let Mode::Device(device_mode) = self.mode_helper.target.unwrap()
{
// If at least one child reached the correct mode, we are done.
if self.mgm_modes.iter().any(|i| i.mode == Some(device_mode)) {
@@ -207,7 +207,7 @@ impl Assembly {
}
// Mode keeping active: Check children modes.
if let AssemblyMode::Device(device_mode) = self.mode_helper.current
if let Mode::Device(device_mode) = self.mode_helper.current
&& self
.mgm_modes
.iter()
@@ -226,8 +226,8 @@ impl Assembly {
}
let target = self.mode_helper.target.unwrap();
let device_mode = match target {
AssemblyMode::Device(device_mode) => device_mode,
AssemblyMode::NoModeKeeping => {
Mode::Device(device_mode) => device_mode,
Mode::NoModeKeeping => {
self.handle_mode_reached(true);
return;
}
@@ -283,7 +283,7 @@ impl Assembly {
pub fn start_transition(
&mut self,
mode_keeping: bool,
target: AssemblyMode,
target: Mode,
tc_id: Option<CcsdsPacketIdAndPsc>,
) {
self.mode_keeping_transition = mode_keeping;
@@ -304,7 +304,7 @@ impl Assembly {
}
#[inline]
pub fn mode(&self) -> AssemblyMode {
pub fn mode(&self) -> Mode {
self.mode_helper.current
}
@@ -411,7 +411,7 @@ mod tests {
tb.assert_all_queues_empty();
tb.assembly.periodic_operation();
tb.assert_all_queues_empty();
assert_eq!(tb.assembly.mode(), AssemblyMode::NoModeKeeping);
assert_eq!(tb.assembly.mode(), Mode::NoModeKeeping);
}
#[test]
@@ -419,7 +419,7 @@ mod tests {
let mut tb = Testbench::new();
tb.tc_tx
.send(create_request_tc(mgm_assembly::request::Request::Mode(
request::ModeRequest::SetMode(AssemblyMode::Device(DeviceMode::Normal)),
request::ModeRequest::SetMode(Mode::Device(DeviceMode::Normal)),
)))
.unwrap();
tb.assembly.periodic_operation();
@@ -443,7 +443,7 @@ mod tests {
tb.assembly.periodic_operation();
assert!(!tb.assembly.mode_transition_active());
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
assert_eq!(tb.assembly.mode(), Mode::Device(DeviceMode::Normal));
let response = tb.tm_rx.try_recv().unwrap();
assert_eq!(response.tm_header.sender_id, Assembly::ID);
@@ -456,7 +456,7 @@ mod tests {
fn test_parent_commanded_transition() {
let mut tb = Testbench::new();
tb.subsystem_req_tx
.send(request::ModeRequest::SetMode(AssemblyMode::Device(
.send(request::ModeRequest::SetMode(Mode::Device(
DeviceMode::Normal,
)))
.unwrap();
@@ -481,12 +481,12 @@ mod tests {
tb.assembly.periodic_operation();
assert!(!tb.assembly.mode_transition_active());
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
assert_eq!(tb.assembly.mode(), Mode::Device(DeviceMode::Normal));
let report = tb.subsystem_report_rx.try_recv().unwrap();
assert_eq!(
report,
response::ModeReport::Mode(AssemblyMode::Device(DeviceMode::Normal))
response::ModeReport::Mode(Mode::Device(DeviceMode::Normal))
);
}
@@ -494,7 +494,7 @@ mod tests {
fn test_one_mgm_is_sufficient() {
let mut tb = Testbench::new();
tb.subsystem_req_tx
.send(request::ModeRequest::SetMode(AssemblyMode::Device(
.send(request::ModeRequest::SetMode(Mode::Device(
DeviceMode::Normal,
)))
.unwrap();
@@ -523,12 +523,12 @@ mod tests {
tb.assembly.periodic_operation();
assert!(!tb.assembly.mode_transition_active());
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
assert_eq!(tb.assembly.mode(), Mode::Device(DeviceMode::Normal));
let report = tb.subsystem_report_rx.try_recv().unwrap();
assert_eq!(
report,
response::ModeReport::Mode(AssemblyMode::Device(DeviceMode::Normal))
response::ModeReport::Mode(Mode::Device(DeviceMode::Normal))
);
}
@@ -536,7 +536,7 @@ mod tests {
fn test_mode_commanding_fails() {
let mut tb = Testbench::new();
tb.subsystem_req_tx
.send(request::ModeRequest::SetMode(AssemblyMode::Device(
.send(request::ModeRequest::SetMode(Mode::Device(
DeviceMode::Normal,
)))
.unwrap();
@@ -561,7 +561,7 @@ mod tests {
tb.assembly.periodic_operation();
assert!(!tb.assembly.mode_transition_active());
assert_eq!(tb.assembly.mode(), AssemblyMode::NoModeKeeping);
assert_eq!(tb.assembly.mode(), Mode::NoModeKeeping);
let report = tb.subsystem_report_rx.try_recv().unwrap();
assert_eq!(
@@ -574,7 +574,7 @@ mod tests {
fn test_mode_keeping_fails() {
let mut tb = Testbench::new();
tb.subsystem_req_tx
.send(request::ModeRequest::SetMode(AssemblyMode::Device(
.send(request::ModeRequest::SetMode(Mode::Device(
DeviceMode::Normal,
)))
.unwrap();
@@ -599,12 +599,12 @@ mod tests {
tb.assembly.periodic_operation();
assert!(!tb.assembly.mode_transition_active());
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
assert_eq!(tb.assembly.mode(), Mode::Device(DeviceMode::Normal));
let report = tb.subsystem_report_rx.try_recv().unwrap();
assert_eq!(
report,
response::ModeReport::Mode(AssemblyMode::Device(DeviceMode::Normal))
response::ModeReport::Mode(Mode::Device(DeviceMode::Normal))
);
for tx in tb.mgm_report_tx.iter() {
+36 -13
View File
@@ -1,3 +1,5 @@
use std::sync::mpsc::SyncSender;
use models::ComponentId;
#[derive(Debug)]
@@ -7,16 +9,16 @@ pub struct TransitionInfo {
#[derive(Debug)]
pub struct ChildModes {
mgm_assembly_mode: models::acs::mgm_assembly::AssemblyMode,
mgt_mode: models::acs::mgt::MgtMode,
controller_mode: models::acs::ctrl::ControllerMode,
mgm_assembly_mode: models::acs::mgm_assembly::Mode,
mgt_mode: models::acs::mgt::Mode,
controller_mode: models::acs::ctrl::Mode,
}
#[derive(Debug)]
pub struct TransitionCommands {
mgm_assembly_mode: Option<(models::acs::mgm_assembly::AssemblyMode, TransitionInfo)>,
mgt_mode: Option<(models::acs::mgt::MgtMode, TransitionInfo)>,
controller_mode: Option<(models::acs::ctrl::ControllerMode, TransitionInfo)>,
mgm_assembly_mode: Option<(models::acs::mgm_assembly::Mode, TransitionInfo)>,
mgt_mode: Option<(models::acs::mgt::Mode, TransitionInfo)>,
controller_mode: Option<(models::acs::ctrl::Mode, TransitionInfo)>,
}
const OFF_SEQUENCE: [TransitionCommands; 2] = [
@@ -24,7 +26,7 @@ const OFF_SEQUENCE: [TransitionCommands; 2] = [
mgm_assembly_mode: None,
mgt_mode: None,
controller_mode: Some((
models::acs::ctrl::ControllerMode::Passive,
models::acs::ctrl::Mode::Passive,
TransitionInfo {
check_mode_reached: true,
},
@@ -32,13 +34,13 @@ const OFF_SEQUENCE: [TransitionCommands; 2] = [
},
TransitionCommands {
mgm_assembly_mode: Some((
models::acs::mgm_assembly::AssemblyMode::Device(models::DeviceMode::Off),
models::acs::mgm_assembly::Mode::Device(models::DeviceMode::Off),
TransitionInfo {
check_mode_reached: false,
},
)),
mgt_mode: Some((
models::acs::mgt::MgtMode::Off,
models::acs::mgt::Mode::Off,
TransitionInfo {
check_mode_reached: false,
},
@@ -50,13 +52,13 @@ const OFF_SEQUENCE: [TransitionCommands; 2] = [
const SAFE_SEQUENCE: [TransitionCommands; 2] = [
TransitionCommands {
mgm_assembly_mode: Some((
models::acs::mgm_assembly::AssemblyMode::Device(models::DeviceMode::Normal),
models::acs::mgm_assembly::Mode::Device(models::DeviceMode::Normal),
TransitionInfo {
check_mode_reached: false,
},
)),
mgt_mode: Some((
models::acs::mgt::MgtMode::Normal,
models::acs::mgt::Mode::Normal,
TransitionInfo {
check_mode_reached: false,
},
@@ -67,7 +69,7 @@ const SAFE_SEQUENCE: [TransitionCommands; 2] = [
mgm_assembly_mode: None,
mgt_mode: None,
controller_mode: Some((
models::acs::ctrl::ControllerMode::Safe,
models::acs::ctrl::Mode::Safe,
TransitionInfo {
check_mode_reached: false,
},
@@ -75,19 +77,40 @@ const SAFE_SEQUENCE: [TransitionCommands; 2] = [
},
];
#[derive(Debug)]
pub struct ModeRequestSenders {
mode_request_ctrl: SyncSender<models::acs::ctrl::request::ModeRequest>,
mode_request_assy: SyncSender<models::acs::mgm_assembly::request::ModeRequest>,
mode_request_mgt: SyncSender<models::acs::mgt::request::ModeRequest>,
}
#[derive(Debug)]
pub struct ModeReportReceivers {
mode_response_ctrl: SyncSender<models::acs::ctrl::response::ModeReport>,
mode_response_assy: SyncSender<models::acs::mgm_assembly::response::ModeReport>,
mode_response_mgt: SyncSender<models::acs::mgt::response::ModeReport>,
}
#[derive(Debug)]
pub struct Subsystem {
current_mode: models::acs::subsystem::Mode,
current_child_modes: Option<ChildModes>,
mode_request_senders: ModeRequestSenders,
mode_report_receivers: ModeReportReceivers,
}
impl Subsystem {
pub const ID: ComponentId = ComponentId::AcsSubsystem;
pub fn new() -> Self {
pub fn new(
mode_request_senders: ModeRequestSenders,
mode_report_receivers: ModeReportReceivers,
) -> Self {
Self {
current_mode: models::acs::subsystem::Mode::Off,
current_child_modes: None,
mode_request_senders,
mode_report_receivers,
}
}
}