This commit is contained in:
Robin Mueller
2026-09-16 12:45:14 +02:00
parent f9da3d6ba7
commit 61c581d301
3 changed files with 99 additions and 111 deletions
+92 -84
View File
@@ -30,31 +30,29 @@ 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),
/// Inject a fault directly into the simulator, bypassing the OBSW entirely.
///
/// This talks straight to minisim's own control port (the same one the OBSW's internal sim
/// client uses), since fault injection is a test/simulation-environment capability, not
/// something the real flight software could ever ask for.
SimFault(SimFaultArgs),
}
impl Commands {
/// The OBSW component this command is addressed to, if any. `SimFault` has none, since it
/// never goes through the OBSW.
#[inline]
pub fn target_id(&self) -> Option<types::ComponentId> {
match self {
Commands::Mgm0(_mgm_args) => Some(types::ComponentId::AcsMgm0),
Commands::Mgm1(_mgm_args) => Some(types::ComponentId::AcsMgm1),
Commands::MgmAssy(_mgm_assembly_args) => Some(types::ComponentId::AcsMgmAssembly),
Commands::AcsSubsystem(_subsystem_args) => Some(types::ComponentId::AcsSubsystem),
Commands::SimFault(_) => None,
}
}
#[derive(clap::Subcommand)]
enum SimCommand {
Fault(SimFaultArgs),
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, clap::Parser)]
@@ -129,6 +127,69 @@ pub enum SubsystemModeSelect {
Safe,
}
fn handle_mgm_command(
client: &UdpSocket,
addr: SocketAddr,
target_id: types::ComponentId,
args: MgmArgs,
) {
if args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, types::MessageType::Ping),
types::acs::mgm::request::Request::Ping,
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
"sending {:?} ping request with TC ID {:#010x}",
target_id,
sent_tc_id.raw()
);
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
if args.request_hk {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, types::MessageType::Hk),
types::acs::mgm::request::Request::Hk(HkRequest {
id: types::acs::mgm::request::HkId::Sensor,
req_type: types::HkRequestType::OneShot,
}),
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
"sending {:?} HK request with TC ID {:#010x}",
target_id,
sent_tc_id.raw()
);
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
if let Some(mode) = args.mode {
let dev_mode = match mode {
DeviceModeSelect::Off => types::DeviceMode::Off,
DeviceModeSelect::Normal => types::DeviceMode::Normal,
};
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, types::MessageType::Mode),
types::acs::mgm::request::Request::Mode(
types::acs::mgm::request::ModeRequest::SetMode(dev_mode),
),
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
"sending {:?} HK request with TC ID {:#010x}",
target_id,
sent_tc_id.raw()
);
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
}
fn setup_logger(level: log::LevelFilter) -> Result<(), fern::InitError> {
fern::Dispatch::new()
.format(|out, message, record| {
@@ -185,68 +246,18 @@ fn main() -> anyhow::Result<()> {
client.send_to(&request_packet, addr).unwrap();
}
if let Some(cmd) = cli.commands {
let target_id = cmd.target_id();
match cmd {
Commands::Mgm0(args) | Commands::Mgm1(args) => {
let target_id = target_id.expect("mgm commands always have a target id");
if args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, types::MessageType::Ping),
types::acs::mgm::request::Request::Ping,
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
"sending {:?} ping request with TC ID {:#010x}",
target_id,
sent_tc_id.raw()
);
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
if args.request_hk {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, types::MessageType::Hk),
types::acs::mgm::request::Request::Hk(HkRequest {
id: types::acs::mgm::request::HkId::Sensor,
req_type: types::HkRequestType::OneShot,
}),
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
"sending {:?} HK request with TC ID {:#010x}",
target_id,
sent_tc_id.raw()
);
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
if let Some(mode) = args.mode {
let dev_mode = match mode {
DeviceModeSelect::Off => types::DeviceMode::Off,
DeviceModeSelect::Normal => types::DeviceMode::Normal,
};
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, types::MessageType::Mode),
types::acs::mgm::request::Request::Mode(
types::acs::mgm::request::ModeRequest::SetMode(dev_mode),
),
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
"sending {:?} HK request with TC ID {:#010x}",
target_id,
sent_tc_id.raw()
);
let request_packet = request.to_vec();
client.send_to(&request_packet, addr).unwrap();
}
Commands::Sim(SimCommand::Fault(sim_fault_args)) => {
inject_sim_fault(sim_fault_args.mode.into())?;
}
Commands::MgmAssy(mgm_assembly_args) => {
let target_id = target_id.expect("mgm assembly command always has a target id");
Commands::Obsw(ObswCommand::Mgm0(args)) => {
handle_mgm_command(&client, addr, types::ComponentId::AcsMgm0, args)
}
Commands::Obsw(ObswCommand::Mgm1(args)) => {
handle_mgm_command(&client, addr, types::ComponentId::AcsMgm1, args)
}
Commands::Obsw(ObswCommand::MgmAssy(mgm_assembly_args)) => {
let target_id = types::ComponentId::AcsMgmAssembly;
if mgm_assembly_args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
@@ -292,8 +303,8 @@ fn main() -> anyhow::Result<()> {
client.send_to(&request_packet, addr).unwrap();
}
}
Commands::AcsSubsystem(subsystem_args) => {
let target_id = target_id.expect("acs subsystem command always has a target id");
Commands::Obsw(ObswCommand::AcsSubsystem(subsystem_args)) => {
let target_id = types::ComponentId::AcsSubsystem;
if subsystem_args.ping {
let request = types::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
@@ -332,9 +343,6 @@ fn main() -> anyhow::Result<()> {
client.send_to(&request_packet, addr).unwrap();
}
}
Commands::SimFault(sim_fault_args) => {
inject_sim_fault(sim_fault_args.mode.into())?;
}
}
}