diff --git a/satrs/src/mode_tree.rs b/satrs/src/mode_tree.rs index 50e17ff..6156437 100644 --- a/satrs/src/mode_tree.rs +++ b/satrs/src/mode_tree.rs @@ -180,10 +180,30 @@ impl SequenceTableEntry { } } +#[derive(Debug, thiserror::Error)] +#[error("target {0} not in mode store")] +pub struct TargetNotInModeStoreError(pub ComponentId); + pub trait ModeStoreProvider { fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode); + + fn has_component(&self, target_id: ComponentId) -> bool; + fn get_mode(&self, target_id: ComponentId) -> Option; - fn set_mode(&mut self, target_id: ComponentId, mode: ModeAndSubmode); + + fn set_mode_for_contained_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode); + + fn set_mode( + &mut self, + target_id: ComponentId, + mode: ModeAndSubmode, + ) -> Result<(), TargetNotInModeStoreError> { + if !self.has_component(target_id) { + return Err(TargetNotInModeStoreError(target_id)); + } + self.set_mode_for_contained_component(target_id, mode); + Ok(()) + } } #[cfg(feature = "alloc")] @@ -268,6 +288,10 @@ pub mod alloc_mod { self.0.push((target_id, mode)); } + fn has_component(&self, target_id: ComponentId) -> bool { + self.0.iter().any(|(id, _)| *id == target_id) + } + fn get_mode(&self, target_id: ComponentId) -> Option { self.0.iter().find_map(|(id, mode)| { if *id == target_id { @@ -277,7 +301,11 @@ pub mod alloc_mod { }) } - fn set_mode(&mut self, target_id: ComponentId, mode_to_set: ModeAndSubmode) { + fn set_mode_for_contained_component( + &mut self, + target_id: ComponentId, + mode_to_set: ModeAndSubmode, + ) { self.0.iter_mut().for_each(|(id, mode)| { if *id == target_id { *mode = mode_to_set; @@ -290,10 +318,19 @@ pub mod alloc_mod { fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) { self.0.insert(target_id, mode); } + + fn has_component(&self, target_id: ComponentId) -> bool { + self.0.contains_key(&target_id) + } + fn get_mode(&self, target_id: ComponentId) -> Option { self.0.get(&target_id).copied() } - fn set_mode(&mut self, target_id: ComponentId, mode_to_set: ModeAndSubmode) { + fn set_mode_for_contained_component( + &mut self, + target_id: ComponentId, + mode_to_set: ModeAndSubmode, + ) { self.0.insert(target_id, mode_to_set); } } diff --git a/satrs/src/subsystem.rs b/satrs/src/subsystem.rs index fac02b6..85ded3b 100644 --- a/satrs/src/subsystem.rs +++ b/satrs/src/subsystem.rs @@ -6,31 +6,13 @@ use crate::{ ComponentId, }; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum SequenceExecutionHelperStates { Idle, AwaitingCheckSuccess, Done, } -#[derive(Debug)] -pub struct SequenceExecutionHelper { - target_mode: Mode, - state: SequenceExecutionHelperStates, - request_id: RequestId, - current_sequence_index: Option, -} - -impl Default for SequenceExecutionHelper { - fn default() -> Self { - Self { - target_mode: 0, - state: SequenceExecutionHelperStates::Idle, - request_id: 0, - current_sequence_index: todo!(), - } - } -} pub trait CheckSuccessProvider { fn mode_request_requires_success_check( &mut self, @@ -46,15 +28,38 @@ pub enum SequenceHandlerResult { AwaitingSuccessCheck, } +#[derive(Debug, thiserror::Error)] +#[error("Mode {0} does not exist")] +pub struct ModeDoesNotExistError(Mode); + +#[derive(Debug)] +pub struct SequenceExecutionHelper { + target_mode: Mode, + state: SequenceExecutionHelperStates, + request_id: RequestId, + current_sequence_index: Option, +} + +impl Default for SequenceExecutionHelper { + fn default() -> Self { + Self { + target_mode: 0, + state: SequenceExecutionHelperStates::Idle, + request_id: 0, + current_sequence_index: None, + } + } +} + impl SequenceExecutionHelper { pub fn load( &mut self, mode: Mode, request_id: RequestId, sequence_tables: &SequenceModeTables, - ) -> Result<(), ()> { + ) -> Result<(), ModeDoesNotExistError> { if !sequence_tables.0.contains_key(&mode) { - return Err(()); + return Err(ModeDoesNotExistError(mode)); } self.target_mode = mode; self.request_id = request_id; @@ -68,6 +73,21 @@ impl SequenceExecutionHelper { } } + pub fn state(&self) -> SequenceExecutionHelperStates { + self.state + } + + pub fn awaiting_check_success(&self) -> bool { + matches!( + self.state, + SequenceExecutionHelperStates::AwaitingCheckSuccess + ) + } + + pub fn current_sequence_index(&self) -> Option { + self.current_sequence_index + } + pub fn run( &mut self, table: &SequenceModeTables, diff --git a/satrs/tests/mode_tree.rs b/satrs/tests/mode_tree.rs index 5134c47..6c94dca 100644 --- a/satrs/tests/mode_tree.rs +++ b/satrs/tests/mode_tree.rs @@ -1,19 +1,19 @@ use core::cell::Cell; use satrs::mode::{ Mode, ModeError, ModeProvider, ModeReplyReceiver, ModeReplySender, ModeRequestHandler, - ModeRequestHandlerMpscBounded, ModeRequestReceiver, ModeRequestorAndHandlerMpscBounded, - ModeRequestorOneChildBoundedMpsc, + ModeRequestHandlerMpscBounded, ModeRequestReceiver, ModeRequestSender, + ModeRequestorAndHandlerMpscBounded, ModeRequestorOneChildBoundedMpsc, }; use satrs::mode_tree::{ connect_mode_nodes, ModeChild, ModeNode, ModeParent, ModeStoreProvider, SequenceTableEntry, - SequenceTableMapTable, TargetTableEntry, + SequenceTableMapTable, TargetNotInModeStoreError, TargetTableEntry, }; use satrs::mode_tree::{ ModeStoreVec, SequenceModeTables, SequenceTablesMapValue, TargetModeTables, TargetTablesMapValue, }; use satrs::request::MessageMetadata; -use satrs::subsystem::SequenceExecutionHelper; +use satrs::subsystem::{SequenceExecutionHelper, SequenceHandlerResult}; use satrs::{ mode::{ModeAndSubmode, ModeReply, ModeRequest}, queue::GenericTargetedMessagingError, @@ -58,6 +58,10 @@ pub enum TestComponentId { pub type RequestSenderType = mpsc::SyncSender>; pub type ReplySenderType = mpsc::SyncSender>; +// TODO: +// +// 1. Fallback mode? +// 2. State to determine whether we are in sequence execution mode or in target keeping mode. #[derive(Default)] pub struct SubsystemHelper { pub children_mode_store: ModeStoreVec, @@ -70,7 +74,7 @@ impl SubsystemHelper { children_mode_store: ModeStoreVec, target_tables: TargetModeTables, sequence_tables: SequenceModeTables, - ) -> Self{ + ) -> Self { Self { children_mode_store, target_tables, @@ -88,6 +92,39 @@ impl SubsystemHelper { self.target_tables.0.insert(mode, target_table_val); self.sequence_tables.0.insert(mode, sequence_table_val); } + + pub fn update_child_mode( + &mut self, + child: ComponentId, + mode: ModeAndSubmode, + ) -> Result<(), TargetNotInModeStoreError> { + self.children_mode_store.set_mode(child, mode) + } + + pub fn insert_mode_reply(&mut self, reply: &ModeReply) { + // 1. Update child mode store (also, do we really need one?) + // 2. If a sequence is active, check whether this completes the sequence. How do we best + // do this? We would have to remember which IDs need a mode confirmation. We could + // extend the mode store for this. + // 3. If no sequence is active and we are in target mode, we need to check whether the + // target mode table is violated. If it is, we need to command the fallback mode. + } + + pub fn run( + &mut self, + req_sender: &impl ModeRequestSender, + ) -> Result { + //if self.helper.awaiting_check_success() { + //self.check_current_sequence_against_mode_store(); + //} + self.helper.run(&self.sequence_tables, req_sender) + } + + //pub fn check_current_sequence_against_mode_store(&self) { + // TODO: Check whether current sequence requires success checks and if some are required, + // check mode store content against the sequence target mode. + + //} } #[derive(Default, Debug)]