continue dev mgmt commanding helper

This commit is contained in:
Robin Müller 2025-01-31 15:18:07 +01:00
parent 68939d3699
commit 23841a14dc
Signed by: muellerr
GPG Key ID: A649FB78196E3849
2 changed files with 59 additions and 67 deletions

View File

@ -3,17 +3,22 @@ use crate::{
mode_tree::{ModeStoreProvider, ModeStoreVec}, mode_tree::{ModeStoreProvider, ModeStoreVec},
queue::GenericTargetedMessagingError, queue::GenericTargetedMessagingError,
request::{GenericMessage, RequestId}, request::{GenericMessage, RequestId},
subsystem::ModeTreeHelperState,
ComponentId, ComponentId,
}; };
use core::fmt::Debug; use core::fmt::Debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ActiveModeCommandContext {
pub target_mode: ModeAndSubmode,
pub active_request_id: RequestId,
}
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub enum DevManagerHelperResult { pub enum DevManagerHelperResult {
#[default] #[default]
Idle, Idle,
Busy, Busy,
ModeCommandingDone, ModeCommandingDone(ActiveModeCommandContext),
} }
#[derive(Debug)] #[derive(Debug)]
@ -24,7 +29,8 @@ pub enum DevManagerHelperError {
pub trait DevManagerUserHook: Debug { pub trait DevManagerUserHook: Debug {
fn send_mode_cmds_to_children( fn send_mode_cmds_to_children(
&self, &self,
parent_mode: ModeAndSubmode, request_id: RequestId,
commanded_parent_mode: ModeAndSubmode,
forced: bool, forced: bool,
children_mode_store: &mut ModeStoreVec, children_mode_store: &mut ModeStoreVec,
mode_req_sender: &impl ModeRequestSender, mode_req_sender: &impl ModeRequestSender,
@ -37,6 +43,7 @@ pub struct TransparentDevManagerHook {}
impl DevManagerUserHook for TransparentDevManagerHook { impl DevManagerUserHook for TransparentDevManagerHook {
fn send_mode_cmds_to_children( fn send_mode_cmds_to_children(
&self, &self,
request_id: RequestId,
commanded_parent_mode: ModeAndSubmode, commanded_parent_mode: ModeAndSubmode,
forced: bool, forced: bool,
children_mode_store: &mut ModeStoreVec, children_mode_store: &mut ModeStoreVec,
@ -44,7 +51,7 @@ impl DevManagerUserHook for TransparentDevManagerHook {
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
for child in children_mode_store { for child in children_mode_store {
mode_req_sender.send_mode_request( mode_req_sender.send_mode_request(
0, request_id,
child.id(), child.id(),
ModeRequest::SetMode { ModeRequest::SetMode {
mode_and_submode: commanded_parent_mode, mode_and_submode: commanded_parent_mode,
@ -57,31 +64,41 @@ impl DevManagerUserHook for TransparentDevManagerHook {
} }
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum DevManagerCommandingState {
#[default]
Idle,
AwaitingReplies(ActiveModeCommandContext),
}
impl DevManagerCommandingState {
fn new_active_cmd(mode_and_submode: ModeAndSubmode, active_request_id: RequestId) -> Self {
DevManagerCommandingState::AwaitingReplies(ActiveModeCommandContext {
target_mode: mode_and_submode,
active_request_id,
})
}
}
/// A generic helper for manager components which manage child components in a mode tree. /// A generic helper for manager components which manage child components in a mode tree.
/// ///
/// Mode commands are usually forwarded to all children components transparently. /// Mode commands are usually forwarded to all children components transparently.
/// For example, this could be used in an Assembly component which manages multiple redundant /// 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. /// child components. It can also be used inside a manager component which only manages one device.
#[derive(Debug)] #[derive(Debug, Default)]
pub struct DevManagerCommandingHelper<UserHook: DevManagerUserHook> { pub struct DevManagerCommandingHelper<UserHook: DevManagerUserHook> {
/// The IDs, modes and reply awaition status of all children are tracked in this data /// The IDs, modes and reply awaition status of all children are tracked in this data
/// structure. /// structure.
pub children_mode_store: ModeStoreVec, pub children_mode_store: ModeStoreVec,
pub user_hook: UserHook, pub user_hook: UserHook,
/// Target mode used for mode commanding. pub state: DevManagerCommandingState,
target_mode: Option<ModeAndSubmode>,
/// Request ID of active mode commanding request.
active_request_id: Option<RequestId>,
state: ModeTreeHelperState,
} }
impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> { impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
pub fn new(user_hook: UserHook) -> Self { pub fn new(user_hook: UserHook) -> Self {
Self { Self {
children_mode_store: Default::default(), children_mode_store: Default::default(),
target_mode: None,
user_hook, user_hook,
active_request_id: None,
state: Default::default(), state: Default::default(),
} }
} }
@ -94,7 +111,7 @@ impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
forced: bool, forced: bool,
mode_req_sender: &impl ModeRequestSender, mode_req_sender: &impl ModeRequestSender,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.target_mode = Some(mode_and_submode); self.state = DevManagerCommandingState::new_active_cmd(mode_and_submode, request_id);
mode_req_sender.send_mode_request( mode_req_sender.send_mode_request(
request_id, request_id,
target_id, target_id,
@ -103,8 +120,6 @@ impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
forced, forced,
}, },
)?; )?;
self.active_request_id = Some(request_id);
self.state = ModeTreeHelperState::ModeCommanding;
Ok(()) Ok(())
} }
@ -115,27 +130,25 @@ impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
forced: bool, forced: bool,
mode_req_sender: &impl ModeRequestSender, mode_req_sender: &impl ModeRequestSender,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.target_mode = Some(mode_and_submode); self.state = DevManagerCommandingState::new_active_cmd(mode_and_submode, request_id);
self.user_hook.send_mode_cmds_to_children( self.user_hook.send_mode_cmds_to_children(
request_id,
mode_and_submode, mode_and_submode,
forced, forced,
&mut self.children_mode_store, &mut self.children_mode_store,
mode_req_sender, mode_req_sender,
)?; )?;
self.active_request_id = Some(request_id);
self.state = ModeTreeHelperState::ModeCommanding;
Ok(()) Ok(())
} }
pub fn target_mode(&self) -> Option<ModeAndSubmode> { pub fn target_mode(&self) -> Option<ModeAndSubmode> {
self.target_mode match self.state {
DevManagerCommandingState::Idle => None,
DevManagerCommandingState::AwaitingReplies(context) => Some(context.target_mode),
}
} }
pub fn active_request_id(&self) -> Option<RequestId> { pub fn state(&self) -> DevManagerCommandingState {
self.active_request_id
}
pub fn state(&self) -> ModeTreeHelperState {
self.state self.state
} }
@ -170,22 +183,16 @@ impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
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<usize> {
Some(self.count_number_of_children_with_mode(self.target_mode?))
}
pub fn handle_mode_reply( pub fn handle_mode_reply(
&mut self, &mut self,
mode_reply: &GenericMessage<ModeReply>, mode_reply: &GenericMessage<ModeReply>,
) -> Result<DevManagerHelperResult, DevManagerHelperError> { ) -> Result<DevManagerHelperResult, DevManagerHelperError> {
if self.target_mode().is_none() || self.active_request_id().is_none() { let context = match self.state {
return Ok(DevManagerHelperResult::Idle); DevManagerCommandingState::Idle => return Ok(DevManagerHelperResult::Idle),
DevManagerCommandingState::AwaitingReplies(active_mode_command_context) => {
Some(active_mode_command_context)
} }
};
if !self if !self
.children_mode_store .children_mode_store
.has_component(mode_reply.sender_id()) .has_component(mode_reply.sender_id())
@ -197,10 +204,7 @@ impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
// 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.
let mut handle_awaition = false; let mut handle_awaition = false;
if self.state == ModeTreeHelperState::ModeCommanding if let DevManagerCommandingState::AwaitingReplies { .. } = self.state {
&& self.active_request_id.is_some()
&& mode_reply.request_id() == self.active_request_id.unwrap()
{
handle_awaition = true; handle_awaition = true;
} }
let still_awating_replies = self.children_mode_store.mode_reply_handler( let still_awating_replies = self.children_mode_store.mode_reply_handler(
@ -210,13 +214,9 @@ impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
); );
// It is okay to unwrap: If awaition should be handled, the returned value should // It is okay to unwrap: If awaition should be handled, the returned value should
// always be some valid value. // always be some valid value.
if self.state == ModeTreeHelperState::ModeCommanding if handle_awaition && !still_awating_replies.unwrap() {
&& handle_awaition self.state = DevManagerCommandingState::Idle;
&& !still_awating_replies.unwrap() return Ok(DevManagerHelperResult::ModeCommandingDone(context.unwrap()));
{
self.state = ModeTreeHelperState::TargetKeeping;
self.active_request_id = None;
return Ok(DevManagerHelperResult::ModeCommandingDone);
} }
Ok(DevManagerHelperResult::Busy) Ok(DevManagerHelperResult::Busy)
}; };
@ -247,9 +247,7 @@ mod tests {
#[test] #[test]
fn test_basic() { fn test_basic() {
let assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default()); let assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default());
assert_eq!(assy_helper.state(), ModeTreeHelperState::Idle); assert_eq!(assy_helper.state(), DevManagerCommandingState::Idle);
assert!(assy_helper.active_request_id().is_none());
assert!(assy_helper.target_mode().is_none());
} }
#[test] #[test]

View File

@ -552,19 +552,12 @@ impl MgmAssembly {
self.mode_reply_mock.handle_mode_reply(&reply_and_id); self.mode_reply_mock.handle_mode_reply(&reply_and_id);
match self.commanding_helper.handle_mode_reply(&reply_and_id) { match self.commanding_helper.handle_mode_reply(&reply_and_id) {
Ok(result) => { Ok(result) => {
match result { if let DevManagerHelperResult::ModeCommandingDone(context) = result {
DevManagerHelperResult::Idle => todo!(),
DevManagerHelperResult::Busy => todo!(),
DevManagerHelperResult::ModeCommandingDone => {
if self.commanding_helper.target_mode().is_some() {
// Complete the mode command. // Complete the mode command.
self.mode_and_submode = self.mode_and_submode = context.target_mode;
self.commanding_helper.target_mode().unwrap();
self.handle_mode_reached(self.mode_requestor_info)?; self.handle_mode_reached(self.mode_requestor_info)?;
} }
} }
}
}
Err(err) => match err { Err(err) => match err {
satrs::dev_mgmt::DevManagerHelperError::ChildNotInStore => todo!(), satrs::dev_mgmt::DevManagerHelperError::ChildNotInStore => todo!(),
}, },
@ -742,12 +735,10 @@ impl DeviceManager {
match result { match result {
DevManagerHelperResult::Idle => todo!(), DevManagerHelperResult::Idle => todo!(),
DevManagerHelperResult::Busy => todo!(), DevManagerHelperResult::Busy => todo!(),
DevManagerHelperResult::ModeCommandingDone => { DevManagerHelperResult::ModeCommandingDone(context) => {
if self.commanding_helper.target_mode().is_some() {
// Complete the mode command. // Complete the mode command.
self.handle_mode_reached(self.mode_requestor_info)?; self.handle_mode_reached(self.mode_requestor_info)?;
self.mode_and_submode = self.commanding_helper.target_mode().unwrap(); self.mode_and_submode = context.target_mode;
}
} }
} }
} }
@ -932,6 +923,9 @@ impl ModeRequestHandler for CommonDevice {
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
forced: bool, forced: bool,
) -> Result<(), ModeError> { ) -> Result<(), ModeError> {
if self.id() == TestComponentId::MagnetorquerDevice as u64 {
println!("test");
}
self.mode_and_submode = mode_and_submode; self.mode_and_submode = mode_and_submode;
self.handle_mode_reached(Some(requestor))?; self.handle_mode_reached(Some(requestor))?;
self.mode_req_mock self.mode_req_mock