From 4c2da7cc504e9525d078386b63fd6d85325c6be0 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 24 Sep 2026 16:14:23 +0200 Subject: [PATCH] smaller fixes --- satrs-example/minisim/README.md | 4 +- satrs-example/minisim/src/acs/mgm.rs | 4 ++ satrs-example/minisim/src/acs/mgt.rs | 86 +++++++++++++++++++++++-- satrs-example/minisim/src/controller.rs | 6 ++ satrs-example/src/acs/mgt.rs | 2 +- 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/satrs-example/minisim/README.md b/satrs-example/minisim/README.md index 42f949d..b55d3e9 100644 --- a/satrs-example/minisim/README.md +++ b/satrs-example/minisim/README.md @@ -2,7 +2,7 @@ sat-rs minisim ====== This crate contains a mini-simulator based on the open-source discrete-event simulation framework -[asynchronix](https://github.com/asynchronics/asynchronix). +[nexosim](https://github.com/asynchronics/nexosim). Right now, this crate is primarily used together with the [`satrs-example` application](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs-example) @@ -29,4 +29,4 @@ still have similar device handlers. The following graph shows the high-level architecture of the mini-simulator. -Mini simulator architecture +Mini simulator architecture diff --git a/satrs-example/minisim/src/acs/mgm.rs b/satrs-example/minisim/src/acs/mgm.rs index 095c139..4684f66 100644 --- a/satrs-example/minisim/src/acs/mgm.rs +++ b/satrs-example/minisim/src/acs/mgm.rs @@ -70,6 +70,10 @@ impl MgmModel { self.external_mag_field = Some(field); } + pub async fn clear_external_magnetic_field(&mut self, _: ()) { + self.external_mag_field = None; + } + fn calculate_current_mgm_tuple(&self, time_ms: u64) -> mgm::SensorValuesMicroTesla { if SwitchStateBinary::On == self.switch_state { if let Some(ext_field) = self.external_mag_field { diff --git a/satrs-example/minisim/src/acs/mgt.rs b/satrs-example/minisim/src/acs/mgt.rs index fe97297..dbd9b96 100644 --- a/satrs-example/minisim/src/acs/mgt.rs +++ b/satrs-example/minisim/src/acs/mgt.rs @@ -15,6 +15,7 @@ pub struct MgtModel { torquing: bool, torque_dipole: mgt::Dipole, pub gen_magnetic_field: Output, + pub clear_magnetic_field: Output<()>, reply_sender: mpsc::Sender, } @@ -25,6 +26,7 @@ impl MgtModel { torquing: false, torque_dipole: mgt::Dipole::default(), gen_magnetic_field: Output::new(), + clear_magnetic_field: Output::new(), reply_sender, } } @@ -48,12 +50,15 @@ impl MgtModel { pub async fn clear_torque(&mut self, _: ()) { self.torque_dipole = mgt::Dipole::default(); self.torquing = false; - self.generate_magnetic_field(()).await; + self.clear_magnetic_field.send(()).await; } pub async fn switch_device(&mut self, switch_state: SwitchStateBinary) { self.switch_state = switch_state; - self.generate_magnetic_field(()).await; + match switch_state { + SwitchStateBinary::On => self.generate_magnetic_field(()).await, + SwitchStateBinary::Off => self.clear_torque(()).await, + } } pub async fn request_housekeeping_data(&mut self, _: (), cx: &mut Context) { @@ -97,8 +102,12 @@ impl Model for MgtModel {} mod tests { use std::time::Duration; - use satrs_minisim::{acs::mgt, SimReply, SimRequestWithTime}; - use types::pcdu::SwitchId; + use satrs_minisim::{ + acs::{mgm, mgt}, + eps::PcduRequest, + SimReply, SimRequest, SimRequestWithTime, + }; + use types::pcdu::{SwitchId, SwitchStateBinary}; use crate::{eps::tests::switch_device_on, test_helpers::SimTestbench}; @@ -166,4 +175,73 @@ mod tests { }) ); } + + /// Processes the request without stepping, so scheduled events like the torque clearing do + /// not fire. + fn process_without_step(sim_testbench: &mut SimTestbench, request: impl Into) { + sim_testbench + .send_request(SimRequestWithTime::new_with_epoch_time(request)) + .expect("sending request failed"); + sim_testbench.handle_sim_requests_time_agnostic(); + } + + fn read_mgm_0_field(sim_testbench: &mut SimTestbench) -> mgm::SensorValuesMicroTesla { + process_without_step( + sim_testbench, + SimRequest::Mgm { + id: mgm::Id::Mgm0, + request: mgm::Request::RequestSensorData, + }, + ); + let sim_reply = sim_testbench + .try_receive_next_reply() + .expect("no MGM reply received"); + let SimReply::Mgm { reply, .. } = sim_reply else { + panic!("unexpected reply {sim_reply:?}"); + }; + reply.sensor_values + } + + fn start_torquing(sim_testbench: &mut SimTestbench, duration: Duration) { + switch_device_on(sim_testbench, SwitchId::Mgm0); + switch_device_on(sim_testbench, SwitchId::Mgt); + process_without_step( + sim_testbench, + mgt::Request::ApplyTorque { + duration, + dipole: mgt::Dipole { x: 1, y: 2, z: 3 }, + }, + ); + assert_eq!(read_mgm_0_field(sim_testbench), mgm::MGT_GEN_MAGNETIC_FIELD); + } + + #[test] + fn test_mgm_field_cleared_after_torquing() { + let mut sim_testbench = SimTestbench::new(); + start_torquing(&mut sim_testbench, Duration::from_millis(100)); + sim_testbench + .step_until(Duration::from_millis(100)) + .unwrap(); + assert_ne!( + read_mgm_0_field(&mut sim_testbench), + mgm::MGT_GEN_MAGNETIC_FIELD + ); + } + + #[test] + fn test_mgm_field_cleared_by_switching_mgt_off() { + let mut sim_testbench = SimTestbench::new(); + start_torquing(&mut sim_testbench, Duration::from_millis(100)); + process_without_step( + &mut sim_testbench, + PcduRequest::SwitchDevice { + switch: SwitchId::Mgt, + state: SwitchStateBinary::Off, + }, + ); + assert_ne!( + read_mgm_0_field(&mut sim_testbench), + mgm::MGT_GEN_MAGNETIC_FIELD + ); + } } diff --git a/satrs-example/minisim/src/controller.rs b/satrs-example/minisim/src/controller.rs index 8c6eeb5..80cdd66 100644 --- a/satrs-example/minisim/src/controller.rs +++ b/satrs-example/minisim/src/controller.rs @@ -85,6 +85,12 @@ impl SimController { mgt_model .gen_magnetic_field .connect(MgmModel::apply_external_magnetic_field, &addrs.mgm_1); + mgt_model + .clear_magnetic_field + .connect(MgmModel::clear_external_magnetic_field, &addrs.mgm_0); + mgt_model + .clear_magnetic_field + .connect(MgmModel::clear_external_magnetic_field, &addrs.mgm_1); let sim_init = if threading_model == ThreadingModel::Single { SimInit::with_num_threads(1) diff --git a/satrs-example/src/acs/mgt.rs b/satrs-example/src/acs/mgt.rs index 4ab7af7..2044ef4 100644 --- a/satrs-example/src/acs/mgt.rs +++ b/satrs-example/src/acs/mgt.rs @@ -18,7 +18,7 @@ use crate::ccsds::pack_ccsds_tm_packet_for_now; use crate::device_mode::{ModeTransitionEvent, SwitchAndModeHelper}; use crate::eps::PowerSwitchHelper; -/// Ideal device which never fails. +/// Interface for ideal device which never fails. #[derive(Default)] pub struct DummyInterface { dipole: sim_mgt::Dipole,