more tests
This commit is contained in:
@@ -63,12 +63,12 @@ pub mod request {
|
||||
pub mod response {
|
||||
use crate::Message;
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ModeCommandFailure {
|
||||
Timeout,
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Response {
|
||||
Ok,
|
||||
ModeFailure(ModeCommandFailure),
|
||||
|
||||
@@ -56,7 +56,7 @@ pub enum TransitionState {
|
||||
Done,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ModeRequest {
|
||||
SetMode(DeviceMode),
|
||||
ReadMode,
|
||||
@@ -255,7 +255,7 @@ impl MgmHandlerLis3Mdl {
|
||||
self.handle_hk_request(Some(tc_id), &hk_request)
|
||||
}
|
||||
mgm::request::Request::Mode(device_mode) => {
|
||||
self.mode_helpers.tc_id = Some(tc_id);
|
||||
self.mode_helpers.tc_commander = Some(tc_id);
|
||||
self.start_transition(device_mode, false);
|
||||
}
|
||||
}
|
||||
@@ -410,10 +410,10 @@ impl MgmHandlerLis3Mdl {
|
||||
|
||||
// Should be called to complete a mode transition which failed.
|
||||
fn handle_mode_transition_failure(&mut self) {
|
||||
self.mode_helpers.finish(false);
|
||||
if let Some(requestor) = self.mode_helpers.tc_id {
|
||||
let tc_commander = self.mode_helpers.finish(false);
|
||||
if tc_commander.is_some() {
|
||||
self.send_telemetry(
|
||||
Some(requestor),
|
||||
tc_commander,
|
||||
mgm::response::Response::ModeFailure(ModeFailure::Timeout),
|
||||
);
|
||||
}
|
||||
@@ -426,7 +426,7 @@ impl MgmHandlerLis3Mdl {
|
||||
// Should be called to complete a mode transition successfully.
|
||||
fn handle_mode_reached(&mut self) {
|
||||
self.announce_mode();
|
||||
if let Some(requestor) = self.mode_helpers.tc_id {
|
||||
if let Some(requestor) = self.mode_helpers.tc_commander {
|
||||
self.send_mode_tm(requestor);
|
||||
}
|
||||
// Inform our parent about mode changes.
|
||||
|
||||
@@ -13,13 +13,13 @@ use satrs_example::{ModeHelper, TmtcQueues};
|
||||
|
||||
use crate::ccsds::pack_ccsds_tm_packet_for_now;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ModeRequest {
|
||||
SetMode(AssemblyMode),
|
||||
ReadMode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ModeReport {
|
||||
/// Mode of the assembly.
|
||||
Mode(AssemblyMode),
|
||||
@@ -67,7 +67,7 @@ pub struct Assembly {
|
||||
}
|
||||
|
||||
impl Assembly {
|
||||
const ID: ComponentId = ComponentId::AcsMgmAssembly;
|
||||
pub const ID: ComponentId = ComponentId::AcsMgmAssembly;
|
||||
|
||||
pub fn new(
|
||||
parent_queues: ParentQueueHelper,
|
||||
@@ -246,15 +246,15 @@ impl Assembly {
|
||||
}
|
||||
|
||||
pub fn handle_mode_reached(&mut self) {
|
||||
let tc_commander = self.mode_helper.finish(true);
|
||||
self.announce_mode();
|
||||
if self.mode_helper.tc_id.is_some() {
|
||||
self.send_telemetry(self.mode_helper.tc_id, response::Response::Ok);
|
||||
if tc_commander.is_some() {
|
||||
self.send_telemetry(tc_commander, response::Response::Ok);
|
||||
}
|
||||
self.parent_queues
|
||||
.report_tx
|
||||
.send(ModeReport::Mode(self.mode_helper.current))
|
||||
.unwrap();
|
||||
self.mode_helper.finish(true);
|
||||
}
|
||||
|
||||
pub fn handle_mode_transition_failure(&mut self) {
|
||||
@@ -263,9 +263,9 @@ impl Assembly {
|
||||
} else {
|
||||
ModeReport::SetModeTimeout(self.mgm_modes.map(|info| info.mode))
|
||||
};
|
||||
if self.mode_helper.tc_id.is_some() {
|
||||
if self.mode_helper.tc_commander.is_some() {
|
||||
self.send_telemetry(
|
||||
self.mode_helper.tc_id,
|
||||
self.mode_helper.tc_commander,
|
||||
response::Response::ModeFailure(ModeCommandFailure::Timeout),
|
||||
);
|
||||
}
|
||||
@@ -286,7 +286,7 @@ impl Assembly {
|
||||
tc_id: Option<CcsdsPacketIdAndPsc>,
|
||||
) {
|
||||
self.mode_keeping_transition = mode_keeping;
|
||||
self.mode_helper.tc_id = tc_id;
|
||||
self.mode_helper.tc_commander = tc_id;
|
||||
self.mgm_modes
|
||||
.iter_mut()
|
||||
.for_each(|m| m.reply_received = false);
|
||||
@@ -301,13 +301,29 @@ impl Assembly {
|
||||
self.mode_helper.current
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mode(&self) -> AssemblyMode {
|
||||
self.mode_helper.current
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mode_transition_active(&self) -> bool {
|
||||
self.mode_helper.transition_active()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::mpsc::TryRecvError;
|
||||
|
||||
use models::ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned};
|
||||
use arbitrary_int::u11;
|
||||
use models::{
|
||||
Apid, Message, MessageType, TcHeader,
|
||||
ccsds::{CcsdsTcPacketOwned, CcsdsTmPacketOwned},
|
||||
mgm_assembly,
|
||||
};
|
||||
use satrs::spacepackets::SpacePacketHeader;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -377,10 +393,132 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_request_tc(
|
||||
request: models::mgm_assembly::request::Request,
|
||||
) -> models::ccsds::CcsdsTcPacketOwned {
|
||||
models::ccsds::CcsdsTcPacketOwned::new_with_request(
|
||||
SpacePacketHeader::new_from_apid(u11::new(Apid::Acs as u16)),
|
||||
TcHeader::new(Assembly::ID, request.message_type()),
|
||||
request,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_test() {
|
||||
let mut tb = Testbench::new();
|
||||
tb.assert_all_queues_empty();
|
||||
tb.assembly.periodic_operation();
|
||||
tb.assert_all_queues_empty();
|
||||
assert_eq!(tb.assembly.mode(), AssemblyMode::NoModeKeeping);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tc_commanded_transition() {
|
||||
let mut tb = Testbench::new();
|
||||
tb.tc_tx
|
||||
.send(create_request_tc(mgm_assembly::request::Request::Mode(
|
||||
AssemblyMode::Device(DeviceMode::Normal),
|
||||
)))
|
||||
.unwrap();
|
||||
tb.assembly.periodic_operation();
|
||||
assert!(tb.assembly.mode_transition_active());
|
||||
|
||||
for rx in tb.mgm_request_rx.iter() {
|
||||
let request = rx.try_recv().unwrap();
|
||||
assert_eq!(
|
||||
request,
|
||||
crate::mgm::ModeRequest::SetMode(DeviceMode::Normal)
|
||||
);
|
||||
}
|
||||
|
||||
// Confirm the mode is set.
|
||||
for tx in tb.mgm_report_tx.iter() {
|
||||
tx.send(crate::mgm::ModeReport::Mode(DeviceMode::Normal))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
tb.assembly.periodic_operation();
|
||||
assert!(!tb.assembly.mode_transition_active());
|
||||
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
|
||||
|
||||
let response = tb.tm_rx.try_recv().unwrap();
|
||||
assert_eq!(response.tm_header.sender_id, Assembly::ID);
|
||||
assert_eq!(response.tm_header.message_type, MessageType::Verification);
|
||||
let response: response::Response = postcard::from_bytes(&response.payload).unwrap();
|
||||
assert_eq!(response, response::Response::Ok);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parent_commanded_transition() {
|
||||
let mut tb = Testbench::new();
|
||||
tb.subsystem_req_tx
|
||||
.send(ModeRequest::SetMode(AssemblyMode::Device(
|
||||
DeviceMode::Normal,
|
||||
)))
|
||||
.unwrap();
|
||||
tb.assembly.periodic_operation();
|
||||
assert!(tb.assembly.mode_transition_active());
|
||||
|
||||
for rx in tb.mgm_request_rx.iter() {
|
||||
let request = rx.try_recv().unwrap();
|
||||
assert_eq!(
|
||||
request,
|
||||
crate::mgm::ModeRequest::SetMode(DeviceMode::Normal)
|
||||
);
|
||||
}
|
||||
|
||||
// Confirm the mode is set.
|
||||
for tx in tb.mgm_report_tx.iter() {
|
||||
tx.send(crate::mgm::ModeReport::Mode(DeviceMode::Normal))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
tb.assembly.periodic_operation();
|
||||
assert!(!tb.assembly.mode_transition_active());
|
||||
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
|
||||
|
||||
let report = tb.subsystem_report_rx.try_recv().unwrap();
|
||||
assert_eq!(
|
||||
report,
|
||||
ModeReport::Mode(AssemblyMode::Device(DeviceMode::Normal))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_one_mgm_is_sufficient() {
|
||||
let mut tb = Testbench::new();
|
||||
tb.subsystem_req_tx
|
||||
.send(ModeRequest::SetMode(AssemblyMode::Device(
|
||||
DeviceMode::Normal,
|
||||
)))
|
||||
.unwrap();
|
||||
tb.assembly.periodic_operation();
|
||||
assert!(tb.assembly.mode_transition_active());
|
||||
|
||||
for rx in tb.mgm_request_rx.iter() {
|
||||
let request = rx.try_recv().unwrap();
|
||||
assert_eq!(
|
||||
request,
|
||||
crate::mgm::ModeRequest::SetMode(DeviceMode::Normal)
|
||||
);
|
||||
}
|
||||
|
||||
// One device is sufficient.
|
||||
tb.mgm_report_tx[0]
|
||||
.send(crate::mgm::ModeReport::Mode(DeviceMode::Normal))
|
||||
.unwrap();
|
||||
tb.mgm_report_tx[1]
|
||||
.send(crate::mgm::ModeReport::Mode(DeviceMode::Off))
|
||||
.unwrap();
|
||||
|
||||
tb.assembly.periodic_operation();
|
||||
assert!(!tb.assembly.mode_transition_active());
|
||||
assert_eq!(tb.assembly.mode(), AssemblyMode::Device(DeviceMode::Normal));
|
||||
|
||||
let report = tb.subsystem_report_rx.try_recv().unwrap();
|
||||
assert_eq!(
|
||||
report,
|
||||
ModeReport::Mode(AssemblyMode::Device(DeviceMode::Normal))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ pub struct TmtcQueues {
|
||||
pub struct ModeHelper<Mode, TransitionState> {
|
||||
pub current: Mode,
|
||||
pub target: Option<Mode>,
|
||||
pub tc_id: Option<CcsdsPacketIdAndPsc>,
|
||||
pub tc_commander: Option<CcsdsPacketIdAndPsc>,
|
||||
pub transition_start: Option<Instant>,
|
||||
pub timeout: Duration,
|
||||
pub transition_state: TransitionState,
|
||||
@@ -115,7 +115,7 @@ impl<Mode: Copy + Clone, TransitionState: Default> ModeHelper<Mode, TransitionSt
|
||||
Self {
|
||||
current: init_mode,
|
||||
target: Default::default(),
|
||||
tc_id: Default::default(),
|
||||
tc_commander: Default::default(),
|
||||
transition_start: None,
|
||||
timeout,
|
||||
transition_state: Default::default(),
|
||||
@@ -143,17 +143,17 @@ impl<Mode: Copy + Clone, TransitionState: Default> ModeHelper<Mode, TransitionSt
|
||||
false
|
||||
}
|
||||
|
||||
pub fn finish(&mut self, success: bool) {
|
||||
pub fn finish(&mut self, success: bool) -> Option<CcsdsPacketIdAndPsc> {
|
||||
if self.target.is_none() {
|
||||
return;
|
||||
return None;
|
||||
}
|
||||
if success {
|
||||
self.current = self.target.take().unwrap();
|
||||
} else {
|
||||
self.target = None;
|
||||
}
|
||||
self.tc_id = None;
|
||||
self.transition_state = Default::default();
|
||||
self.transition_start = None;
|
||||
self.tc_commander.take()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user