continue testing of mode tables
This commit is contained in:
parent
0870471886
commit
127d22d445
@ -35,6 +35,14 @@ pub enum ModeCommandingResult {
|
||||
#[error("mode {0} does not exist")]
|
||||
pub struct ModeDoesNotExistError(Mode);
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum StartSequenceError {
|
||||
#[error("mode {0} does not exist")]
|
||||
ModeDoesNotExist(#[from] ModeDoesNotExistError),
|
||||
#[error("invalid request ID")]
|
||||
InvalidRequestId(RequestId),
|
||||
}
|
||||
|
||||
/// This sequence execution helper includes some boilerplate logic to
|
||||
/// execute [SequenceModeTables].
|
||||
///
|
||||
@ -184,6 +192,14 @@ impl SequenceExecutionHelper {
|
||||
self.state
|
||||
}
|
||||
|
||||
pub fn request_id(&self) -> Option<RequestId> {
|
||||
self.request_id
|
||||
}
|
||||
|
||||
pub fn set_request_id(&mut self, request_id: RequestId) {
|
||||
self.request_id = Some(request_id);
|
||||
}
|
||||
|
||||
pub fn awaiting_success_check(&self) -> bool {
|
||||
self.state == SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
}
|
||||
@ -323,7 +339,7 @@ pub struct SubsystemCommandingHelper {
|
||||
pub children_mode_store: ModeStoreVec,
|
||||
/// This field is set when a mode sequence is executed. It is used to determine whether mode
|
||||
/// replies are relevant for reply awaition logic.
|
||||
pub active_request_id: Option<RequestId>,
|
||||
active_internal_request_id: Option<RequestId>,
|
||||
/// The primary data structure to keep the target state information for subsystem
|
||||
/// [modes][Mode]. it specifies the mode each child should have for a certain subsystem mode
|
||||
/// and is relevant for target keeping.
|
||||
@ -342,7 +358,7 @@ impl Default for SubsystemCommandingHelper {
|
||||
current_mode: UNKNOWN_MODE_VAL,
|
||||
state: Default::default(),
|
||||
children_mode_store: Default::default(),
|
||||
active_request_id: None,
|
||||
active_internal_request_id: None,
|
||||
target_tables: Default::default(),
|
||||
sequence_tables: Default::default(),
|
||||
seq_exec_helper: Default::default(),
|
||||
@ -362,7 +378,7 @@ impl SubsystemCommandingHelper {
|
||||
current_mode: UNKNOWN_MODE_VAL,
|
||||
state: ModeTreeHelperState::Idle,
|
||||
children_mode_store,
|
||||
active_request_id: None,
|
||||
active_internal_request_id: None,
|
||||
target_tables,
|
||||
sequence_tables,
|
||||
seq_exec_helper: Default::default(),
|
||||
@ -377,6 +393,20 @@ impl SubsystemCommandingHelper {
|
||||
self.current_mode
|
||||
}
|
||||
|
||||
pub fn request_id(&self) -> Option<RequestId> {
|
||||
self.active_internal_request_id.map(|v| v >> 8)
|
||||
}
|
||||
|
||||
/// This returns the internal request ID, which is the regular [Self::request_id] specified
|
||||
/// by the user shifter 8 to the right and then increment with the current sequence commanding
|
||||
/// step. The value can still be retrieved because it might be required for reply verification.
|
||||
///
|
||||
/// The state machine specifies this request ID for all mode commands related to the
|
||||
/// current step of sequence commanding.
|
||||
pub fn internal_request_id(&self) -> Option<RequestId> {
|
||||
self.active_internal_request_id
|
||||
}
|
||||
|
||||
/// Retrieve the fallback mode for the current mode of the subsystem by trying to retrieve
|
||||
/// it from the target table.
|
||||
///
|
||||
@ -410,14 +440,26 @@ impl SubsystemCommandingHelper {
|
||||
}
|
||||
|
||||
/// Starts a command sequence for a given [mode][Mode].
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `mode` - The mode to command
|
||||
/// - `request_id` - Request ID associated with the command sequence. The value of this value
|
||||
/// should not be larger than the maximum possible value for 24 bits: (2 ^ 24) - 1 = 16777215
|
||||
/// because 8 bits are reserved for internal sequence index tracking.
|
||||
pub fn start_command_sequence(
|
||||
&mut self,
|
||||
mode: Mode,
|
||||
request_id: RequestId,
|
||||
) -> Result<(), ModeDoesNotExistError> {
|
||||
) -> Result<(), StartSequenceError> {
|
||||
self.seq_exec_helper
|
||||
.load(mode, request_id, &self.sequence_tables)?;
|
||||
self.active_request_id = Some(request_id);
|
||||
if request_id > 2_u32.pow(24) - 1 {
|
||||
return Err(StartSequenceError::InvalidRequestId(request_id));
|
||||
}
|
||||
self.active_internal_request_id = Some(request_id << 8);
|
||||
self.seq_exec_helper
|
||||
.set_request_id(self.active_internal_request_id.unwrap());
|
||||
self.state = ModeTreeHelperState::ModeCommanding;
|
||||
Ok(())
|
||||
}
|
||||
@ -444,7 +486,17 @@ impl SubsystemCommandingHelper {
|
||||
req_sender: &impl ModeRequestSender,
|
||||
) -> Result<SubsystemHelperResult, ModeTreeHelperError> {
|
||||
if let Some(reply) = opt_reply {
|
||||
self.handle_mode_reply(&reply)?;
|
||||
if self.handle_mode_reply(&reply)? {
|
||||
if self.seq_exec_helper.state() == SequenceExecutionHelperState::Idle {
|
||||
self.transition_to_target_keeping();
|
||||
return Ok(SubsystemHelperResult::ModeCommanding(
|
||||
ModeCommandingResult::Done,
|
||||
));
|
||||
}
|
||||
return Ok(SubsystemHelperResult::ModeCommanding(
|
||||
ModeCommandingResult::StepDone,
|
||||
));
|
||||
}
|
||||
}
|
||||
match self.state {
|
||||
ModeTreeHelperState::Idle => Ok(SubsystemHelperResult::Idle),
|
||||
@ -461,19 +513,31 @@ impl SubsystemCommandingHelper {
|
||||
req_sender,
|
||||
&mut self.children_mode_store,
|
||||
)?;
|
||||
match result {
|
||||
ModeCommandingResult::Done => {
|
||||
// By default, the helper will automatically transition into the target keeping
|
||||
// mode after an executed sequence.
|
||||
if let ModeCommandingResult::Done = result {
|
||||
self.state = ModeTreeHelperState::TargetKeeping;
|
||||
self.active_request_id = None;
|
||||
self.current_mode = self.seq_exec_helper.target_mode().unwrap();
|
||||
self.transition_to_target_keeping();
|
||||
}
|
||||
ModeCommandingResult::StepDone => {
|
||||
// Normally, this step is done after all replies were received, but if no
|
||||
// reply checking is required for a command sequence, the step would never
|
||||
// be performed, so this function needs to be called here as well.
|
||||
self.update_internal_req_id();
|
||||
}
|
||||
ModeCommandingResult::AwaitingSuccessCheck => (),
|
||||
}
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perform_target_keeping(
|
||||
fn transition_to_target_keeping(&mut self) {
|
||||
self.state = ModeTreeHelperState::TargetKeeping;
|
||||
self.current_mode = self.seq_exec_helper.target_mode().unwrap();
|
||||
}
|
||||
|
||||
fn perform_target_keeping(
|
||||
&self,
|
||||
target_table: &TargetTablesMapValue,
|
||||
) -> Result<(), ModeTreeHelperError> {
|
||||
@ -505,22 +569,32 @@ impl SubsystemCommandingHelper {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_mode_reply(
|
||||
fn update_internal_req_id(&mut self) {
|
||||
let new_internal_req_id = self.request_id().unwrap() << 8
|
||||
| self.seq_exec_helper.current_sequence_index().unwrap() as u32;
|
||||
self.seq_exec_helper.set_request_id(new_internal_req_id);
|
||||
self.active_internal_request_id = Some(new_internal_req_id);
|
||||
}
|
||||
|
||||
// Handles a mode reply message and returns whether the reply completes a step of sequence
|
||||
// commanding.
|
||||
fn handle_mode_reply(
|
||||
&mut self,
|
||||
reply: &GenericMessage<ModeReply>,
|
||||
) -> Result<(), ModeTreeHelperError> {
|
||||
) -> Result<bool, ModeTreeHelperError> {
|
||||
if !self.children_mode_store.has_component(reply.sender_id()) {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
let mut generic_mode_reply_handler =
|
||||
|sender_id, mode_and_submode: Option<ModeAndSubmode>, success: bool| {
|
||||
let mut partial_step_done = false;
|
||||
// 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
|
||||
// the mode commanding. This is important for forced mode commands.
|
||||
let mut handle_awaition = false;
|
||||
if self.state == ModeTreeHelperState::ModeCommanding
|
||||
&& self.active_request_id.is_some()
|
||||
&& reply.request_id() == self.active_request_id.unwrap()
|
||||
&& self.active_internal_request_id.is_some()
|
||||
&& reply.request_id() == self.active_internal_request_id.unwrap()
|
||||
{
|
||||
handle_awaition = true;
|
||||
}
|
||||
@ -530,9 +604,12 @@ impl SubsystemCommandingHelper {
|
||||
handle_awaition,
|
||||
);
|
||||
if self.state == ModeTreeHelperState::ModeCommanding
|
||||
&& handle_awaition
|
||||
&& !still_awating_replies.unwrap_or(false)
|
||||
{
|
||||
self.seq_exec_helper.confirm_sequence_done();
|
||||
self.update_internal_req_id();
|
||||
partial_step_done = true;
|
||||
}
|
||||
if !success && self.state == ModeTreeHelperState::ModeCommanding {
|
||||
// The user has to decide how to proceed.
|
||||
@ -541,7 +618,7 @@ impl SubsystemCommandingHelper {
|
||||
seq_table_index: self.seq_exec_helper.current_sequence_index(),
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
Ok(partial_step_done)
|
||||
};
|
||||
match reply.message {
|
||||
ModeReply::ModeInfo(mode_and_submode) => {
|
||||
@ -828,11 +905,12 @@ mod tests {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_command_sequence(
|
||||
&mut self,
|
||||
mode: ExampleMode,
|
||||
request_id: RequestId,
|
||||
) -> Result<(), ModeDoesNotExistError> {
|
||||
) -> Result<(), StartSequenceError> {
|
||||
self.helper.start_command_sequence(mode as Mode, request_id)
|
||||
}
|
||||
|
||||
@ -1145,8 +1223,9 @@ mod tests {
|
||||
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!(tb.helper.active_internal_request_id.is_none());
|
||||
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||
assert!(tb.helper.request_id().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1195,6 +1274,7 @@ mod tests {
|
||||
let expected_req_id = 1;
|
||||
tb.start_command_sequence(ExampleMode::Mode0, expected_req_id)
|
||||
.unwrap();
|
||||
assert_eq!(tb.helper.request_id().unwrap(), 1);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.sender.requests.borrow().len(), 0);
|
||||
assert_eq!(
|
||||
@ -1203,7 +1283,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||
assert_eq!(tb.helper.mode(), ExampleMode::Mode0 as Mode);
|
||||
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||
tb.generic_checks_subsystem_md0(tb.helper.internal_request_id().unwrap());
|
||||
// FSM call should be a no-op.
|
||||
assert_eq!(
|
||||
tb.state_machine(None).unwrap(),
|
||||
@ -1221,10 +1301,18 @@ mod tests {
|
||||
.unwrap();
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.sender.requests.borrow().len(), 0);
|
||||
// Need to cache this before it is incremented, because it is incremented
|
||||
// immediately in the state machine (no reply checking)
|
||||
let expected_req_id = tb.helper.internal_request_id().unwrap();
|
||||
assert_eq!(
|
||||
tb.state_machine(None).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::StepDone)
|
||||
);
|
||||
// Assert that this was already incremented because no reply checking is necessary.
|
||||
assert_eq!(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
expected_req_id + 1
|
||||
);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||
tb.generic_checks_subsystem_md1_step0(expected_req_id);
|
||||
@ -1235,7 +1323,7 @@ mod tests {
|
||||
);
|
||||
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);
|
||||
tb.generic_checks_subsystem_md1_step1(tb.helper.internal_request_id().unwrap());
|
||||
|
||||
// FSM call should be a no-op.
|
||||
assert_eq!(
|
||||
@ -1263,13 +1351,19 @@ mod tests {
|
||||
);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||
tb.generic_checks_subsystem_md0(tb.helper.internal_request_id().unwrap());
|
||||
let mode_reply_ok_0 = GenericMessage::new(
|
||||
MessageMetadata::new(expected_req_id, ExampleTargetId::Target0 as ComponentId),
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
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),
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target1 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT1_MODE),
|
||||
);
|
||||
// One success reply still expected.
|
||||
@ -1290,4 +1384,205 @@ mod tests {
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::TargetKeeping);
|
||||
assert_eq!(tb.helper.mode(), ExampleMode::Mode0 as Mode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subsystem_helper_cmd_mode1_with_success_checks() {
|
||||
let mut tb = SubsystemHelperTestbench::new();
|
||||
let expected_req_id = 1;
|
||||
let seq_tables = tb.get_sequence_tables(ExampleMode::Mode1);
|
||||
seq_tables.entries[0].entries[0].check_success = true;
|
||||
seq_tables.entries[0].entries[1].check_success = true;
|
||||
seq_tables.entries[1].entries[0].check_success = true;
|
||||
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::AwaitingSuccessCheck)
|
||||
);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||
tb.generic_checks_subsystem_md1_step0(tb.helper.internal_request_id().unwrap());
|
||||
let mode_reply_ok_0 = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target0 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT0_MODE),
|
||||
);
|
||||
let mode_reply_ok_1 = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
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::StepDone)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
tb.state_machine(None).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::AwaitingSuccessCheck)
|
||||
);
|
||||
let mode_reply_ok = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target2 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD1_ST1_TGT2_MODE),
|
||||
);
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok)).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::Mode1 as Mode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subsystem_helper_cmd_mode1_with_partial_success_checks_0() {
|
||||
let mut tb = SubsystemHelperTestbench::new();
|
||||
let expected_req_id = 1;
|
||||
let seq_tables = tb.get_sequence_tables(ExampleMode::Mode1);
|
||||
seq_tables.entries[0].entries[0].check_success = true;
|
||||
seq_tables.entries[0].entries[1].check_success = false;
|
||||
seq_tables.entries[1].entries[0].check_success = false;
|
||||
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::AwaitingSuccessCheck)
|
||||
);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||
tb.generic_checks_subsystem_md1_step0(tb.helper.internal_request_id().unwrap());
|
||||
let mode_reply_ok_0 = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target0 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT0_MODE),
|
||||
);
|
||||
let mode_reply_ok_1 = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target1 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT1_MODE),
|
||||
);
|
||||
// One success reply still expected.
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok_1)).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::AwaitingSuccessCheck)
|
||||
);
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok_0)).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::StepDone)
|
||||
);
|
||||
|
||||
// Inserting the reply makes no difference: This call completes the sequence commanding.
|
||||
let mode_reply_ok = GenericMessage::new(
|
||||
MessageMetadata::new(expected_req_id, ExampleTargetId::Target2 as ComponentId),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD1_ST1_TGT2_MODE),
|
||||
);
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok)).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::Done)
|
||||
);
|
||||
// The internal request ID is still cached.
|
||||
tb.generic_checks_subsystem_md1_step1(tb.helper.internal_request_id().unwrap());
|
||||
|
||||
// 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_mode1_with_partial_success_checks_1() {
|
||||
let mut tb = SubsystemHelperTestbench::new();
|
||||
let expected_req_id = 1;
|
||||
let seq_tables = tb.get_sequence_tables(ExampleMode::Mode1);
|
||||
seq_tables.entries[0].entries[0].check_success = true;
|
||||
seq_tables.entries[0].entries[1].check_success = false;
|
||||
seq_tables.entries[1].entries[0].check_success = false;
|
||||
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::AwaitingSuccessCheck)
|
||||
);
|
||||
assert_eq!(tb.helper.state(), ModeTreeHelperState::ModeCommanding);
|
||||
assert_eq!(tb.helper.mode(), UNKNOWN_MODE_VAL);
|
||||
tb.generic_checks_subsystem_md1_step0(tb.helper.internal_request_id().unwrap());
|
||||
let mode_reply_ok_0 = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target0 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT0_MODE),
|
||||
);
|
||||
let mode_reply_ok_1 = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target1 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD0_TGT1_MODE),
|
||||
);
|
||||
// This completes the step, so the next FSM call will perform the next step
|
||||
// in sequence commanding.
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok_0)).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::StepDone)
|
||||
);
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok_1)).unwrap(),
|
||||
SubsystemHelperResult::ModeCommanding(ModeCommandingResult::Done)
|
||||
);
|
||||
|
||||
// Inserting the reply makes no difference: Sequence command is done and target keeping
|
||||
// is performed.
|
||||
let mode_reply_ok = GenericMessage::new(
|
||||
MessageMetadata::new(
|
||||
tb.helper.internal_request_id().unwrap(),
|
||||
ExampleTargetId::Target2 as ComponentId,
|
||||
),
|
||||
ModeReply::ModeInfo(SUBSYSTEM_MD1_ST1_TGT2_MODE),
|
||||
);
|
||||
assert_eq!(
|
||||
tb.state_machine(Some(mode_reply_ok)).unwrap(),
|
||||
SubsystemHelperResult::TargetKeeping
|
||||
);
|
||||
// The internal request ID is still cached.
|
||||
tb.generic_checks_subsystem_md1_step1(tb.helper.internal_request_id().unwrap());
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use satrs::mode_tree::{SequenceTablesMapValue, TargetTablesMapValue};
|
||||
use satrs::request::{MessageMetadata, RequestId};
|
||||
use satrs::res_code::ResultU16;
|
||||
use satrs::subsystem::{
|
||||
ModeCommandingResult, ModeDoesNotExistError, ModeTreeHelperError, ModeTreeHelperState,
|
||||
ModeCommandingResult, ModeTreeHelperError, ModeTreeHelperState, StartSequenceError,
|
||||
SubsystemCommandingHelper, SubsystemHelperResult,
|
||||
};
|
||||
use satrs::{
|
||||
@ -394,8 +394,8 @@ impl ModeProvider for AcsSubsystem {
|
||||
pub enum SubsystemModeError {
|
||||
#[error("messaging error: {0:?}")]
|
||||
Mode(#[from] ModeError),
|
||||
#[error("mode does not exist: {0}")]
|
||||
ModeDoesNotExist(#[from] ModeDoesNotExistError),
|
||||
#[error("start sequence error: {0}")]
|
||||
StartError(#[from] StartSequenceError),
|
||||
}
|
||||
|
||||
impl ModeRequestHandler for AcsSubsystem {
|
||||
@ -1452,11 +1452,12 @@ fn command_safe_mode() {
|
||||
);
|
||||
|
||||
// Check function calls for subsystem
|
||||
let generic_mock_check =
|
||||
|mock: &mut ModeRequestHandlerMock, expected_mode_for_transition: ModeAndSubmode| {
|
||||
let generic_mock_check = |mock: &mut ModeRequestHandlerMock,
|
||||
expected_mode_for_transition: ModeAndSubmode,
|
||||
expected_req_id: RequestId| {
|
||||
assert_eq!(mock.start_transition_calls.borrow().len(), 1);
|
||||
let start_transition_call = mock.start_transition_calls.borrow_mut().front().unwrap();
|
||||
assert_eq!(start_transition_call.0.request_id(), request_id);
|
||||
assert_eq!(start_transition_call.0.request_id(), expected_req_id);
|
||||
assert_eq!(start_transition_call.1, expected_mode_for_transition);
|
||||
assert_eq!(mock.handle_mode_reached_calls.borrow().len(), 1);
|
||||
|
||||
@ -1464,13 +1465,13 @@ fn command_safe_mode() {
|
||||
let handle_mode_reached_call = handle_mode_reached_ref.front().unwrap();
|
||||
assert_eq!(
|
||||
handle_mode_reached_call.as_ref().unwrap().request_id(),
|
||||
request_id
|
||||
expected_req_id
|
||||
);
|
||||
drop(handle_mode_reached_ref);
|
||||
|
||||
assert_eq!(mock.send_mode_reply_calls.borrow().len(), 1);
|
||||
let mode_reply_call = *mock.send_mode_reply_calls.borrow_mut().front().unwrap();
|
||||
assert_eq!(mode_reply_call.0.request_id(), request_id);
|
||||
assert_eq!(mode_reply_call.0.request_id(), expected_req_id);
|
||||
if let ModeReply::ModeReply(mode_and_submode) = mode_reply_call.1 {
|
||||
assert_eq!(
|
||||
mode_and_submode, expected_mode_for_transition,
|
||||
@ -1485,11 +1486,16 @@ fn command_safe_mode() {
|
||||
mock.clear();
|
||||
};
|
||||
|
||||
let expected_req_id_for_children = tb.subsystem.subsystem_helper.internal_request_id().unwrap();
|
||||
generic_mock_check(
|
||||
&mut tb.subsystem.mode_req_mock,
|
||||
ModeAndSubmode::new(AcsMode::SAFE as u32, 0),
|
||||
request_id,
|
||||
);
|
||||
assert_eq!(
|
||||
tb.subsystem.subsystem_helper.request_id().unwrap(),
|
||||
request_id
|
||||
);
|
||||
assert!(tb.subsystem.subsystem_helper.active_request_id.is_none());
|
||||
assert_eq!(
|
||||
tb.subsystem.subsystem_helper.state(),
|
||||
ModeTreeHelperState::TargetKeeping
|
||||
@ -1520,10 +1526,12 @@ fn command_safe_mode() {
|
||||
generic_mock_check(
|
||||
&mut tb.ctrl.mode_req_mock,
|
||||
ModeAndSubmode::new(AcsMode::SAFE as u32, 0),
|
||||
expected_req_id_for_children,
|
||||
);
|
||||
generic_mock_check(
|
||||
&mut tb.mgm_assy.mode_req_mock,
|
||||
ModeAndSubmode::new(DefaultMode::NORMAL as u32, 0),
|
||||
expected_req_id_for_children,
|
||||
);
|
||||
let mut expected_modes = HashMap::new();
|
||||
expected_modes.insert(
|
||||
@ -1542,6 +1550,7 @@ fn command_safe_mode() {
|
||||
generic_mock_check(
|
||||
&mut tb.mgt_manager.mode_req_mock,
|
||||
ModeAndSubmode::new(DefaultMode::NORMAL as u32, 0),
|
||||
expected_req_id_for_children,
|
||||
);
|
||||
let mut expected_modes = HashMap::new();
|
||||
expected_modes.insert(
|
||||
@ -1559,13 +1568,16 @@ fn command_safe_mode() {
|
||||
generic_mock_check(
|
||||
&mut tb.mgt_dev.mode_req_mock,
|
||||
ModeAndSubmode::new(DefaultMode::NORMAL as u32, 0),
|
||||
expected_req_id_for_children,
|
||||
);
|
||||
generic_mock_check(
|
||||
&mut tb.mgm_devs[0].mode_req_mock,
|
||||
ModeAndSubmode::new(DefaultMode::NORMAL as u32, 0),
|
||||
expected_req_id_for_children,
|
||||
);
|
||||
generic_mock_check(
|
||||
&mut tb.mgm_devs[1].mode_req_mock,
|
||||
ModeAndSubmode::new(DefaultMode::NORMAL as u32, 0),
|
||||
expected_req_id_for_children,
|
||||
);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user