start adding ACS subsystem #266

Open
muellerr wants to merge 2 commits from start-adding-acs-subsys into main
14 changed files with 316 additions and 112 deletions
+19 -16
View File
@@ -1,7 +1,7 @@
use anyhow::bail;
use arbitrary_int::u11;
use clap::Parser as _;
use models::{Apid, MessageType, TcHeader, mgm::request::HkRequest};
use models::{Apid, MessageType, TcHeader, acs::mgm::request::HkRequest};
use satrs_example::config::{OBSW_SERVER_ADDR, SERVER_PORT};
use spacepackets::{CcsdsPacketIdAndPsc, SpacePacketHeader};
use std::{
@@ -136,7 +136,7 @@ fn main() -> anyhow::Result<()> {
let request = models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(cmd.target_id(), models::MessageType::Ping),
models::mgm::request::Request::Ping,
models::acs::mgm::request::Request::Ping,
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
@@ -151,8 +151,8 @@ fn main() -> anyhow::Result<()> {
let request = models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, models::MessageType::Hk),
models::mgm::request::Request::Hk(HkRequest {
id: models::mgm::request::HkId::Sensor,
models::acs::mgm::request::Request::Hk(HkRequest {
id: models::acs::mgm::request::HkId::Sensor,
req_type: models::HkRequestType::OneShot,
}),
);
@@ -174,8 +174,8 @@ fn main() -> anyhow::Result<()> {
let request = models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, models::MessageType::Mode),
models::mgm::request::Request::Mode(
models::mgm::request::ModeRequest::SetMode(dev_mode),
models::acs::mgm::request::Request::Mode(
models::acs::mgm::request::ModeRequest::SetMode(dev_mode),
),
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
@@ -193,7 +193,7 @@ fn main() -> anyhow::Result<()> {
let request = models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(cmd.target_id(), models::MessageType::Ping),
models::mgm::request::Request::Ping,
models::acs::mgm::request::Request::Ping,
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
log::info!(
@@ -207,21 +207,23 @@ fn main() -> anyhow::Result<()> {
if let Some(mode) = mgm_assembly_args.mode {
let assembly_mode = match mode {
AssemblyModeSelect::NoModeKeeping => {
models::mgm_assembly::AssemblyMode::NoModeKeeping
models::acs::mgm_assembly::Mode::NoModeKeeping
}
AssemblyModeSelect::Off => {
models::mgm_assembly::AssemblyMode::Device(models::DeviceMode::Off)
models::acs::mgm_assembly::Mode::Device(models::DeviceMode::Off)
}
AssemblyModeSelect::Normal => {
models::mgm_assembly::AssemblyMode::Device(models::DeviceMode::Normal)
models::acs::mgm_assembly::Mode::Device(
models::DeviceMode::Normal,
)
}
};
let request = models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
TcHeader::new(target_id, models::MessageType::Mode),
models::mgm_assembly::request::Request::Mode(
models::mgm_assembly::request::ModeRequest::SetMode(assembly_mode),
models::acs::mgm_assembly::request::Request::Mode(
models::acs::mgm_assembly::request::ModeRequest::SetMode(assembly_mode),
),
);
let sent_tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&request.sp_header);
@@ -304,8 +306,9 @@ fn handle_raw_tm_packet(data: &[u8]) -> anyhow::Result<()> {
}
models::ComponentId::AcsSubsystem => todo!(),
models::ComponentId::AcsMgmAssembly => {
let response =
postcard::from_bytes::<models::mgm_assembly::response::Response>(remainder);
let response = postcard::from_bytes::<
models::acs::mgm_assembly::response::Response,
>(remainder);
log::info!(
"Received response from MGM Assembly: {:?}",
response.unwrap()
@@ -313,12 +316,12 @@ fn handle_raw_tm_packet(data: &[u8]) -> anyhow::Result<()> {
}
models::ComponentId::AcsMgm0 => {
let response =
postcard::from_bytes::<models::mgm::response::Response>(remainder);
postcard::from_bytes::<models::acs::mgm::response::Response>(remainder);
log::info!("Received response from MGM0: {:?}", response.unwrap());
}
models::ComponentId::AcsMgm1 => {
let response =
postcard::from_bytes::<models::mgm::response::Response>(remainder);
postcard::from_bytes::<models::acs::mgm::response::Response>(remainder);
log::info!("Received response from MGM1: {:?}", response.unwrap());
}
models::ComponentId::EpsSubsystem => todo!(),
+28
View File
@@ -0,0 +1,28 @@
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
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]),
}
}
@@ -42,7 +42,7 @@ pub mod request {
}
#[derive(Default, Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
pub struct MgmData {
pub struct SensorData {
pub valid: bool,
pub x: f32,
pub y: f32,
@@ -50,11 +50,11 @@ pub struct MgmData {
}
pub mod response {
use crate::{DeviceMode, Message, mgm::MgmData};
use crate::{DeviceMode, Message, acs::mgm::SensorData};
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
pub enum HkResponse {
MgmData(MgmData),
MgmData(SensorData),
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy)]
@@ -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, 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.
+27
View File
@@ -0,0 +1,27 @@
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
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]),
}
}
+5
View File
@@ -0,0 +1,5 @@
pub mod ctrl;
pub mod mgm;
pub mod mgm_assembly;
pub mod mgt;
pub mod subsystem;
+15
View File
@@ -0,0 +1,15 @@
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
Off,
Safe,
}
impl Mode {
/// Each subsystem mode has a fallback mode to allow clean transitions.
pub const fn fallback_mode(&self) -> Self {
match self {
Mode::Off => Mode::Safe,
Mode::Safe => Mode::Safe,
}
}
}
+1 -2
View File
@@ -6,10 +6,9 @@ use spacepackets::{
time::cds::{CdsTime, MIN_CDS_FIELD_LEN},
};
pub mod acs;
pub mod ccsds;
pub mod control;
pub mod mgm;
pub mod mgm_assembly;
pub mod pcdu;
#[derive(
+25 -21
View File
@@ -1,8 +1,8 @@
use models::mgm::MgmData;
use models::mgm::request::ModeRequest;
use models::mgm::response::ModeResponse;
use models::acs::mgm::SensorData;
use models::acs::mgm::request::ModeRequest;
use models::acs::mgm::response::ModeResponse;
use models::pcdu::SwitchId;
use models::{ComponentId, DeviceMode, HkRequestType, mgm};
use models::{ComponentId, DeviceMode, HkRequestType, acs::mgm};
use satrs::spacepackets::CcsdsPacketIdAndPsc;
use satrs_example::{HkHelperSingleSet, ModeHelper, TimestampHelper, TmtcQueues};
use satrs_minisim::acs::MgmRequestLis3Mdl;
@@ -153,7 +153,7 @@ pub struct MgmHandlerLis3Mdl {
switch_helper: PowerSwitchHelper,
tmtc_queues: TmtcQueues,
pub spi_com: SpiCommunication,
shared_mgm_set: Arc<Mutex<MgmData>>,
shared_mgm_set: Arc<Mutex<SensorData>>,
buffers: BufWrapper,
stamp_helper: TimestampHelper,
hk_helper: HkHelperSingleSet,
@@ -167,9 +167,9 @@ impl MgmHandlerLis3Mdl {
tmtc_queues: TmtcQueues,
switch_helper: PowerSwitchHelper,
spi_com: SpiCommunication,
shared_mgm_set: Arc<Mutex<MgmData>>,
shared_mgm_set: Arc<Mutex<SensorData>>,
mode_leaf_helper: ModeLeafHelper,
mode_timeout: Duration
mode_timeout: Duration,
) -> Self {
Self {
id,
@@ -308,7 +308,7 @@ impl MgmHandlerLis3Mdl {
pub fn handle_hk_request(
&mut self,
tc_id: Option<CcsdsPacketIdAndPsc>,
hk_request: &models::mgm::request::HkRequest,
hk_request: &models::acs::mgm::request::HkRequest,
) {
match hk_request.req_type {
HkRequestType::OneShot => {
@@ -462,8 +462,8 @@ mod tests {
use arbitrary_int::u11;
use models::{
Apid, ComponentId, TcHeader,
acs::mgm::request::HkRequest,
ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned},
mgm::request::HkRequest,
pcdu::{SwitchRequest, SwitchState, SwitchStateBinary},
};
use satrs::{request::GenericMessage, spacepackets::SpacePacketHeader};
@@ -490,7 +490,7 @@ mod tests {
pub fn create_request_tc(
select: MgmSelect,
request: models::mgm::request::Request,
request: models::acs::mgm::request::Request,
) -> models::ccsds::CcsdsTcPacketOwned {
models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
@@ -533,6 +533,7 @@ mod tests {
SpiCommunication::Test(TestSpiInterface::default()),
shared_mgm_set,
mode_leaf_helper,
Duration::from_millis(100),
);
Self {
assembly_mode_request_tx,
@@ -600,9 +601,10 @@ mod tests {
assert_eq!(tm_packet.tm_header.sender_id, ComponentId::AcsMgm0);
let response = postcard::from_bytes::<models::mgm::response::Response>(&tm_packet.payload)
.expect("failed to deserialize mode reply");
matches!(response, models::mgm::response::Response::Ok);
let response =
postcard::from_bytes::<models::acs::mgm::response::Response>(&tm_packet.payload)
.expect("failed to deserialize mode reply");
matches!(response, models::acs::mgm::response::Response::Ok);
// The device should have been polled once.
assert_eq!(testbench.test_spi_interface().call_count, 1);
let mgm_set = *testbench.handler.shared_mgm_set.lock().unwrap();
@@ -688,9 +690,10 @@ mod tests {
assert_eq!(tm_packet.tm_header.sender_id, ComponentId::AcsMgm0);
let response = postcard::from_bytes::<models::mgm::response::Response>(&tm_packet.payload)
.expect("failed to deserialize mode reply");
if let models::mgm::response::Response::Hk(mgm::response::HkResponse::MgmData(data)) =
let response =
postcard::from_bytes::<models::acs::mgm::response::Response>(&tm_packet.payload)
.expect("failed to deserialize mode reply");
if let models::acs::mgm::response::Response::Hk(mgm::response::HkResponse::MgmData(data)) =
response
{
assert_eq!(data.valid, false);
@@ -739,17 +742,18 @@ mod tests {
assert_eq!(mode_tm.tm_header.sender_id, ComponentId::AcsMgm0);
let response = postcard::from_bytes::<models::mgm::response::Response>(&mode_tm.payload)
.expect("failed to deserialize mode reply");
matches!(response, models::mgm::response::Response::Ok);
let response =
postcard::from_bytes::<models::acs::mgm::response::Response>(&mode_tm.payload)
.expect("failed to deserialize mode reply");
matches!(response, models::acs::mgm::response::Response::Ok);
let hk_tm = testbench.tm_rx.try_recv().expect("no hk reply generated");
assert_eq!(hk_tm.tm_header.sender_id, ComponentId::AcsMgm0);
let response = postcard::from_bytes::<models::mgm::response::Response>(&hk_tm.payload)
let response = postcard::from_bytes::<models::acs::mgm::response::Response>(&hk_tm.payload)
.expect("failed to deserialize mode reply");
if let models::mgm::response::Response::Hk(mgm::response::HkResponse::MgmData(data)) =
if let models::acs::mgm::response::Response::Hk(mgm::response::HkResponse::MgmData(data)) =
response
{
// Set is now valid.
+64 -56
View File
@@ -2,7 +2,7 @@ use std::{sync::mpsc, time::Duration};
use models::{
ComponentId, DeviceMode,
mgm_assembly::{AssemblyMode, request, response},
acs::mgm_assembly::{Mode, request, response},
};
use satrs::spacepackets::CcsdsPacketIdAndPsc;
use satrs_example::{ModeHelper, TmtcQueues};
@@ -16,8 +16,8 @@ pub struct ParentQueueHelper {
/// Helper component for communication with a parent component, which is usually as assembly.
pub struct ChildrenQueueHelper {
pub request_tx_queues: [mpsc::SyncSender<models::mgm::request::ModeRequest>; 2],
pub report_rx_queues: [mpsc::Receiver<models::mgm::response::ModeResponse>; 2],
pub request_tx_queues: [mpsc::SyncSender<models::acs::mgm::request::ModeRequest>; 2],
pub report_rx_queues: [mpsc::Receiver<models::acs::mgm::response::ModeResponse>; 2],
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
@@ -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],
@@ -80,14 +80,14 @@ impl Assembly {
match self.tmtc_queues.tc_rx.try_recv() {
Ok(packet) => {
let tc_id = CcsdsPacketIdAndPsc::new_from_ccsds_packet(&packet.sp_header);
match postcard::from_bytes::<models::mgm_assembly::request::Request>(
match postcard::from_bytes::<models::acs::mgm_assembly::request::Request>(
&packet.payload,
) {
Ok(request) => match request {
models::mgm_assembly::request::Request::Ping => {
models::acs::mgm_assembly::request::Request::Ping => {
self.send_telemetry(Some(tc_id), response::Response::Ok)
}
models::mgm_assembly::request::Request::Mode(request) => {
models::acs::mgm_assembly::request::Request::Mode(request) => {
match request {
request::ModeRequest::SetMode(assembly_mode) => {
self.start_transition(false, assembly_mode, Some(tc_id))
@@ -117,7 +117,7 @@ impl Assembly {
pub fn send_telemetry(
&self,
tc_id: Option<CcsdsPacketIdAndPsc>,
response: models::mgm_assembly::response::Response,
response: models::acs::mgm_assembly::response::Response,
) {
match pack_ccsds_tm_packet_for_now(Self::ID, tc_id, &response) {
Ok(packet) => {
@@ -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
@@ -165,12 +165,12 @@ impl Assembly {
loop {
match rx.try_recv() {
Ok(report) => match report {
models::mgm::response::ModeResponse::Mode(device_mode) => {
models::acs::mgm::response::ModeResponse::Mode(device_mode) => {
self.mgm_modes[idx].mode = Some(device_mode);
self.mgm_modes[idx].reply_received = true;
mode_report_received = true;
}
models::mgm::response::ModeResponse::SetModeTimeout => {
models::acs::mgm::response::ModeResponse::SetModeTimeout => {
// Ignore, handle this with our own timeout.
log::warn!("MGM {} mode timeout", idx);
}
@@ -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;
}
@@ -275,7 +275,7 @@ impl Assembly {
pub fn command_children(&self, mode: DeviceMode) {
for tx in &self.children_queues.request_tx_queues {
tx.send(models::mgm::request::ModeRequest::SetMode(mode))
tx.send(models::acs::mgm::request::ModeRequest::SetMode(mode))
.unwrap();
}
}
@@ -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
}
@@ -322,8 +322,8 @@ mod tests {
use arbitrary_int::u11;
use models::{
Apid, Message, MessageType, TcHeader,
acs::mgm_assembly,
ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned},
mgm_assembly,
};
use satrs::spacepackets::SpacePacketHeader;
@@ -332,8 +332,8 @@ mod tests {
pub struct Testbench {
subsystem_req_tx: mpsc::SyncSender<request::ModeRequest>,
subsystem_report_rx: mpsc::Receiver<response::ModeReport>,
mgm_request_rx: [mpsc::Receiver<models::mgm::request::ModeRequest>; 2],
mgm_report_tx: [mpsc::SyncSender<models::mgm::response::ModeResponse>; 2],
mgm_request_rx: [mpsc::Receiver<models::acs::mgm::request::ModeRequest>; 2],
mgm_report_tx: [mpsc::SyncSender<models::acs::mgm::response::ModeResponse>; 2],
tc_tx: mpsc::SyncSender<CcsdsTcPacketOwned>,
tm_rx: mpsc::Receiver<CcsdsTmPacketOwned>,
assembly: Assembly,
@@ -396,7 +396,7 @@ mod tests {
}
pub fn create_request_tc(
request: models::mgm_assembly::request::Request,
request: models::acs::mgm_assembly::request::Request,
) -> models::ccsds::CcsdsTcPacketOwned {
models::ccsds::CcsdsTcPacketOwned::new_with_request(
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
@@ -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();
@@ -429,13 +429,13 @@ mod tests {
let request = rx.try_recv().unwrap();
assert_eq!(
request,
models::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
models::acs::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
);
}
// Confirm the mode is set.
for tx in tb.mgm_report_tx.iter() {
tx.send(models::mgm::response::ModeResponse::Mode(
tx.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Normal,
))
.unwrap();
@@ -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();
@@ -467,13 +467,13 @@ mod tests {
let request = rx.try_recv().unwrap();
assert_eq!(
request,
models::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
models::acs::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
);
}
// Confirm the mode is set.
for tx in tb.mgm_report_tx.iter() {
tx.send(models::mgm::response::ModeResponse::Mode(
tx.send(models::acs::mgm::response::ModeResponse::Mode(
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();
@@ -505,28 +505,30 @@ mod tests {
let request = rx.try_recv().unwrap();
assert_eq!(
request,
models::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
models::acs::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
);
}
// One device is sufficient.
tb.mgm_report_tx[0]
.send(models::mgm::response::ModeResponse::Mode(
.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Normal,
))
.unwrap();
tb.mgm_report_tx[1]
.send(models::mgm::response::ModeResponse::Mode(DeviceMode::Off))
.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Off,
))
.unwrap();
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))
);
}
@@ -534,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();
@@ -545,19 +547,21 @@ mod tests {
let request = rx.try_recv().unwrap();
assert_eq!(
request,
models::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
models::acs::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
);
}
// Confirm the mode is set.
for tx in tb.mgm_report_tx.iter() {
tx.send(models::mgm::response::ModeResponse::Mode(DeviceMode::Off))
.unwrap();
tx.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Off,
))
.unwrap();
}
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!(
@@ -570,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();
@@ -581,13 +585,13 @@ mod tests {
let request = rx.try_recv().unwrap();
assert_eq!(
request,
models::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
models::acs::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
);
}
// Confirm the mode is set.
for tx in tb.mgm_report_tx.iter() {
tx.send(models::mgm::response::ModeResponse::Mode(
tx.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Normal,
))
.unwrap();
@@ -595,17 +599,19 @@ 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() {
tx.send(models::mgm::response::ModeResponse::Mode(DeviceMode::Off))
.unwrap();
tx.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Off,
))
.unwrap();
}
// This should start mode keeping.
tb.assembly.periodic_operation();
@@ -615,14 +621,16 @@ mod tests {
let request = rx.try_recv().unwrap();
assert_eq!(
request,
models::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
models::acs::mgm::request::ModeRequest::SetMode(DeviceMode::Normal)
);
}
// Let the mode keeping fail.
for tx in tb.mgm_report_tx.iter() {
tx.send(models::mgm::response::ModeResponse::Mode(DeviceMode::Off))
.unwrap();
tx.send(models::acs::mgm::response::ModeResponse::Mode(
DeviceMode::Off,
))
.unwrap();
}
tb.assembly.periodic_operation();
let report = tb.subsystem_report_rx.try_recv().unwrap();
+1
View File
@@ -0,0 +1 @@
+1 -2
View File
@@ -1,6 +1,5 @@
pub mod ctrl;
pub mod mgm;
pub mod mgm_assembly;
pub mod mgt;
pub mod subsystem;
+116 -1
View File
@@ -1 +1,116 @@
// TODO: Write subsystem
use std::sync::mpsc::SyncSender;
use models::ComponentId;
#[derive(Debug)]
pub struct TransitionInfo {
check_mode_reached: bool,
}
#[derive(Debug)]
pub struct ChildModes {
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::Mode, TransitionInfo)>,
mgt_mode: Option<(models::acs::mgt::Mode, TransitionInfo)>,
controller_mode: Option<(models::acs::ctrl::Mode, TransitionInfo)>,
}
const OFF_SEQUENCE: [TransitionCommands; 2] = [
TransitionCommands {
mgm_assembly_mode: None,
mgt_mode: None,
controller_mode: Some((
models::acs::ctrl::Mode::Passive,
TransitionInfo {
check_mode_reached: true,
},
)),
},
TransitionCommands {
mgm_assembly_mode: Some((
models::acs::mgm_assembly::Mode::Device(models::DeviceMode::Off),
TransitionInfo {
check_mode_reached: false,
},
)),
mgt_mode: Some((
models::acs::mgt::Mode::Off,
TransitionInfo {
check_mode_reached: false,
},
)),
controller_mode: None,
},
];
const SAFE_SEQUENCE: [TransitionCommands; 2] = [
TransitionCommands {
mgm_assembly_mode: Some((
models::acs::mgm_assembly::Mode::Device(models::DeviceMode::Normal),
TransitionInfo {
check_mode_reached: false,
},
)),
mgt_mode: Some((
models::acs::mgt::Mode::Normal,
TransitionInfo {
check_mode_reached: false,
},
)),
controller_mode: None,
},
TransitionCommands {
mgm_assembly_mode: None,
mgt_mode: None,
controller_mode: Some((
models::acs::ctrl::Mode::Safe,
TransitionInfo {
check_mode_reached: false,
},
)),
},
];
#[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(
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,
}
}
}
+2 -2
View File
@@ -188,7 +188,7 @@ fn main() {
request_rx: mgm_0_mode_request_rx,
report_tx: mgm_0_mode_report_tx,
},
Duration::from_millis(1000)
Duration::from_millis(1000),
);
let mut mgm_1_handler = mgm::MgmHandlerLis3Mdl::new(
mgm::MgmId::_1,
@@ -203,7 +203,7 @@ fn main() {
request_rx: mgm_1_mode_request_rx,
report_tx: mgm_1_mode_report_tx,
},
Duration::from_millis(1000)
Duration::from_millis(1000),
);
let mut mgm_assembly = mgm_assembly::Assembly::new(
mgm_assembly::ParentQueueHelper {