diff --git a/satrs/src/dev_mgmt.rs b/satrs/src/dev_mgmt.rs index 11c1c3a..1ddefd5 100644 --- a/satrs/src/dev_mgmt.rs +++ b/satrs/src/dev_mgmt.rs @@ -6,25 +6,68 @@ use crate::{ subsystem::ModeTreeHelperState, ComponentId, }; +use core::fmt::Debug; #[derive(Debug, Default)] -pub enum AssemblyHelperResult { +pub enum DevManagerHelperResult { #[default] Idle, - TargetKeepingViolation(ComponentId), + Busy, ModeCommandingDone, } +#[derive(Debug)] +pub enum DevManagerHelperError { + ChildNotInStore, +} + +pub trait DevManagerUserHook: Debug { + fn send_mode_cmds_to_children( + &self, + parent_mode: ModeAndSubmode, + forced: bool, + children_mode_store: &mut ModeStoreVec, + mode_req_sender: &impl ModeRequestSender, + ) -> Result<(), GenericTargetedMessagingError>; +} + +#[derive(Debug, Default)] +pub struct TransparentDevManagerHook {} + +impl DevManagerUserHook for TransparentDevManagerHook { + fn send_mode_cmds_to_children( + &self, + commanded_parent_mode: ModeAndSubmode, + forced: bool, + children_mode_store: &mut ModeStoreVec, + mode_req_sender: &impl ModeRequestSender, + ) -> Result<(), GenericTargetedMessagingError> { + for child in children_mode_store { + mode_req_sender.send_mode_request( + 0, + child.id(), + ModeRequest::SetMode { + mode_and_submode: commanded_parent_mode, + forced, + }, + )?; + child.awaiting_reply = true; + } + Ok(()) + } +} + /// A generic helper for manager components which manage child components in a mode tree. /// /// Mode commands are usually forwarded to all children components transparently. /// For example, this could be used in an Assembly component which manages multiple redundant /// child components. It can also be used inside a manager component which only manages one device. -#[derive(Debug, Default)] -pub struct AssemblyCommandingHelper { +#[derive(Debug)] +pub struct DevManagerCommandingHelper { /// The IDs, modes and reply awaition status of all children are tracked in this data /// structure. pub children_mode_store: ModeStoreVec, + pub user_hook: UserHook, /// Target mode used for mode commanding. target_mode: Option, /// Request ID of active mode commanding request. @@ -32,10 +75,40 @@ pub struct AssemblyCommandingHelper { state: ModeTreeHelperState, } -pub type DevManagerCommandingHelper = AssemblyCommandingHelper; +impl DevManagerCommandingHelper { + pub fn new(user_hook: UserHook) -> Self { + Self { + children_mode_store: Default::default(), + target_mode: None, + user_hook, + active_request_id: None, + state: Default::default(), + } + } -impl AssemblyCommandingHelper { - pub fn send_mode_cmd_to_all_children_with_reply_awaition( + pub fn send_mode_cmd_to_one_child( + &mut self, + request_id: RequestId, + target_id: ComponentId, + mode_and_submode: ModeAndSubmode, + forced: bool, + mode_req_sender: &impl ModeRequestSender, + ) -> Result<(), GenericTargetedMessagingError> { + self.target_mode = Some(mode_and_submode); + mode_req_sender.send_mode_request( + request_id, + target_id, + ModeRequest::SetMode { + mode_and_submode, + forced, + }, + )?; + self.active_request_id = Some(request_id); + self.state = ModeTreeHelperState::ModeCommanding; + Ok(()) + } + + pub fn send_mode_cmd_to_all_children( &mut self, request_id: RequestId, mode_and_submode: ModeAndSubmode, @@ -43,17 +116,12 @@ impl AssemblyCommandingHelper { mode_req_sender: &impl ModeRequestSender, ) -> Result<(), GenericTargetedMessagingError> { self.target_mode = Some(mode_and_submode); - for child in self.children_mode_store.0.iter_mut() { - mode_req_sender.send_mode_request( - request_id, - child.id(), - ModeRequest::SetMode { - mode_and_submode, - forced, - }, - )?; - child.awaiting_reply = true; - } + self.user_hook.send_mode_cmds_to_children( + mode_and_submode, + forced, + &mut self.children_mode_store, + mode_req_sender, + )?; self.active_request_id = Some(request_id); self.state = ModeTreeHelperState::ModeCommanding; Ok(()) @@ -91,27 +159,38 @@ impl AssemblyCommandingHelper { self.children_mode_store.add_component(target_id, mode); } - pub fn count_number_of_children_with_target_mode(&self) -> Option { - self.target_mode?; - let target_mode = self.target_mode.unwrap(); + /// Helper method which counts the number of children which have a certain mode. + pub fn count_number_of_children_with_mode(&self, mode_and_submode: ModeAndSubmode) -> usize { let mut children_in_target_mode = 0; - for child in self.children_mode_store.0.iter() { - if child.mode_and_submode() == target_mode { + for child in &self.children_mode_store { + if child.mode_and_submode() == mode_and_submode { children_in_target_mode += 1; } } - Some(children_in_target_mode) + children_in_target_mode + } + + /// Helper method which counts the number of children which have the mode of the assembly + /// itself. + /// + /// This is useful for device managers where the child or the children devices should have the + /// same mode as the device manager. + pub fn count_number_of_children_with_target_mode(&self) -> Option { + Some(self.count_number_of_children_with_mode(self.target_mode?)) } pub fn handle_mode_reply( &mut self, mode_reply: &GenericMessage, - ) -> AssemblyHelperResult { + ) -> Result { + if self.target_mode().is_none() || self.active_request_id().is_none() { + return Ok(DevManagerHelperResult::Idle); + } if !self .children_mode_store .has_component(mode_reply.sender_id()) { - return AssemblyHelperResult::Idle; + return Err(DevManagerHelperError::ChildNotInStore); } let mut generic_mode_reply_handler = |mode_and_submode: Option| { // Tying the reply awaition to the request ID ensures that something like replies @@ -129,13 +208,6 @@ impl AssemblyCommandingHelper { mode_and_submode, handle_awaition, ); - if self.state == ModeTreeHelperState::TargetKeeping - && mode_and_submode.is_some() - && self.target_mode.is_some() - && mode_and_submode.unwrap() != self.target_mode.unwrap() - { - return AssemblyHelperResult::TargetKeepingViolation(mode_reply.sender_id()); - } // It is okay to unwrap: If awaition should be handled, the returned value should // always be some valid value. if self.state == ModeTreeHelperState::ModeCommanding @@ -144,9 +216,9 @@ impl AssemblyCommandingHelper { { self.state = ModeTreeHelperState::TargetKeeping; self.active_request_id = None; - return AssemblyHelperResult::ModeCommandingDone; + return Ok(DevManagerHelperResult::ModeCommandingDone); } - AssemblyHelperResult::Idle + Ok(DevManagerHelperResult::Busy) }; match mode_reply.message { ModeReply::ModeInfo(mode_and_submode) | ModeReply::ModeReply(mode_and_submode) => { @@ -174,7 +246,7 @@ mod tests { #[test] fn test_basic() { - let assy_helper = AssemblyCommandingHelper::default(); + let assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default()); assert_eq!(assy_helper.state(), ModeTreeHelperState::Idle); assert!(assy_helper.active_request_id().is_none()); assert!(assy_helper.target_mode().is_none()); @@ -182,7 +254,7 @@ mod tests { #[test] fn test_mode_announce() { - let mut assy_helper = AssemblyCommandingHelper::default(); + let mut assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default()); let mode_req_sender = ModeReqSenderMock::default(); assy_helper.add_mode_child(ExampleId::Id1 as u64, UNKNOWN_MODE); assy_helper.add_mode_child(ExampleId::Id2 as u64, UNKNOWN_MODE); @@ -199,10 +271,10 @@ mod tests { assert_eq!(req.request_id, 1); assert_eq!(req.request, ModeRequest::AnnounceMode); } - + #[test] fn test_mode_announce_recursive() { - let mut assy_helper = AssemblyCommandingHelper::default(); + let mut assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default()); let mode_req_sender = ModeReqSenderMock::default(); assy_helper.add_mode_child(ExampleId::Id1 as u64, UNKNOWN_MODE); assy_helper.add_mode_child(ExampleId::Id2 as u64, UNKNOWN_MODE); @@ -221,10 +293,9 @@ mod tests { } #[test] - fn test_mode_commanding() { - let mut assy_helper = AssemblyCommandingHelper::default(); + fn test_mode_commanding_one_child() { + let mut assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default()); let mode_req_sender = ModeReqSenderMock::default(); - assy_helper.send_mode_cmd_to_all_children_with_reply_awaition(1, , forced, mode_req_sender) - + //assy_helper.send_mode_cmd_to_all_children_with_reply_awaition(1, , forced, mode_req_sender) } } diff --git a/satrs/src/health.rs b/satrs/src/health.rs new file mode 100644 index 0000000..9d32457 --- /dev/null +++ b/satrs/src/health.rs @@ -0,0 +1,39 @@ +use crate::ComponentId; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum HealthState { + Healthy = 1, + Faulty = 2, + PermanentFaulty = 3, + ExternalControl = 4, + NeedsRecovery = 5, +} + +pub trait HealthTableProvider { + fn health(&self, id: ComponentId) -> Option; + fn set_health(&mut self, id: ComponentId, health: HealthState); +} + +#[cfg(feature = "std")] +#[derive(Debug, Clone)] +pub struct HealthTableMapSync( + std::sync::Arc>>, +); + +#[cfg(feature = "std")] +impl HealthTableMapSync { + pub fn new(health_table: hashbrown::HashMap) -> Self { + Self(std::sync::Arc::new(std::sync::Mutex::new(health_table))) + } +} + +#[cfg(feature = "std")] +impl HealthTableProvider for HealthTableMapSync { + fn health(&self, id: ComponentId) -> Option { + self.0.lock().unwrap().get(&id).copied() + } + + fn set_health(&mut self, id: ComponentId, health: HealthState) { + self.0.lock().unwrap().insert(id, health); + } +} diff --git a/satrs/src/lib.rs b/satrs/src/lib.rs index e0fead3..5b81fe2 100644 --- a/satrs/src/lib.rs +++ b/satrs/src/lib.rs @@ -31,6 +31,7 @@ pub mod events; #[cfg(feature = "std")] pub mod executable; pub mod hal; +pub mod health; pub mod hk; pub mod mode; #[cfg(feature = "std")] diff --git a/satrs/src/mode_tree.rs b/satrs/src/mode_tree.rs index e184d58..e058378 100644 --- a/satrs/src/mode_tree.rs +++ b/satrs/src/mode_tree.rs @@ -360,10 +360,37 @@ pub mod alloc_mod { #[derive(Debug, Default)] pub struct ModeStoreVec(pub alloc::vec::Vec); + impl<'a> IntoIterator for &'a ModeStoreVec { + type Item = &'a ModeStoreValue; + type IntoIter = std::slice::Iter<'a, ModeStoreValue>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } + } + + impl<'a> IntoIterator for &'a mut ModeStoreVec { + type Item = &'a mut ModeStoreValue; + type IntoIter = std::slice::IterMut<'a, ModeStoreValue>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter_mut() + } + } + /// Mode store which tracks the mode information inside a [hashbrown::HashMap] #[derive(Debug, Default)] pub struct ModeStoreMap(pub hashbrown::HashMap); + impl<'a> IntoIterator for &'a ModeStoreMap { + type Item = (&'a ComponentId, &'a ModeStoreValue); + type IntoIter = hashbrown::hash_map::Iter<'a, ComponentId, ModeStoreValue>; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } + } + impl ModeStoreProvider for ModeStoreVec { fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) { self.0.push(ModeStoreValue::new(target_id, mode)); diff --git a/satrs/src/subsystem.rs b/satrs/src/subsystem.rs index 2a458d0..b1235f4 100644 --- a/satrs/src/subsystem.rs +++ b/satrs/src/subsystem.rs @@ -1,4 +1,5 @@ use crate::{ + health::{HealthState, HealthTableProvider}, mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender, UNKNOWN_MODE_VAL}, mode_tree::{ ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableMapTable, @@ -70,6 +71,20 @@ impl Default for SequenceExecutionHelper { } } +pub trait IsChildCommandable { + fn is_commandable(&self, id: ComponentId) -> bool; +} + +impl IsChildCommandable for T +where + T: HealthTableProvider, +{ + fn is_commandable(&self, id: ComponentId) -> bool { + self.health(id) + .is_some_and(|h| h != HealthState::ExternalControl) + } +} + impl SequenceExecutionHelper { pub fn new() -> Self { Default::default() @@ -127,6 +142,7 @@ impl SequenceExecutionHelper { table: &SequenceModeTables, sender: &impl ModeRequestSender, children_mode_store: &mut ModeStoreVec, + is_commandable: &impl IsChildCommandable, ) -> Result { if self.state == SequenceExecutionHelperState::Idle { return Ok(ModeCommandingResult::Done); @@ -146,6 +162,7 @@ impl SequenceExecutionHelper { idx, sender, children_mode_store, + is_commandable, ) } None => { @@ -161,6 +178,7 @@ impl SequenceExecutionHelper { 0, sender, children_mode_store, + is_commandable, ) } } @@ -218,6 +236,7 @@ impl SequenceExecutionHelper { sequence_idx: usize, sender: &impl ModeRequestSender, mode_store_vec: &mut ModeStoreVec, + is_commandable: &impl IsChildCommandable, ) -> Result { if self.state() == SequenceExecutionHelperState::Idle || self.request_id.is_none() { return Ok(ModeCommandingResult::Done); @@ -227,6 +246,7 @@ impl SequenceExecutionHelper { &seq_table_value.entries[sequence_idx], sender, mode_store_vec, + is_commandable, )? { self.state = SequenceExecutionHelperState::AwaitingSuccessCheck; Ok(ModeCommandingResult::AwaitingSuccessCheck) @@ -255,9 +275,13 @@ impl SequenceExecutionHelper { map_table: &SequenceTableMapTable, sender: &impl ModeRequestSender, children_mode_store: &mut ModeStoreVec, + commandable: &impl IsChildCommandable, ) -> Result { let mut some_succes_check_required = false; for entry in &map_table.entries { + if !commandable.is_commandable(entry.common.target_id) { + continue; + } sender.send_mode_request( request_id, entry.common.target_id, @@ -485,6 +509,7 @@ impl SubsystemCommandingHelper { &mut self, opt_reply: Option>, req_sender: &impl ModeRequestSender, + is_commandable: &impl IsChildCommandable, ) -> Result { if let Some(reply) = opt_reply { if self.handle_mode_reply(&reply)? { @@ -513,6 +538,7 @@ impl SubsystemCommandingHelper { &self.sequence_tables, req_sender, &mut self.children_mode_store, + is_commandable, )?; match result { ModeCommandingResult::Done => { @@ -657,7 +683,8 @@ mod tests { use crate::{ mode::{ - tests::{ModeReqSenderMock, ModeReqWrapper}, Mode, ModeAndSubmode, ModeReply, ModeRequest, UNKNOWN_MODE, + tests::{ModeReqSenderMock, ModeReqWrapper}, + Mode, ModeAndSubmode, ModeReply, ModeRequest, UNKNOWN_MODE, }, mode_tree::{ ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableEntry, @@ -683,11 +710,23 @@ mod tests { Mode2 = 3, } + #[derive(Debug, Default)] + pub struct IsCommandableMock { + pub commandable_map: std::collections::HashMap, + } + + impl IsChildCommandable for IsCommandableMock { + fn is_commandable(&self, id: ComponentId) -> bool { + self.commandable_map.get(&id).copied().unwrap_or(false) + } + } + pub struct SequenceExecutorTestbench { pub sender: ModeReqSenderMock, pub mode_store: ModeStoreVec, pub seq_tables: SequenceModeTables, pub execution_helper: SequenceExecutionHelper, + pub is_commandable_mock: IsCommandableMock, } impl SequenceExecutorTestbench { @@ -699,6 +738,7 @@ mod tests { mode_store, seq_tables, execution_helper: SequenceExecutionHelper::new(), + is_commandable_mock: IsCommandableMock::default(), } } @@ -707,15 +747,24 @@ mod tests { } pub fn run(&mut self) -> Result { - self.execution_helper - .run(&self.seq_tables, &self.sender, &mut self.mode_store) + self.execution_helper.run( + &self.seq_tables, + &self.sender, + &mut self.mode_store, + &self.is_commandable_mock, + ) } fn check_run_is_no_op(&mut self) { // Assure that no unexpected behaviour occurs. assert_eq!( self.execution_helper - .run(&self.seq_tables, &self.sender, &mut self.mode_store) + .run( + &self.seq_tables, + &self.sender, + &mut self.mode_store, + &self.is_commandable_mock + ) .unwrap(), ModeCommandingResult::Done ); @@ -861,6 +910,7 @@ mod tests { pub struct SubsystemHelperTestbench { pub sender: ModeReqSenderMock, pub helper: SubsystemCommandingHelper, + pub is_commandable_mock: IsCommandableMock, } impl SubsystemHelperTestbench { @@ -873,6 +923,7 @@ mod tests { target_tables, sequence_tables, ), + is_commandable_mock: IsCommandableMock::default(), } } @@ -905,7 +956,8 @@ mod tests { &mut self, opt_reply: Option>, ) -> Result { - self.helper.state_machine(opt_reply, &self.sender) + self.helper + .state_machine(opt_reply, &self.sender, &self.is_commandable_mock) } pub fn generic_checks_subsystem_md0(&mut self, expected_req_id: RequestId) { diff --git a/satrs/tests/mode_tree.rs b/satrs/tests/mode_tree.rs index 7bfb979..bbfe9e9 100644 --- a/satrs/tests/mode_tree.rs +++ b/satrs/tests/mode_tree.rs @@ -1,6 +1,8 @@ use core::cell::Cell; use num_enum::TryFromPrimitive; -use satrs::dev_mgmt::{AssemblyCommandingHelper, AssemblyHelperResult}; +use satrs::dev_mgmt::{ + DevManagerCommandingHelper, DevManagerHelperResult, TransparentDevManagerHook, +}; use satrs::mode::{ Mode, ModeError, ModeProvider, ModeReplyReceiver, ModeReplySender, ModeRequestHandler, ModeRequestHandlerMpscBounded, ModeRequestReceiver, ModeRequestorAndHandlerMpscBounded, @@ -14,8 +16,8 @@ use satrs::mode_tree::{SequenceTablesMapValue, TargetTablesMapValue}; use satrs::request::{MessageMetadata, RequestId}; use satrs::res_code::ResultU16; use satrs::subsystem::{ - ModeCommandingResult, ModeTreeHelperError, ModeTreeHelperState, StartSequenceError, - SubsystemCommandingHelper, SubsystemHelperResult, + IsChildCommandable, ModeCommandingResult, ModeTreeHelperError, ModeTreeHelperState, + StartSequenceError, SubsystemCommandingHelper, SubsystemHelperResult, }; use satrs::{ mode::{ModeAndSubmode, ModeReply, ModeRequest}, @@ -276,11 +278,21 @@ impl ModeParent for PusModeService { } } +#[derive(Debug, Default)] +struct IsCommandableDummy {} + +impl IsChildCommandable for IsCommandableDummy { + fn is_commandable(&self, _id: ComponentId) -> bool { + true + } +} + struct AcsSubsystem { pub mode_node: ModeRequestorAndHandlerMpscBounded, pub mode_requestor_info: Option, pub target_mode_and_submode: Option, pub subsystem_helper: SubsystemCommandingHelper, + is_commandable_dummy: IsCommandableDummy, pub mode_req_mock: ModeRequestHandlerMock, pub mode_reply_mock: ModeReplyHandlerMock, } @@ -295,6 +307,7 @@ impl AcsSubsystem { mode_node, mode_requestor_info: None, target_mode_and_submode: None, + is_commandable_dummy: IsCommandableDummy::default(), subsystem_helper: SubsystemCommandingHelper::default(), mode_req_mock: ModeRequestHandlerMock::new(Self::id()), mode_reply_mock: ModeReplyHandlerMock::new(Self::id()), @@ -345,13 +358,19 @@ impl AcsSubsystem { while let Some(mode_reply) = self.mode_node.try_recv_mode_reply().unwrap() { received_reply = true; self.mode_reply_mock.handle_mode_reply(&mode_reply); - let result = self - .subsystem_helper - .state_machine(Some(mode_reply), &self.mode_node); + let result = self.subsystem_helper.state_machine( + Some(mode_reply), + &self.mode_node, + &self.is_commandable_dummy, + ); self.handle_subsystem_helper_result(result); } if !received_reply { - let result = self.subsystem_helper.state_machine(None, &self.mode_node); + let result = self.subsystem_helper.state_machine( + None, + &self.mode_node, + &self.is_commandable_dummy, + ); self.handle_subsystem_helper_result(result); } } @@ -492,7 +511,7 @@ struct MgmAssembly { pub mode_node: ModeRequestorAndHandlerMpscBounded, pub mode_requestor_info: Option, pub mode_and_submode: ModeAndSubmode, - pub commanding_helper: AssemblyCommandingHelper, + pub commanding_helper: DevManagerCommandingHelper, pub mode_req_mock: ModeRequestHandlerMock, pub mode_reply_mock: ModeReplyHandlerMock, } @@ -506,7 +525,7 @@ impl MgmAssembly { mode_node, mode_requestor_info: None, mode_and_submode: UNKNOWN_MODE, - commanding_helper: Default::default(), + commanding_helper: DevManagerCommandingHelper::new(TransparentDevManagerHook::default()), mode_req_mock: ModeRequestHandlerMock::new(Self::id()), mode_reply_mock: ModeReplyHandlerMock::new(Self::id()), } @@ -532,18 +551,23 @@ impl MgmAssembly { while let Some(reply_and_id) = self.mode_node.try_recv_mode_reply()? { self.mode_reply_mock.handle_mode_reply(&reply_and_id); match self.commanding_helper.handle_mode_reply(&reply_and_id) { - AssemblyHelperResult::Idle => (), - AssemblyHelperResult::TargetKeepingViolation(_id) => { - // TODO: Check whether enough children are available to keep the mode. - // Otherwise, we command everything OFF, because we can not keep the mode. - } - AssemblyHelperResult::ModeCommandingDone => { - if self.commanding_helper.target_mode().is_some() { - // Complete the mode command. - self.mode_and_submode = self.commanding_helper.target_mode().unwrap(); - self.handle_mode_reached(self.mode_requestor_info)?; + Ok(result) => { + match result { + DevManagerHelperResult::Idle => todo!(), + DevManagerHelperResult::Busy => todo!(), + DevManagerHelperResult::ModeCommandingDone => { + if self.commanding_helper.target_mode().is_some() { + // Complete the mode command. + self.mode_and_submode = + self.commanding_helper.target_mode().unwrap(); + self.handle_mode_reached(self.mode_requestor_info)?; + } + } } } + Err(err) => match err { + satrs::dev_mgmt::DevManagerHelperError::ChildNotInStore => todo!(), + }, } } Ok(()) @@ -597,13 +621,12 @@ impl ModeRequestHandler for MgmAssembly { self.mode_req_mock .start_transition(requestor, mode_and_submode, forced) .unwrap(); - self.commanding_helper - .send_mode_cmd_to_all_children_with_reply_awaition( - requestor.request_id(), - mode_and_submode, - forced, - &self.mode_node, - )?; + self.commanding_helper.send_mode_cmd_to_all_children( + requestor.request_id(), + mode_and_submode, + forced, + &self.mode_node, + )?; Ok(()) } @@ -660,7 +683,7 @@ impl ModeRequestHandler for MgmAssembly { struct DeviceManager { name: &'static str, pub id: ComponentId, - pub commanding_helper: AssemblyCommandingHelper, + pub commanding_helper: DevManagerCommandingHelper, pub mode_node: ModeRequestorAndHandlerMpscBounded, pub mode_requestor_info: Option, pub mode_and_submode: ModeAndSubmode, @@ -679,7 +702,7 @@ impl DeviceManager { id, mode_node, mode_requestor_info: None, - commanding_helper: Default::default(), + commanding_helper: DevManagerCommandingHelper::new(TransparentDevManagerHook::default()), mode_and_submode: UNKNOWN_MODE, mode_req_mock: ModeRequestHandlerMock::new(id), mode_reply_mock: ModeReplyHandlerMock::new(id), @@ -715,30 +738,22 @@ impl DeviceManager { ) -> Result<(), ModeError> { self.mode_reply_mock.handle_mode_reply(mode_reply); match self.commanding_helper.handle_mode_reply(mode_reply) { - AssemblyHelperResult::Idle => (), - AssemblyHelperResult::TargetKeepingViolation(_id) => { - // TODO: Check whether enough children are available to keep the mode. - // Otherwise, we command everything OFF, because we can not keep the mode. - if self - .commanding_helper - .count_number_of_children_with_target_mode() - .unwrap() - < 1 - { - if let Err(_e) = self.start_transition( - MessageMetadata::new(0, self.id()), - ModeAndSubmode::new(DefaultMode::OFF as Mode, 0), - false, - ) {} - } - } - AssemblyHelperResult::ModeCommandingDone => { - if self.commanding_helper.target_mode().is_some() { - // Complete the mode command. - self.handle_mode_reached(self.mode_requestor_info)?; - self.mode_and_submode = self.commanding_helper.target_mode().unwrap(); + Ok(result) => { + match result { + DevManagerHelperResult::Idle => todo!(), + DevManagerHelperResult::Busy => todo!(), + DevManagerHelperResult::ModeCommandingDone => { + if self.commanding_helper.target_mode().is_some() { + // Complete the mode command. + self.handle_mode_reached(self.mode_requestor_info)?; + self.mode_and_submode = self.commanding_helper.target_mode().unwrap(); + } + } } } + Err(e) => match e { + satrs::dev_mgmt::DevManagerHelperError::ChildNotInStore => todo!(), + }, } Ok(()) } @@ -789,13 +804,12 @@ impl ModeRequestHandler for DeviceManager { self.mode_req_mock .start_transition(requestor, mode_and_submode, forced) .unwrap(); - self.commanding_helper - .send_mode_cmd_to_all_children_with_reply_awaition( - requestor.request_id(), - mode_and_submode, - forced, - &self.mode_node, - )?; + self.commanding_helper.send_mode_cmd_to_all_children( + requestor.request_id(), + mode_and_submode, + forced, + &self.mode_node, + )?; Ok(()) }