continue tests
This commit is contained in:
parent
365f8f9e7a
commit
0870471886
@ -28,8 +28,10 @@ pub struct ModeAndSubmode {
|
|||||||
submode: Submode,
|
submode: Submode,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const INVALID_MODE: ModeAndSubmode = ModeAndSubmode::new(u32::MAX, 0);
|
pub const INVALID_MODE_VAL: Mode = Mode::MAX;
|
||||||
pub const UNKNOWN_MODE: ModeAndSubmode = ModeAndSubmode::new(u32::MAX - 1, 0);
|
pub const UNKNOWN_MODE_VAL: Mode = Mode::MAX - 1;
|
||||||
|
pub const INVALID_MODE: ModeAndSubmode = ModeAndSubmode::new(INVALID_MODE_VAL, 0);
|
||||||
|
pub const UNKNOWN_MODE: ModeAndSubmode = ModeAndSubmode::new(UNKNOWN_MODE_VAL, 0);
|
||||||
|
|
||||||
impl ModeAndSubmode {
|
impl ModeAndSubmode {
|
||||||
pub const RAW_LEN: usize = size_of::<Mode>() + size_of::<Submode>();
|
pub const RAW_LEN: usize = size_of::<Mode>() + size_of::<Submode>();
|
||||||
|
@ -331,6 +331,24 @@ pub mod alloc_mod {
|
|||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TargetModeTables(pub HashMap<Mode, TargetTablesMapValue>);
|
pub struct TargetModeTables(pub HashMap<Mode, TargetTablesMapValue>);
|
||||||
|
|
||||||
|
impl TargetModeTables {
|
||||||
|
pub fn name(&self, mode: Mode) -> Option<&'static str> {
|
||||||
|
self.0.get(&mode).map(|value| value.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SequenceModeTables {
|
||||||
|
pub fn name(&self, mode: Mode) -> Option<&'static str> {
|
||||||
|
self.0.get(&mode).map(|value| value.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_of_sequence(&self, mode: Mode, seq_idx: usize) -> Option<&'static str> {
|
||||||
|
self.0
|
||||||
|
.get(&mode)
|
||||||
|
.map(|value| value.entries.get(seq_idx).map(|v| v.name))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is the core data structure used to store mode sequence tables.
|
/// This is the core data structure used to store mode sequence tables.
|
||||||
///
|
///
|
||||||
/// A mode sequence table specifies which commands have to be sent in which order
|
/// A mode sequence table specifies which commands have to be sent in which order
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender, UNKNOWN_MODE},
|
mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender, UNKNOWN_MODE_VAL},
|
||||||
mode_tree::{
|
mode_tree::{
|
||||||
ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableMapTable,
|
ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableMapTable,
|
||||||
SequenceTablesMapValue, TargetModeTables, TargetNotInModeStoreError, TargetTablesMapValue,
|
SequenceTablesMapValue, TargetModeTables, TargetNotInModeStoreError, TargetTablesMapValue,
|
||||||
@ -21,12 +21,6 @@ pub enum SequenceExecutionHelperState {
|
|||||||
AwaitingSuccessCheck,
|
AwaitingSuccessCheck,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum TargetKeepingResult {
|
|
||||||
Ok,
|
|
||||||
Violated { fallback_mode: Option<Mode> },
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum ModeCommandingResult {
|
pub enum ModeCommandingResult {
|
||||||
/// The commanding of all children is finished
|
/// The commanding of all children is finished
|
||||||
@ -38,7 +32,7 @@ pub enum ModeCommandingResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
#[error("Mode {0} does not exist")]
|
#[error("mode {0} does not exist")]
|
||||||
pub struct ModeDoesNotExistError(Mode);
|
pub struct ModeDoesNotExistError(Mode);
|
||||||
|
|
||||||
/// This sequence execution helper includes some boilerplate logic to
|
/// This sequence execution helper includes some boilerplate logic to
|
||||||
@ -269,7 +263,7 @@ impl SequenceExecutionHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum ModeTreeHelperState {
|
pub enum ModeTreeHelperState {
|
||||||
#[default]
|
#[default]
|
||||||
Idle,
|
Idle,
|
||||||
@ -279,22 +273,16 @@ pub enum ModeTreeHelperState {
|
|||||||
ModeCommanding,
|
ModeCommanding,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
pub enum SubsystemHelperResult {
|
pub enum SubsystemHelperResult {
|
||||||
#[default]
|
#[default]
|
||||||
Idle,
|
Idle,
|
||||||
/// Result of a target keeping operation
|
/// Busy with target keeping.
|
||||||
TargetKeeping(TargetKeepingResult),
|
TargetKeeping,
|
||||||
/// Result of a mode commanding operation
|
/// Result of a mode commanding operation
|
||||||
ModeCommanding(ModeCommandingResult),
|
ModeCommanding(ModeCommandingResult),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TargetKeepingResult> for SubsystemHelperResult {
|
|
||||||
fn from(value: TargetKeepingResult) -> Self {
|
|
||||||
Self::TargetKeeping(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ModeCommandingResult> for SubsystemHelperResult {
|
impl From<ModeCommandingResult> for SubsystemHelperResult {
|
||||||
fn from(value: ModeCommandingResult) -> Self {
|
fn from(value: ModeCommandingResult) -> Self {
|
||||||
Self::ModeCommanding(value)
|
Self::ModeCommanding(value)
|
||||||
@ -307,6 +295,18 @@ pub enum ModeTreeHelperError {
|
|||||||
Message(#[from] GenericTargetedMessagingError),
|
Message(#[from] GenericTargetedMessagingError),
|
||||||
#[error("current mode {0} is not contained in target table")]
|
#[error("current mode {0} is not contained in target table")]
|
||||||
CurrentModeNotInTargetTable(Mode),
|
CurrentModeNotInTargetTable(Mode),
|
||||||
|
/// Mode command has failed, for example while executing a mode table.
|
||||||
|
#[error("mode command failed")]
|
||||||
|
ModeCommmandFailure {
|
||||||
|
/// Table index of the sequence table entry which failed.
|
||||||
|
seq_table_index: Option<usize>,
|
||||||
|
},
|
||||||
|
/// Target mode keeping violation.
|
||||||
|
#[error("target keeping violation")]
|
||||||
|
TargetKeepingViolation {
|
||||||
|
/// Table index of the sequence table entry which failed.
|
||||||
|
fallback_mode: Option<Mode>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is a helper object which can be used by a subsystem component to execute mode sequences
|
/// This is a helper object which can be used by a subsystem component to execute mode sequences
|
||||||
@ -315,10 +315,10 @@ pub enum ModeTreeHelperError {
|
|||||||
/// This helper object tries to compose as much data and state information as possible which is
|
/// This helper object tries to compose as much data and state information as possible which is
|
||||||
/// required for this process.
|
/// required for this process.
|
||||||
pub struct SubsystemCommandingHelper {
|
pub struct SubsystemCommandingHelper {
|
||||||
/// Current mode of the owner subsystem.
|
|
||||||
pub current_mode: ModeAndSubmode,
|
|
||||||
/// State of the helper.
|
/// State of the helper.
|
||||||
pub state: ModeTreeHelperState,
|
state: ModeTreeHelperState,
|
||||||
|
/// Current mode of the owner subsystem.
|
||||||
|
current_mode: Mode,
|
||||||
/// This data structure is used to track all mode children.
|
/// This data structure is used to track all mode children.
|
||||||
pub children_mode_store: ModeStoreVec,
|
pub children_mode_store: ModeStoreVec,
|
||||||
/// This field is set when a mode sequence is executed. It is used to determine whether mode
|
/// This field is set when a mode sequence is executed. It is used to determine whether mode
|
||||||
@ -339,7 +339,7 @@ pub struct SubsystemCommandingHelper {
|
|||||||
impl Default for SubsystemCommandingHelper {
|
impl Default for SubsystemCommandingHelper {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_mode: UNKNOWN_MODE,
|
current_mode: UNKNOWN_MODE_VAL,
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
children_mode_store: Default::default(),
|
children_mode_store: Default::default(),
|
||||||
active_request_id: None,
|
active_request_id: None,
|
||||||
@ -359,7 +359,7 @@ impl SubsystemCommandingHelper {
|
|||||||
sequence_tables: SequenceModeTables,
|
sequence_tables: SequenceModeTables,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
current_mode: UNKNOWN_MODE,
|
current_mode: UNKNOWN_MODE_VAL,
|
||||||
state: ModeTreeHelperState::Idle,
|
state: ModeTreeHelperState::Idle,
|
||||||
children_mode_store,
|
children_mode_store,
|
||||||
active_request_id: None,
|
active_request_id: None,
|
||||||
@ -369,6 +369,30 @@ impl SubsystemCommandingHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn state(&self) -> ModeTreeHelperState {
|
||||||
|
self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mode(&self) -> Mode {
|
||||||
|
self.current_mode
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the fallback mode for the current mode of the subsystem by trying to retrieve
|
||||||
|
/// it from the target table.
|
||||||
|
///
|
||||||
|
/// If the current mode does not have a fallback mode, returns [None].
|
||||||
|
/// If the current mode is not inside the target table, returns a [ModeDoesNotExistError].
|
||||||
|
/// The fallback mode can and should be commanded when a target keeping violation was detected
|
||||||
|
/// or after self-commanding to the current mode has failed, which can happen after a failed
|
||||||
|
/// mode table execution.
|
||||||
|
pub fn fallback_mode(&self) -> Result<Option<Mode>, ModeDoesNotExistError> {
|
||||||
|
self.target_tables
|
||||||
|
.0
|
||||||
|
.get(&self.current_mode)
|
||||||
|
.ok_or(ModeDoesNotExistError(self.current_mode))
|
||||||
|
.map(|v| v.fallback_mode)
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a mode child to the internal [Self::children_mode_store].
|
/// Add a mode child to the internal [Self::children_mode_store].
|
||||||
pub fn add_mode_child(&mut self, child: ComponentId, mode: ModeAndSubmode) {
|
pub fn add_mode_child(&mut self, child: ComponentId, mode: ModeAndSubmode) {
|
||||||
self.children_mode_store.add_component(child, mode);
|
self.children_mode_store.add_component(child, mode);
|
||||||
@ -393,6 +417,7 @@ impl SubsystemCommandingHelper {
|
|||||||
) -> Result<(), ModeDoesNotExistError> {
|
) -> Result<(), ModeDoesNotExistError> {
|
||||||
self.seq_exec_helper
|
self.seq_exec_helper
|
||||||
.load(mode, request_id, &self.sequence_tables)?;
|
.load(mode, request_id, &self.sequence_tables)?;
|
||||||
|
self.active_request_id = Some(request_id);
|
||||||
self.state = ModeTreeHelperState::ModeCommanding;
|
self.state = ModeTreeHelperState::ModeCommanding;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -419,16 +444,16 @@ impl SubsystemCommandingHelper {
|
|||||||
req_sender: &impl ModeRequestSender,
|
req_sender: &impl ModeRequestSender,
|
||||||
) -> Result<SubsystemHelperResult, ModeTreeHelperError> {
|
) -> Result<SubsystemHelperResult, ModeTreeHelperError> {
|
||||||
if let Some(reply) = opt_reply {
|
if let Some(reply) = opt_reply {
|
||||||
self.handle_mode_reply(&reply);
|
self.handle_mode_reply(&reply)?;
|
||||||
}
|
}
|
||||||
match self.state {
|
match self.state {
|
||||||
ModeTreeHelperState::Idle => Ok(SubsystemHelperResult::Idle),
|
ModeTreeHelperState::Idle => Ok(SubsystemHelperResult::Idle),
|
||||||
ModeTreeHelperState::TargetKeeping => {
|
ModeTreeHelperState::TargetKeeping => {
|
||||||
// We check whether the current mode is modelled by a target table first.
|
// We check whether the current mode is modelled by a target table first.
|
||||||
if let Some(target_table) = self.target_tables.0.get(&self.current_mode.mode()) {
|
if let Some(target_table) = self.target_tables.0.get(&self.current_mode) {
|
||||||
return Ok(self.perform_target_keeping(target_table).into());
|
self.perform_target_keeping(target_table)?;
|
||||||
}
|
}
|
||||||
Ok(TargetKeepingResult::Ok.into())
|
Ok(SubsystemHelperResult::TargetKeeping)
|
||||||
}
|
}
|
||||||
ModeTreeHelperState::ModeCommanding => {
|
ModeTreeHelperState::ModeCommanding => {
|
||||||
let result = self.seq_exec_helper.run(
|
let result = self.seq_exec_helper.run(
|
||||||
@ -441,8 +466,7 @@ impl SubsystemCommandingHelper {
|
|||||||
if let ModeCommandingResult::Done = result {
|
if let ModeCommandingResult::Done = result {
|
||||||
self.state = ModeTreeHelperState::TargetKeeping;
|
self.state = ModeTreeHelperState::TargetKeeping;
|
||||||
self.active_request_id = None;
|
self.active_request_id = None;
|
||||||
self.current_mode =
|
self.current_mode = self.seq_exec_helper.target_mode().unwrap();
|
||||||
ModeAndSubmode::new(self.seq_exec_helper.target_mode().unwrap(), 0);
|
|
||||||
}
|
}
|
||||||
Ok(result.into())
|
Ok(result.into())
|
||||||
}
|
}
|
||||||
@ -452,7 +476,7 @@ impl SubsystemCommandingHelper {
|
|||||||
pub fn perform_target_keeping(
|
pub fn perform_target_keeping(
|
||||||
&self,
|
&self,
|
||||||
target_table: &TargetTablesMapValue,
|
target_table: &TargetTablesMapValue,
|
||||||
) -> TargetKeepingResult {
|
) -> Result<(), ModeTreeHelperError> {
|
||||||
for entry in &target_table.entries {
|
for entry in &target_table.entries {
|
||||||
if !entry.monitor_state {
|
if !entry.monitor_state {
|
||||||
continue;
|
continue;
|
||||||
@ -473,20 +497,23 @@ impl SubsystemCommandingHelper {
|
|||||||
});
|
});
|
||||||
if target_mode_violated {
|
if target_mode_violated {
|
||||||
// Target keeping violated. Report violation and fallback mode to user.
|
// Target keeping violated. Report violation and fallback mode to user.
|
||||||
return TargetKeepingResult::Violated {
|
return Err(ModeTreeHelperError::TargetKeepingViolation {
|
||||||
fallback_mode: target_table.fallback_mode,
|
fallback_mode: target_table.fallback_mode,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TargetKeepingResult::Ok
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_mode_reply(&mut self, reply: &GenericMessage<ModeReply>) {
|
pub fn handle_mode_reply(
|
||||||
|
&mut self,
|
||||||
|
reply: &GenericMessage<ModeReply>,
|
||||||
|
) -> Result<(), ModeTreeHelperError> {
|
||||||
if !self.children_mode_store.has_component(reply.sender_id()) {
|
if !self.children_mode_store.has_component(reply.sender_id()) {
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mut generic_mode_reply_handler =
|
let mut generic_mode_reply_handler =
|
||||||
|sender_id, mode_and_submode: Option<ModeAndSubmode>| {
|
|sender_id, mode_and_submode: Option<ModeAndSubmode>, success: bool| {
|
||||||
// Tying the reply awaition to the request ID ensures that something like replies
|
// Tying the reply awaition to the request ID ensures that something like replies
|
||||||
// belonging to older requests do not interfere with the completion handling of
|
// belonging to older requests do not interfere with the completion handling of
|
||||||
// the mode commanding. This is important for forced mode commands.
|
// the mode commanding. This is important for forced mode commands.
|
||||||
@ -507,21 +534,29 @@ impl SubsystemCommandingHelper {
|
|||||||
{
|
{
|
||||||
self.seq_exec_helper.confirm_sequence_done();
|
self.seq_exec_helper.confirm_sequence_done();
|
||||||
}
|
}
|
||||||
|
if !success && self.state == ModeTreeHelperState::ModeCommanding {
|
||||||
|
// The user has to decide how to proceed.
|
||||||
|
self.state = ModeTreeHelperState::Idle;
|
||||||
|
return Err(ModeTreeHelperError::ModeCommmandFailure {
|
||||||
|
seq_table_index: self.seq_exec_helper.current_sequence_index(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
};
|
};
|
||||||
match reply.message {
|
match reply.message {
|
||||||
ModeReply::ModeInfo(mode_and_submode) => {
|
ModeReply::ModeInfo(mode_and_submode) => {
|
||||||
generic_mode_reply_handler(reply.sender_id(), Some(mode_and_submode));
|
generic_mode_reply_handler(reply.sender_id(), Some(mode_and_submode), true)
|
||||||
}
|
}
|
||||||
ModeReply::ModeReply(mode_and_submode) => {
|
ModeReply::ModeReply(mode_and_submode) => {
|
||||||
generic_mode_reply_handler(reply.sender_id(), Some(mode_and_submode));
|
generic_mode_reply_handler(reply.sender_id(), Some(mode_and_submode), true)
|
||||||
}
|
}
|
||||||
ModeReply::CantReachMode(_) => {
|
ModeReply::CantReachMode(_) => {
|
||||||
generic_mode_reply_handler(reply.sender_id(), None);
|
generic_mode_reply_handler(reply.sender_id(), None, false)
|
||||||
}
|
}
|
||||||
ModeReply::WrongMode { reached, .. } => {
|
ModeReply::WrongMode { reached, .. } => {
|
||||||
generic_mode_reply_handler(reply.sender_id(), Some(reached));
|
generic_mode_reply_handler(reply.sender_id(), Some(reached), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_child_mode(
|
pub fn update_child_mode(
|
||||||
@ -540,23 +575,22 @@ impl SubsystemCommandingHelper {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mode::{Mode, ModeAndSubmode, ModeRequest, ModeRequestSender, UNKNOWN_MODE},
|
mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender, UNKNOWN_MODE},
|
||||||
mode_tree::{
|
mode_tree::{
|
||||||
ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableEntry,
|
ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableEntry,
|
||||||
SequenceTableMapTable, SequenceTablesMapValue,
|
SequenceTableMapTable, SequenceTablesMapValue, TargetModeTables,
|
||||||
},
|
},
|
||||||
queue::GenericTargetedMessagingError,
|
queue::GenericTargetedMessagingError,
|
||||||
request::RequestId,
|
request::{GenericMessage, MessageMetadata, RequestId},
|
||||||
subsystem::{ModeCommandingResult, SequenceExecutionHelperState},
|
subsystem::{ModeCommandingResult, ModeTreeHelperState, SequenceExecutionHelperState},
|
||||||
ComponentId,
|
ComponentId,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SequenceExecutionHelper;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ExampleTargetId {
|
pub enum ExampleTargetId {
|
||||||
Target0 = 1,
|
Target0 = 1,
|
||||||
@ -605,36 +639,36 @@ mod tests {
|
|||||||
pub struct SequenceExecutorTestbench {
|
pub struct SequenceExecutorTestbench {
|
||||||
pub sender: ModeReqSenderMock,
|
pub sender: ModeReqSenderMock,
|
||||||
pub mode_store: ModeStoreVec,
|
pub mode_store: ModeStoreVec,
|
||||||
pub seq_table: SequenceModeTables,
|
pub seq_tables: SequenceModeTables,
|
||||||
pub execution_helper: SequenceExecutionHelper,
|
pub execution_helper: SequenceExecutionHelper,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SequenceExecutorTestbench {
|
impl SequenceExecutorTestbench {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mode_store = create_default_mode_store();
|
let mode_store = create_default_mode_store();
|
||||||
let seq_table = create_simple_sample_seq_table(false, false);
|
let (seq_tables, _) = create_simple_sample_seq_tables();
|
||||||
Self {
|
Self {
|
||||||
sender: ModeReqSenderMock::default(),
|
sender: ModeReqSenderMock::default(),
|
||||||
mode_store,
|
mode_store,
|
||||||
seq_table,
|
seq_tables,
|
||||||
execution_helper: SequenceExecutionHelper::new(),
|
execution_helper: SequenceExecutionHelper::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mode_table(&mut self, mode: ExampleMode) -> &mut SequenceTablesMapValue {
|
pub fn get_mode_table(&mut self, mode: ExampleMode) -> &mut SequenceTablesMapValue {
|
||||||
self.seq_table.0.get_mut(&(mode as Mode)).unwrap()
|
self.seq_tables.0.get_mut(&(mode as Mode)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<ModeCommandingResult, GenericTargetedMessagingError> {
|
pub fn run(&mut self) -> Result<ModeCommandingResult, GenericTargetedMessagingError> {
|
||||||
self.execution_helper
|
self.execution_helper
|
||||||
.run(&self.seq_table, &self.sender, &mut self.mode_store)
|
.run(&self.seq_tables, &self.sender, &mut self.mode_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_run_is_no_op(&mut self) {
|
fn check_run_is_no_op(&mut self) {
|
||||||
// Assure that no unexpected behaviour occurs.
|
// Assure that no unexpected behaviour occurs.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
self.execution_helper
|
self.execution_helper
|
||||||
.run(&self.seq_table, &self.sender, &mut self.mode_store)
|
.run(&self.seq_tables, &self.sender, &mut self.mode_store)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
ModeCommandingResult::Done
|
ModeCommandingResult::Done
|
||||||
);
|
);
|
||||||
@ -702,7 +736,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
req_0.request,
|
req_0.request,
|
||||||
ModeRequest::SetMode {
|
ModeRequest::SetMode {
|
||||||
mode_and_submode: SUBSYSTEM_MD0_TGT_0_MODE,
|
mode_and_submode: SUBSYSTEM_MD0_TGT0_MODE,
|
||||||
forced: false
|
forced: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -711,7 +745,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
req_1.request,
|
req_1.request,
|
||||||
ModeRequest::SetMode {
|
ModeRequest::SetMode {
|
||||||
mode_and_submode: SUBSYSTEM_MD0_TGT_1_MODE,
|
mode_and_submode: SUBSYSTEM_MD0_TGT1_MODE,
|
||||||
forced: false
|
forced: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -726,28 +760,25 @@ mod tests {
|
|||||||
mode_store
|
mode_store
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_simple_sample_seq_table(
|
fn create_simple_sample_seq_tables() -> (SequenceModeTables, TargetModeTables) {
|
||||||
success_check_tgt0: bool,
|
let mut seq_tables = SequenceModeTables::default();
|
||||||
success_check_tgt1: bool,
|
|
||||||
) -> SequenceModeTables {
|
|
||||||
let mut table = SequenceModeTables::default();
|
|
||||||
// Mode 0 - One step command
|
// Mode 0 - One step command
|
||||||
let mut table_val = SequenceTablesMapValue::new("MODE_0");
|
let mut table_val = SequenceTablesMapValue::new("MODE_0");
|
||||||
let mut table_seq_0 = SequenceTableMapTable::new("MODE_0_SEQ_0");
|
let mut table_seq_0 = SequenceTableMapTable::new("MODE_0_SEQ_0");
|
||||||
table_seq_0.add_entry(SequenceTableEntry::new(
|
table_seq_0.add_entry(SequenceTableEntry::new(
|
||||||
"TARGET_0",
|
"TARGET_0",
|
||||||
ExampleTargetId::Target0 as u64,
|
ExampleTargetId::Target0 as u64,
|
||||||
SUBSYSTEM_MD0_TGT_0_MODE,
|
SUBSYSTEM_MD0_TGT0_MODE,
|
||||||
success_check_tgt0,
|
false,
|
||||||
));
|
));
|
||||||
table_seq_0.add_entry(SequenceTableEntry::new(
|
table_seq_0.add_entry(SequenceTableEntry::new(
|
||||||
"TARGET_1",
|
"TARGET_1",
|
||||||
ExampleTargetId::Target1 as u64,
|
ExampleTargetId::Target1 as u64,
|
||||||
SUBSYSTEM_MD0_TGT_1_MODE,
|
SUBSYSTEM_MD0_TGT1_MODE,
|
||||||
success_check_tgt1,
|
false,
|
||||||
));
|
));
|
||||||
table_val.add_sequence_table(table_seq_0);
|
table_val.add_sequence_table(table_seq_0);
|
||||||
table.0.insert(ExampleMode::Mode0 as u32, table_val);
|
seq_tables.0.insert(ExampleMode::Mode0 as u32, table_val);
|
||||||
|
|
||||||
// Mode 1 - Multi Step command
|
// Mode 1 - Multi Step command
|
||||||
let mut table_val = SequenceTablesMapValue::new("MODE_1");
|
let mut table_val = SequenceTablesMapValue::new("MODE_1");
|
||||||
@ -773,13 +804,130 @@ mod tests {
|
|||||||
false,
|
false,
|
||||||
));
|
));
|
||||||
table_val.add_sequence_table(table_seq_1);
|
table_val.add_sequence_table(table_seq_1);
|
||||||
table.0.insert(ExampleMode::Mode1 as u32, table_val);
|
seq_tables.0.insert(ExampleMode::Mode1 as u32, table_val);
|
||||||
table
|
|
||||||
|
let mode_tables = TargetModeTables::default();
|
||||||
|
// TODO: Write mode tables.
|
||||||
|
(seq_tables, mode_tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SUBSYSTEM_MD0_TGT_0_MODE: ModeAndSubmode =
|
pub struct SubsystemHelperTestbench {
|
||||||
|
pub sender: ModeReqSenderMock,
|
||||||
|
pub helper: SubsystemCommandingHelper,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubsystemHelperTestbench {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let (sequence_tables, target_tables) = create_simple_sample_seq_tables();
|
||||||
|
Self {
|
||||||
|
sender: ModeReqSenderMock::default(),
|
||||||
|
helper: SubsystemCommandingHelper::new(
|
||||||
|
create_default_mode_store(),
|
||||||
|
target_tables,
|
||||||
|
sequence_tables,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn start_command_sequence(
|
||||||
|
&mut self,
|
||||||
|
mode: ExampleMode,
|
||||||
|
request_id: RequestId,
|
||||||
|
) -> Result<(), ModeDoesNotExistError> {
|
||||||
|
self.helper.start_command_sequence(mode as Mode, request_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_announce_mode_cmd_to_children(
|
||||||
|
&mut self,
|
||||||
|
request_id: RequestId,
|
||||||
|
recursive: bool,
|
||||||
|
) -> Result<(), GenericTargetedMessagingError> {
|
||||||
|
self.helper
|
||||||
|
.send_announce_mode_cmd_to_children(request_id, &self.sender, recursive)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_sequence_tables(&mut self, mode: ExampleMode) -> &mut SequenceTablesMapValue {
|
||||||
|
self.helper
|
||||||
|
.sequence_tables
|
||||||
|
.0
|
||||||
|
.get_mut(&(mode as Mode))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn state_machine(
|
||||||
|
&mut self,
|
||||||
|
opt_reply: Option<GenericMessage<ModeReply>>,
|
||||||
|
) -> Result<SubsystemHelperResult, ModeTreeHelperError> {
|
||||||
|
self.helper.state_machine(opt_reply, &self.sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generic_checks_subsystem_md0(&mut self, expected_req_id: RequestId) {
|
||||||
|
assert_eq!(self.sender.requests.borrow().len(), 2);
|
||||||
|
let req0 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
assert_eq!(req0.request_id, expected_req_id);
|
||||||
|
assert_eq!(req0.target_id, ExampleTargetId::Target0 as ComponentId);
|
||||||
|
assert_eq!(
|
||||||
|
req0.request,
|
||||||
|
ModeRequest::SetMode {
|
||||||
|
mode_and_submode: SUBSYSTEM_MD0_TGT0_MODE,
|
||||||
|
forced: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let req1 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
assert_eq!(req1.request_id, expected_req_id);
|
||||||
|
assert_eq!(req1.target_id, ExampleTargetId::Target1 as ComponentId);
|
||||||
|
assert_eq!(
|
||||||
|
req1.request,
|
||||||
|
ModeRequest::SetMode {
|
||||||
|
mode_and_submode: SUBSYSTEM_MD0_TGT1_MODE,
|
||||||
|
forced: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generic_checks_subsystem_md1_step0(&mut self, expected_req_id: RequestId) {
|
||||||
|
assert_eq!(self.sender.requests.borrow().len(), 2);
|
||||||
|
let req0 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
assert_eq!(req0.request_id, expected_req_id);
|
||||||
|
assert_eq!(req0.target_id, ExampleTargetId::Target0 as ComponentId);
|
||||||
|
assert_eq!(
|
||||||
|
req0.request,
|
||||||
|
ModeRequest::SetMode {
|
||||||
|
mode_and_submode: SUBSYSTEM_MD1_ST0_TGT0_MODE,
|
||||||
|
forced: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let req1 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
assert_eq!(req1.request_id, expected_req_id);
|
||||||
|
assert_eq!(req1.target_id, ExampleTargetId::Target1 as ComponentId);
|
||||||
|
assert_eq!(
|
||||||
|
req1.request,
|
||||||
|
ModeRequest::SetMode {
|
||||||
|
mode_and_submode: SUBSYSTEM_MD1_ST0_TGT1_MODE,
|
||||||
|
forced: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generic_checks_subsystem_md1_step1(&mut self, expected_req_id: RequestId) {
|
||||||
|
assert_eq!(self.sender.requests.borrow().len(), 1);
|
||||||
|
let req0 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
assert_eq!(req0.request_id, expected_req_id);
|
||||||
|
assert_eq!(req0.target_id, ExampleTargetId::Target2 as ComponentId);
|
||||||
|
assert_eq!(
|
||||||
|
req0.request,
|
||||||
|
ModeRequest::SetMode {
|
||||||
|
mode_and_submode: SUBSYSTEM_MD1_ST1_TGT2_MODE,
|
||||||
|
forced: false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SUBSYSTEM_MD0_TGT0_MODE: ModeAndSubmode =
|
||||||
ModeAndSubmode::new(ExampleMode::Mode0 as u32, 0);
|
ModeAndSubmode::new(ExampleMode::Mode0 as u32, 0);
|
||||||
const SUBSYSTEM_MD0_TGT_1_MODE: ModeAndSubmode =
|
const SUBSYSTEM_MD0_TGT1_MODE: ModeAndSubmode =
|
||||||
ModeAndSubmode::new(ExampleMode::Mode1 as u32, 0);
|
ModeAndSubmode::new(ExampleMode::Mode1 as u32, 0);
|
||||||
|
|
||||||
const SUBSYSTEM_MD1_ST0_TGT0_MODE: ModeAndSubmode =
|
const SUBSYSTEM_MD1_ST0_TGT0_MODE: ModeAndSubmode =
|
||||||
@ -803,7 +951,7 @@ mod tests {
|
|||||||
let mut tb = SequenceExecutorTestbench::new();
|
let mut tb = SequenceExecutorTestbench::new();
|
||||||
let expected_req_id = 1;
|
let expected_req_id = 1;
|
||||||
tb.execution_helper
|
tb.execution_helper
|
||||||
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_table)
|
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_tables)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tb.execution_helper.state(),
|
tb.execution_helper.state(),
|
||||||
@ -815,9 +963,7 @@ mod tests {
|
|||||||
ExampleMode::Mode0 as Mode
|
ExampleMode::Mode0 as Mode
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tb.execution_helper
|
tb.run().expect("sequence exeecution helper run failure"),
|
||||||
.run(&tb.seq_table, &tb.sender, &mut tb.mode_store)
|
|
||||||
.expect("sequence exeecution helper run failure"),
|
|
||||||
ModeCommandingResult::Done
|
ModeCommandingResult::Done
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -837,7 +983,7 @@ mod tests {
|
|||||||
mode0_table.entries[0].entries[1].check_success = true;
|
mode0_table.entries[0].entries[1].check_success = true;
|
||||||
let expected_req_id = 1;
|
let expected_req_id = 1;
|
||||||
tb.execution_helper
|
tb.execution_helper
|
||||||
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_table)
|
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_tables)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -877,7 +1023,7 @@ mod tests {
|
|||||||
mode0_table.entries[0].entries[0].check_success = true;
|
mode0_table.entries[0].entries[0].check_success = true;
|
||||||
let expected_req_id = 1;
|
let expected_req_id = 1;
|
||||||
tb.execution_helper
|
tb.execution_helper
|
||||||
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_table)
|
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_tables)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -910,7 +1056,7 @@ mod tests {
|
|||||||
let mut tb = SequenceExecutorTestbench::new();
|
let mut tb = SequenceExecutorTestbench::new();
|
||||||
let expected_req_id = 1;
|
let expected_req_id = 1;
|
||||||
tb.execution_helper
|
tb.execution_helper
|
||||||
.load(ExampleMode::Mode1 as u32, expected_req_id, &tb.seq_table)
|
.load(ExampleMode::Mode1 as u32, expected_req_id, &tb.seq_tables)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tb.execution_helper.state(),
|
tb.execution_helper.state(),
|
||||||
@ -950,7 +1096,7 @@ mod tests {
|
|||||||
let mut tb = SequenceExecutorTestbench::new();
|
let mut tb = SequenceExecutorTestbench::new();
|
||||||
let expected_req_id = 1;
|
let expected_req_id = 1;
|
||||||
tb.execution_helper
|
tb.execution_helper
|
||||||
.load(ExampleMode::Mode1 as u32, expected_req_id, &tb.seq_table)
|
.load(ExampleMode::Mode1 as u32, expected_req_id, &tb.seq_tables)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mode1_table = tb.get_mode_table(ExampleMode::Mode1);
|
let mode1_table = tb.get_mode_table(ExampleMode::Mode1);
|
||||||
mode1_table.entries[0].entries[0].check_success = true;
|
mode1_table.entries[0].entries[0].check_success = true;
|
||||||
@ -995,4 +1141,153 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test subsystem commanding helper
|
// TODO: Test subsystem commanding helper
|
||||||
|
#[test]
|
||||||
|
fn test_subsystem_helper_basic_state() {
|
||||||
|
let tb = SubsystemHelperTestbench::new();
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::Idle);
|
||||||
|
assert!(tb.helper.active_request_id.is_none());
|
||||||
|
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subsystem_helper_announce_recursive() {
|
||||||
|
let mut tb = SubsystemHelperTestbench::new();
|
||||||
|
let expected_req_id = 1;
|
||||||
|
tb.send_announce_mode_cmd_to_children(expected_req_id, true)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(tb.sender.requests.borrow().len(), 3);
|
||||||
|
let check_req = |req: ModeReqWrapper, target_id: ComponentId| {
|
||||||
|
assert_eq!(req.target_id, target_id);
|
||||||
|
assert_eq!(req.request_id, expected_req_id);
|
||||||
|
assert_eq!(req.request, ModeRequest::AnnounceModeRecursive);
|
||||||
|
};
|
||||||
|
let req0 = tb.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
check_req(req0, ExampleTargetId::Target0 as u64);
|
||||||
|
let req1 = tb.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
check_req(req1, ExampleTargetId::Target1 as u64);
|
||||||
|
let req2 = tb.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
check_req(req2, ExampleTargetId::Target2 as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subsystem_helper_announce() {
|
||||||
|
let mut tb = SubsystemHelperTestbench::new();
|
||||||
|
let expected_req_id = 1;
|
||||||
|
tb.send_announce_mode_cmd_to_children(expected_req_id, false)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(tb.sender.requests.borrow().len(), 3);
|
||||||
|
let check_req = |req: ModeReqWrapper, target_id: ComponentId| {
|
||||||
|
assert_eq!(req.target_id, target_id);
|
||||||
|
assert_eq!(req.request_id, expected_req_id);
|
||||||
|
assert_eq!(req.request, ModeRequest::AnnounceMode);
|
||||||
|
};
|
||||||
|
let req0 = tb.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
check_req(req0, ExampleTargetId::Target0 as u64);
|
||||||
|
let req1 = tb.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
check_req(req1, ExampleTargetId::Target1 as u64);
|
||||||
|
let req2 = tb.sender.requests.borrow_mut().pop_front().unwrap();
|
||||||
|
check_req(req2, ExampleTargetId::Target2 as u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subsystem_helper_cmd_mode0_no_success_checks() {
|
||||||
|
let mut tb = SubsystemHelperTestbench::new();
|
||||||
|
let expected_req_id = 1;
|
||||||
|
tb.start_command_sequence(ExampleMode::Mode0, expected_req_id)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||||
|
assert_eq!(tb.sender.requests.borrow().len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::Done)
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||||
|
assert_eq!(tb.helper.mode(), ExampleMode::Mode0 as Mode);
|
||||||
|
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||||
|
// FSM call should be a no-op.
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::TargetKeeping
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||||
|
assert_eq!(tb.helper.mode(), ExampleMode::Mode0 as Mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subsystem_helper_cmd_mode1_no_success_checks() {
|
||||||
|
let mut tb = SubsystemHelperTestbench::new();
|
||||||
|
let expected_req_id = 1;
|
||||||
|
tb.start_command_sequence(ExampleMode::Mode1, expected_req_id)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||||
|
assert_eq!(tb.sender.requests.borrow().len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::StepDone)
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||||
|
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||||
|
tb.generic_checks_subsystem_md1_step0(expected_req_id);
|
||||||
|
// Second commanding step.
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::Done)
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||||
|
assert_eq!(tb.helper.mode(), ExampleMode::Mode1 as Mode);
|
||||||
|
tb.generic_checks_subsystem_md1_step1(expected_req_id);
|
||||||
|
|
||||||
|
// FSM call should be a no-op.
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::TargetKeeping
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||||
|
assert_eq!(tb.helper.mode(), ExampleMode::Mode1 as Mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_subsystem_helper_cmd_mode0_with_success_checks() {
|
||||||
|
let mut tb = SubsystemHelperTestbench::new();
|
||||||
|
let expected_req_id = 1;
|
||||||
|
let seq_tables = tb.get_sequence_tables(ExampleMode::Mode0);
|
||||||
|
seq_tables.entries[0].entries[0].check_success = true;
|
||||||
|
seq_tables.entries[0].entries[1].check_success = true;
|
||||||
|
tb.start_command_sequence(ExampleMode::Mode0, expected_req_id)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||||
|
assert_eq!(tb.sender.requests.borrow().len(), 0);
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::AwaitingSuccessCheck)
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||||
|
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||||
|
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||||
|
let mode_reply_ok_0 = GenericMessage::new(
|
||||||
|
MessageMetadata::new(expected_req_id, ExampleTargetId::Target0 as ComponentId),
|
||||||
|
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT0_MODE),
|
||||||
|
);
|
||||||
|
let mode_reply_ok_1 = GenericMessage::new(
|
||||||
|
MessageMetadata::new(expected_req_id, ExampleTargetId::Target1 as ComponentId),
|
||||||
|
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT1_MODE),
|
||||||
|
);
|
||||||
|
// One success reply still expected.
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(Some(mode_reply_ok_0)).unwrap(),
|
||||||
|
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::AwaitingSuccessCheck)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(Some(mode_reply_ok_1)).unwrap(),
|
||||||
|
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::Done)
|
||||||
|
);
|
||||||
|
|
||||||
|
// FSM call should be a no-op.
|
||||||
|
assert_eq!(
|
||||||
|
tb.state_machine(None).unwrap(),
|
||||||
|
SubsystemHelperResult::TargetKeeping
|
||||||
|
);
|
||||||
|
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||||
|
assert_eq!(tb.helper.mode(), ExampleMode::Mode0 as Mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use satrs::request::{MessageMetadata, RequestId};
|
|||||||
use satrs::res_code::ResultU16;
|
use satrs::res_code::ResultU16;
|
||||||
use satrs::subsystem::{
|
use satrs::subsystem::{
|
||||||
ModeCommandingResult, ModeDoesNotExistError, ModeTreeHelperError, ModeTreeHelperState,
|
ModeCommandingResult, ModeDoesNotExistError, ModeTreeHelperError, ModeTreeHelperState,
|
||||||
SubsystemCommandingHelper, SubsystemHelperResult, TargetKeepingResult,
|
SubsystemCommandingHelper, SubsystemHelperResult,
|
||||||
};
|
};
|
||||||
use satrs::{
|
use satrs::{
|
||||||
mode::{ModeAndSubmode, ModeReply, ModeRequest},
|
mode::{ModeAndSubmode, ModeReply, ModeRequest},
|
||||||
@ -301,32 +301,27 @@ impl AcsSubsystem {
|
|||||||
result: Result<SubsystemHelperResult, ModeTreeHelperError>,
|
result: Result<SubsystemHelperResult, ModeTreeHelperError>,
|
||||||
) {
|
) {
|
||||||
match result {
|
match result {
|
||||||
Ok(result) => match result {
|
Ok(result) => {
|
||||||
SubsystemHelperResult::Idle => (),
|
if let SubsystemHelperResult::ModeCommanding(ModeCommandingResult::Done) = result {
|
||||||
SubsystemHelperResult::TargetKeeping(target_keeping_result) => {
|
self.handle_mode_reached(self.mode_requestor_info)
|
||||||
match target_keeping_result {
|
.expect("mode reply handling failed");
|
||||||
TargetKeepingResult::Ok => (),
|
}
|
||||||
TargetKeepingResult::Violated { fallback_mode } => {
|
}
|
||||||
|
Err(error) => match error {
|
||||||
|
ModeTreeHelperError::Message(_generic_targeted_messaging_error) => {
|
||||||
|
panic!("messaging error")
|
||||||
|
}
|
||||||
|
ModeTreeHelperError::CurrentModeNotInTargetTable(_) => panic!("mode not found"),
|
||||||
|
ModeTreeHelperError::ModeCommmandFailure { seq_table_index: _ } => {
|
||||||
|
// TODO: Cache the command failure.
|
||||||
|
}
|
||||||
|
ModeTreeHelperError::TargetKeepingViolation { fallback_mode } => {
|
||||||
if let Some(fallback_mode) = fallback_mode {
|
if let Some(fallback_mode) = fallback_mode {
|
||||||
self.subsystem_helper
|
self.subsystem_helper
|
||||||
.start_command_sequence(fallback_mode, 0)
|
.start_command_sequence(fallback_mode, 0)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
SubsystemHelperResult::ModeCommanding(mode_commanding_result) => {
|
|
||||||
if let ModeCommandingResult::Done = mode_commanding_result {
|
|
||||||
self.handle_mode_reached(self.mode_requestor_info)
|
|
||||||
.expect("mode reply handling failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(error) => match error {
|
|
||||||
ModeTreeHelperError::Message(_generic_targeted_messaging_error) => {
|
|
||||||
panic!("messaging error")
|
|
||||||
}
|
|
||||||
ModeTreeHelperError::CurrentModeNotInTargetTable(_) => panic!("mode not found"),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,7 +386,7 @@ impl ModeChild for AcsSubsystem {
|
|||||||
|
|
||||||
impl ModeProvider for AcsSubsystem {
|
impl ModeProvider for AcsSubsystem {
|
||||||
fn mode_and_submode(&self) -> ModeAndSubmode {
|
fn mode_and_submode(&self) -> ModeAndSubmode {
|
||||||
self.subsystem_helper.current_mode
|
ModeAndSubmode::new(self.subsystem_helper.mode(), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,7 +407,7 @@ impl ModeRequestHandler for AcsSubsystem {
|
|||||||
mode_and_submode: ModeAndSubmode,
|
mode_and_submode: ModeAndSubmode,
|
||||||
forced: bool,
|
forced: bool,
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
if !forced && self.subsystem_helper.state == ModeTreeHelperState::ModeCommanding {
|
if !forced && self.subsystem_helper.state() == ModeTreeHelperState::ModeCommanding {
|
||||||
return Err(ModeError::Busy.into());
|
return Err(ModeError::Busy.into());
|
||||||
}
|
}
|
||||||
self.mode_requestor_info = Some(requestor);
|
self.mode_requestor_info = Some(requestor);
|
||||||
@ -428,7 +423,8 @@ impl ModeRequestHandler for AcsSubsystem {
|
|||||||
fn announce_mode(&self, requestor_info: Option<MessageMetadata>, recursive: bool) {
|
fn announce_mode(&self, requestor_info: Option<MessageMetadata>, recursive: bool) {
|
||||||
println!(
|
println!(
|
||||||
"TestAssembly: Announcing mode (recursively: {}): {:?}",
|
"TestAssembly: Announcing mode (recursively: {}): {:?}",
|
||||||
recursive, self.subsystem_helper.current_mode
|
recursive,
|
||||||
|
self.subsystem_helper.mode()
|
||||||
);
|
);
|
||||||
let request_id = requestor_info.map_or(0, |info| info.request_id());
|
let request_id = requestor_info.map_or(0, |info| info.request_id());
|
||||||
self.subsystem_helper
|
self.subsystem_helper
|
||||||
@ -447,7 +443,7 @@ impl ModeRequestHandler for AcsSubsystem {
|
|||||||
if let Some(requestor) = requestor_info {
|
if let Some(requestor) = requestor_info {
|
||||||
self.send_mode_reply(
|
self.send_mode_reply(
|
||||||
requestor,
|
requestor,
|
||||||
ModeReply::ModeReply(self.subsystem_helper.current_mode),
|
ModeReply::ModeReply(ModeAndSubmode::new(self.subsystem_helper.mode(), 0)),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1495,13 +1491,10 @@ fn command_safe_mode() {
|
|||||||
);
|
);
|
||||||
assert!(tb.subsystem.subsystem_helper.active_request_id.is_none());
|
assert!(tb.subsystem.subsystem_helper.active_request_id.is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tb.subsystem.subsystem_helper.state,
|
tb.subsystem.subsystem_helper.state(),
|
||||||
ModeTreeHelperState::TargetKeeping
|
ModeTreeHelperState::TargetKeeping
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(tb.subsystem.subsystem_helper.mode(), AcsMode::SAFE as Mode,);
|
||||||
tb.subsystem.subsystem_helper.current_mode,
|
|
||||||
ModeAndSubmode::new(AcsMode::SAFE as u32, 0),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
tb.subsystem.mode_reply_mock.num_of_received_mode_replies(),
|
tb.subsystem.mode_reply_mock.num_of_received_mode_replies(),
|
||||||
3
|
3
|
||||||
|
Loading…
x
Reference in New Issue
Block a user