FDIR extensions and improvements for MGM device handler
This commit is contained in:
@@ -4,7 +4,8 @@ use clap::Parser as _;
|
||||
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
|
||||
use satrs_minisim::{
|
||||
SerializableSimMsgPayload, SimComponent, SimCtrlReply, SimCtrlRequest, SimMessageProvider,
|
||||
SimReply, SimRequest, acs::MgmRequestLis3Mdl, acs::SpiFaultMode, udp::SIM_CTRL_PORT,
|
||||
SimReply, SimRequest, acs::MgmRequestLis3Mdl, acs::SpiFault, acs::SpiFaultMode,
|
||||
udp::SIM_CTRL_PORT,
|
||||
};
|
||||
use spacepackets::{CcsdsPacketIdAndPsc, SpacePacketHeader};
|
||||
use std::{
|
||||
@@ -105,6 +106,15 @@ impl From<SpiFaultModeSelect> for SpiFaultMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy, clap::ValueEnum)]
|
||||
enum SpiFaultKindSelect {
|
||||
/// Cleared when the device is switched off, so a power cycle recovers from it.
|
||||
Transient,
|
||||
/// Survives power cycles.
|
||||
#[default]
|
||||
Permanent,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, clap::ValueEnum)]
|
||||
enum HealthStateSelect {
|
||||
Healthy,
|
||||
@@ -140,6 +150,9 @@ struct MgmArgs {
|
||||
/// regardless of which MGM the request names (a pre-existing minisim limitation).
|
||||
#[arg(long, value_enum)]
|
||||
spi_fault: Option<SpiFaultModeSelect>,
|
||||
/// Whether a power cycle clears the injected SPI fault.
|
||||
#[arg(long, value_enum, default_value_t)]
|
||||
spi_fault_kind: SpiFaultKindSelect,
|
||||
/// Override the device's FDIR health state, for example to clear a `Faulty` state set by
|
||||
/// the handler after the underlying issue has been fixed or worked around.
|
||||
#[arg(long, value_enum)]
|
||||
@@ -191,7 +204,10 @@ fn handle_mgm_command(
|
||||
if target_id != types::ComponentId::AcsMgm0 {
|
||||
bail!("SPI fault injection is only supported for MGM0 right now (minisim limitation)");
|
||||
}
|
||||
inject_mgm_failure(mode.into())?;
|
||||
inject_mgm_failure(SpiFault {
|
||||
mode: mode.into(),
|
||||
cleared_by_power_cycle: args.spi_fault_kind == SpiFaultKindSelect::Transient,
|
||||
})?;
|
||||
}
|
||||
if args.ping {
|
||||
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
|
||||
@@ -477,12 +493,12 @@ fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Injects the given SPI fault mode directly into minisim's MGM0 model, bypassing the OBSW.
|
||||
/// Injects the given SPI fault directly into minisim's MGM0 model, bypassing the OBSW.
|
||||
///
|
||||
/// Confirms the simulator is actually reachable first (same ping/pong check the OBSW's own
|
||||
/// internal sim client does, see `SimClientUdp::attempt_connection`), since a fire-and-forget
|
||||
/// UDP send would otherwise silently do nothing if minisim is not running.
|
||||
fn inject_mgm_failure(mode: SpiFaultMode) -> anyhow::Result<()> {
|
||||
fn inject_mgm_failure(fault: SpiFault) -> anyhow::Result<()> {
|
||||
let sim_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), SIM_CTRL_PORT);
|
||||
let sim_socket = UdpSocket::bind("127.0.0.1:0")?;
|
||||
sim_socket.set_read_timeout(Some(Duration::from_millis(200)))?;
|
||||
@@ -514,9 +530,9 @@ fn inject_mgm_failure(mode: SpiFaultMode) -> anyhow::Result<()> {
|
||||
Err(e) => return Err(e.into()),
|
||||
}
|
||||
|
||||
let request = SimRequest::new_with_epoch_time(MgmRequestLis3Mdl::SetSpiFault(mode));
|
||||
let request = SimRequest::new_with_epoch_time(MgmRequestLis3Mdl::SetSpiFault(fault));
|
||||
sim_socket.send_to(&serde_json::to_vec(&request)?, sim_addr)?;
|
||||
log::info!("injected SPI fault mode {mode:?} into minisim MGM0");
|
||||
log::info!("injected SPI fault {fault:?} into minisim MGM0");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user