continue dev mgmt commanding helper
This commit is contained in:
parent
68939d3699
commit
23841a14dc
@ -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]
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user