fix FDIR reaction

This commit is contained in:
Robin Mueller
2026-09-16 13:05:17 +02:00
parent 61c581d301
commit 7b9c0ca21d
3 changed files with 101 additions and 60 deletions
+23 -40
View File
@@ -30,41 +30,12 @@ pub struct Cli {
#[derive(clap::Subcommand)]
enum Commands {
/// Commands addressed to a component in the OBSW.
#[command(subcommand)]
Obsw(ObswCommand),
/// Commands that talk straight to minisim's own control port, bypassing the OBSW entirely.
///
/// This is the same control port the OBSW's internal sim client uses. Kept separate from
/// `Obsw`, since these commands have no OBSW component to address and only make sense in a
/// test/simulation environment, never something the real flight software could ask for.
#[command(subcommand)]
Sim(SimCommand),
}
#[derive(clap::Subcommand)]
enum ObswCommand {
Mgm0(MgmArgs),
Mgm1(MgmArgs),
MgmAssy(MgmAssemblyArgs),
AcsSubsystem(SubsystemArgs),
}
#[derive(clap::Subcommand)]
enum SimCommand {
Fault(SimFaultArgs),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, clap::Parser)]
struct SimFaultArgs {
/// Fault mode to inject on the simulated MGM0 SPI bus.
#[arg(value_enum)]
mode: SpiFaultModeSelect,
}
// MGM1 is not selectable here: MgmRequestLis3Mdl::TARGET is hardcoded to Mgm0Lis3Mdl, so a
// request built from this payload always reaches the MGM0 model regardless of intent. This
// appears to be a pre-existing minisim limitation, not something specific to fault injection.
#[derive(Debug, PartialEq, Eq, Clone, Copy, clap::ValueEnum)]
enum SpiFaultModeSelect {
None,
@@ -90,6 +61,12 @@ struct MgmArgs {
request_hk: bool,
#[arg(short, long)]
mode: Option<DeviceModeSelect>,
/// Inject (or clear) an SPI bus failure on the simulated device, bypassing the OBSW.
///
/// Only takes effect for MGM0: minisim always routes this fault to the MGM0 model
/// regardless of which MGM the request names (a pre-existing minisim limitation).
#[arg(long, value_enum)]
spi_fault: Option<SpiFaultModeSelect>,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, clap::Parser)]
@@ -132,7 +109,15 @@ fn handle_mgm_command(
addr: SocketAddr,
target_id: types::ComponentId,
args: MgmArgs,
) {
) -> anyhow::Result<()> {
if let Some(mode) = args.spi_fault {
if target_id != types::ComponentId::AcsMgm0 {
bail!(
"SPI fault injection is only supported for MGM0 right now (minisim limitation)"
);
}
inject_mgm_failure(mode.into())?;
}
if args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
@@ -188,6 +173,7 @@ fn handle_mgm_command(
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
Ok(())
}
fn setup_logger(level: log::LevelFilter) -> Result<(), fern::InitError> {
@@ -247,16 +233,13 @@ fn main() -> anyhow::Result<()> {
}
if let Some(cmd) = cli.commands {
match cmd {
Commands::Sim(SimCommand::Fault(sim_fault_args)) => {
inject_sim_fault(sim_fault_args.mode.into())?;
Commands::Mgm0(args) => {
handle_mgm_command(&client, addr, types::ComponentId::AcsMgm0, args)?
}
Commands::Obsw(ObswCommand::Mgm0(args)) => {
handle_mgm_command(&client, addr, types::ComponentId::AcsMgm0, args)
Commands::Mgm1(args) => {
handle_mgm_command(&client, addr, types::ComponentId::AcsMgm1, args)?
}
Commands::Obsw(ObswCommand::Mgm1(args)) => {
handle_mgm_command(&client, addr, types::ComponentId::AcsMgm1, args)
}
Commands::Obsw(ObswCommand::MgmAssy(mgm_assembly_args)) => {
Commands::MgmAssy(mgm_assembly_args) => {
let target_id = types::ComponentId::AcsMgmAssembly;
if mgm_assembly_args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
@@ -303,7 +286,7 @@ fn main() -> anyhow::Result<()> {
client.send_to(&request_packet, addr).unwrap();
}
}
Commands::Obsw(ObswCommand::AcsSubsystem(subsystem_args)) => {
Commands::AcsSubsystem(subsystem_args) => {
let target_id = types::ComponentId::AcsSubsystem;
if subsystem_args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
@@ -373,7 +356,7 @@ fn main() -> anyhow::Result<()> {
/// 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_sim_fault(mode: SpiFaultMode) -> anyhow::Result<()> {
fn inject_mgm_failure(mode: SpiFaultMode) -> 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)))?;