Compare commits
29 Commits
682fa964d3
...
68d20b222a
Author | SHA1 | Date | |
---|---|---|---|
68d20b222a | |||
f202ba59d0 | |||
2b01537cfd | |||
bda47b067d | |||
4d1dd0aa19 | |||
245cd6a2c2 | |||
7b1efeb150 | |||
b46c06f1af | |||
b948f9fe2d | |||
4a2262dbe2 | |||
fabe52ee0d | |||
803f626d51 | |||
559e040ea9 | |||
43f67876c1 | |||
b7662636f5 | |||
a326da6ed6 | |||
da6ed5233d | |||
7532dd78de | |||
d5d3577af8 | |||
1a211b073f | |||
3ec5c76733 | |||
51e723a45f | |||
a27e1e308d | |||
31074dc1aa | |||
d97ae401e5 | |||
f4624afd41 | |||
d9a20e2d7d | |||
c18fbb59ad | |||
c91ddcd658 |
3
docs.sh
Executable file
3
docs.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
|
||||
cargo +nightly doc --all-features --open
|
@ -386,6 +386,7 @@ impl<
|
||||
&mut self,
|
||||
requestor: MessageMetadata,
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
_forced: bool,
|
||||
) -> Result<(), satrs::mode::ModeError> {
|
||||
log::info!(
|
||||
"{}: transitioning to mode {:?}",
|
||||
@ -575,7 +576,10 @@ mod tests {
|
||||
.mode_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as u32, 0)),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
.expect("failed to send mode request");
|
||||
testbench.handler.periodic_operation();
|
||||
@ -633,7 +637,10 @@ mod tests {
|
||||
.mode_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as u32, 0)),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
.expect("failed to send mode request");
|
||||
testbench.handler.periodic_operation();
|
||||
|
@ -412,6 +412,7 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeRequestHandler
|
||||
&mut self,
|
||||
requestor: MessageMetadata,
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
_forced: bool,
|
||||
) -> Result<(), satrs::mode::ModeError> {
|
||||
log::info!(
|
||||
"{}: transitioning to mode {:?}",
|
||||
@ -660,7 +661,10 @@ mod tests {
|
||||
.mode_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as u32, 0)),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
.expect("failed to send mode request");
|
||||
let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap();
|
||||
@ -692,7 +696,10 @@ mod tests {
|
||||
.mode_request_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, PUS_MODE_SERVICE.id()),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as u32, 0)),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as u32, 0),
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
.expect("failed to send mode request");
|
||||
testbench
|
||||
|
@ -291,7 +291,10 @@ fn static_tmtc_pool_main() {
|
||||
pcdu_handler_mode_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, NO_SENDER),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as Mode, 0)),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as Mode, 0),
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
.expect("sending initial mode request failed");
|
||||
|
||||
@ -598,7 +601,10 @@ fn dyn_tmtc_pool_main() {
|
||||
pcdu_handler_mode_tx
|
||||
.send(GenericMessage::new(
|
||||
MessageMetadata::new(0, NO_SENDER),
|
||||
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as Mode, 0)),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: ModeAndSubmode::new(DeviceMode::Normal as Mode, 0),
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
.expect("sending initial mode request failed");
|
||||
|
||||
|
@ -110,6 +110,7 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
|
||||
),
|
||||
)?;
|
||||
}
|
||||
ModeReply::ModeInfo(_mode_and_submode) => (),
|
||||
};
|
||||
Ok(true)
|
||||
}
|
||||
@ -190,7 +191,13 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
|
||||
}
|
||||
let mode_and_submode = ModeAndSubmode::from_be_bytes(&tc.user_data()[4..])
|
||||
.expect("mode and submode extraction failed");
|
||||
Ok((active_request, ModeRequest::SetMode(mode_and_submode)))
|
||||
Ok((
|
||||
active_request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode,
|
||||
forced: false,
|
||||
},
|
||||
))
|
||||
}
|
||||
Subservice::TcReadMode => Ok((active_request, ModeRequest::ReadMode)),
|
||||
Subservice::TcAnnounceMode => Ok((active_request, ModeRequest::AnnounceMode)),
|
||||
@ -346,7 +353,13 @@ mod tests {
|
||||
let (_active_req, req) = testbench
|
||||
.convert(token, &[], TEST_APID, TEST_UNIQUE_ID_0)
|
||||
.expect("conversion has failed");
|
||||
assert_eq!(req, ModeRequest::SetMode(mode_and_submode));
|
||||
assert_eq!(
|
||||
req,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
156
satrs/src/dev_mgmt.rs
Normal file
156
satrs/src/dev_mgmt.rs
Normal file
@ -0,0 +1,156 @@
|
||||
use crate::{
|
||||
mode::{ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender},
|
||||
mode_tree::{ModeStoreProvider, ModeStoreVec},
|
||||
queue::GenericTargetedMessagingError,
|
||||
request::{GenericMessage, RequestId},
|
||||
subsystem::ModeTreeHelperState,
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum AssemblyHelperResult {
|
||||
#[default]
|
||||
Idle,
|
||||
TargetKeepingViolation(ComponentId),
|
||||
ModeCommandingDone,
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// The IDs, modes and reply awaition status of all children are tracked in this data
|
||||
/// structure.
|
||||
pub children_mode_store: ModeStoreVec,
|
||||
/// Target mode used for mode commanding.
|
||||
pub target_mode: Option<ModeAndSubmode>,
|
||||
/// Request ID of active mode commanding request.
|
||||
pub active_request_id: Option<RequestId>,
|
||||
pub state: ModeTreeHelperState,
|
||||
}
|
||||
|
||||
pub type DevManagerCommandingHelper = AssemblyCommandingHelper;
|
||||
|
||||
impl AssemblyCommandingHelper {
|
||||
pub fn send_mode_cmd_to_all_children_with_reply_awaition(
|
||||
&mut self,
|
||||
request_id: RequestId,
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
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.active_request_id = Some(request_id);
|
||||
self.state = ModeTreeHelperState::ModeCommanding;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_announce_mode_cmd_to_children(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
recursive: bool,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
let mut request = ModeRequest::AnnounceMode;
|
||||
if recursive {
|
||||
request = ModeRequest::AnnounceModeRecursive;
|
||||
}
|
||||
for child in self.children_mode_store.0.iter() {
|
||||
mode_req_sender.send_mode_request(request_id, child.id(), request)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_mode_child(&mut self, target_id: ComponentId, mode: ModeAndSubmode) {
|
||||
self.children_mode_store.add_component(target_id, mode);
|
||||
}
|
||||
|
||||
pub fn count_number_of_children_with_target_mode(&self) -> Option<usize> {
|
||||
self.target_mode?;
|
||||
let target_mode = self.target_mode.unwrap();
|
||||
let mut children_in_target_mode = 0;
|
||||
for child in self.children_mode_store.0.iter() {
|
||||
if child.mode_and_submode() == target_mode {
|
||||
children_in_target_mode += 1;
|
||||
}
|
||||
}
|
||||
Some(children_in_target_mode)
|
||||
}
|
||||
|
||||
pub fn handle_mode_reply(
|
||||
&mut self,
|
||||
mode_reply: &GenericMessage<ModeReply>,
|
||||
) -> AssemblyHelperResult {
|
||||
if !self
|
||||
.children_mode_store
|
||||
.has_component(mode_reply.sender_id())
|
||||
{
|
||||
return AssemblyHelperResult::Idle;
|
||||
}
|
||||
let mut generic_mode_reply_handler = |mode_and_submode: Option<ModeAndSubmode>| {
|
||||
// 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()
|
||||
&& mode_reply.request_id() == self.active_request_id.unwrap()
|
||||
{
|
||||
handle_awaition = true;
|
||||
}
|
||||
let still_awating_replies = self.children_mode_store.mode_reply_handler(
|
||||
mode_reply.sender_id(),
|
||||
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
|
||||
&& handle_awaition
|
||||
&& !still_awating_replies.unwrap()
|
||||
{
|
||||
self.state = ModeTreeHelperState::TargetKeeping;
|
||||
self.active_request_id = None;
|
||||
return AssemblyHelperResult::ModeCommandingDone;
|
||||
}
|
||||
AssemblyHelperResult::Idle
|
||||
};
|
||||
match mode_reply.message {
|
||||
ModeReply::ModeInfo(mode_and_submode) | ModeReply::ModeReply(mode_and_submode) => {
|
||||
generic_mode_reply_handler(Some(mode_and_submode))
|
||||
}
|
||||
ModeReply::CantReachMode(_result_u16) => generic_mode_reply_handler(None),
|
||||
ModeReply::WrongMode {
|
||||
expected: _,
|
||||
reached,
|
||||
} => generic_mode_reply_handler(Some(reached)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_basic() {}
|
||||
}
|
@ -22,29 +22,32 @@ extern crate downcast_rs;
|
||||
#[cfg(any(feature = "std", test))]
|
||||
extern crate std;
|
||||
|
||||
pub mod action;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod dev_mgmt;
|
||||
pub mod encoding;
|
||||
pub mod event_man;
|
||||
pub mod events;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod executable;
|
||||
pub mod hal;
|
||||
pub mod hk;
|
||||
pub mod mode;
|
||||
#[cfg(feature = "std")]
|
||||
pub mod mode_tree;
|
||||
pub mod params;
|
||||
pub mod pool;
|
||||
pub mod power;
|
||||
pub mod pus;
|
||||
pub mod queue;
|
||||
pub mod request;
|
||||
pub mod res_code;
|
||||
pub mod time;
|
||||
pub mod tmtc;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod scheduling;
|
||||
|
||||
pub mod action;
|
||||
pub mod hk;
|
||||
pub mod mode;
|
||||
pub mod params;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod subsystem;
|
||||
pub mod time;
|
||||
pub mod tmtc;
|
||||
|
||||
pub use spacepackets;
|
||||
|
||||
|
@ -12,7 +12,9 @@ pub use std_mod::*;
|
||||
|
||||
use crate::{
|
||||
queue::GenericTargetedMessagingError,
|
||||
request::{GenericMessage, MessageMetadata, MessageReceiver, MessageReceiverWithId, RequestId},
|
||||
request::{
|
||||
GenericMessage, MessageMetadata, MessageReceiverProvider, MessageReceiverWithId, RequestId,
|
||||
},
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
@ -26,6 +28,9 @@ pub struct ModeAndSubmode {
|
||||
submode: Submode,
|
||||
}
|
||||
|
||||
pub const INVALID_MODE: ModeAndSubmode = ModeAndSubmode::new(u32::MAX, 0);
|
||||
pub const UNKNOWN_MODE: ModeAndSubmode = ModeAndSubmode::new(u32::MAX - 1, 0);
|
||||
|
||||
impl ModeAndSubmode {
|
||||
pub const RAW_LEN: usize = size_of::<Mode>() + size_of::<Submode>();
|
||||
|
||||
@ -111,7 +116,10 @@ impl TargetedModeCommand {
|
||||
pub enum ModeRequest {
|
||||
/// Mode information. Can be used to notify other components of changed modes.
|
||||
ModeInfo(ModeAndSubmode),
|
||||
SetMode(ModeAndSubmode),
|
||||
SetMode {
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
},
|
||||
ReadMode,
|
||||
AnnounceMode,
|
||||
AnnounceModeRecursive,
|
||||
@ -127,6 +135,8 @@ pub struct TargetedModeRequest {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum ModeReply {
|
||||
/// Mode information. Can be used to notify other components of changed modes.
|
||||
ModeInfo(ModeAndSubmode),
|
||||
/// Reply to a mode request to confirm the commanded mode was reached.
|
||||
ModeReply(ModeAndSubmode),
|
||||
// Can not reach the commanded mode. Contains a reason as a [ResultU16].
|
||||
@ -156,7 +166,7 @@ pub trait ModeRequestReceiver {
|
||||
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError>;
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver<ModeRequest>> ModeRequestReceiver
|
||||
impl<R: MessageReceiverProvider<ModeRequest>> ModeRequestReceiver
|
||||
for MessageReceiverWithId<ModeRequest, R>
|
||||
{
|
||||
fn try_recv_mode_request(
|
||||
@ -166,15 +176,12 @@ impl<R: MessageReceiver<ModeRequest>> ModeRequestReceiver
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum ModeError {
|
||||
Messaging(GenericTargetedMessagingError),
|
||||
}
|
||||
|
||||
impl From<GenericTargetedMessagingError> for ModeError {
|
||||
fn from(value: GenericTargetedMessagingError) -> Self {
|
||||
Self::Messaging(value)
|
||||
}
|
||||
#[error("Messaging error: {0}")]
|
||||
Messaging(#[from] GenericTargetedMessagingError),
|
||||
#[error("busy with other mode request")]
|
||||
Busy,
|
||||
}
|
||||
|
||||
pub trait ModeProvider {
|
||||
@ -196,6 +203,7 @@ pub trait ModeRequestHandler: ModeProvider {
|
||||
&mut self,
|
||||
requestor: MessageMetadata,
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
fn announce_mode(&self, requestor_info: Option<MessageMetadata>, recursive: bool);
|
||||
@ -222,9 +230,10 @@ pub trait ModeRequestHandler: ModeProvider {
|
||||
request: GenericMessage<ModeRequest>,
|
||||
) -> Result<(), Self::Error> {
|
||||
match request.message {
|
||||
ModeRequest::SetMode(mode_and_submode) => {
|
||||
self.start_transition(request.requestor_info, mode_and_submode)
|
||||
}
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode,
|
||||
forced,
|
||||
} => self.start_transition(request.requestor_info, mode_and_submode, forced),
|
||||
ModeRequest::ReadMode => self.send_mode_reply(
|
||||
request.requestor_info,
|
||||
ModeReply::ModeReply(self.mode_and_submode()),
|
||||
@ -248,7 +257,9 @@ pub trait ModeReplyReceiver {
|
||||
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError>;
|
||||
}
|
||||
|
||||
impl<R: MessageReceiver<ModeReply>> ModeReplyReceiver for MessageReceiverWithId<ModeReply, R> {
|
||||
impl<R: MessageReceiverProvider<ModeReply>> ModeReplyReceiver
|
||||
for MessageReceiverWithId<ModeReply, R>
|
||||
{
|
||||
fn try_recv_mode_reply(
|
||||
&self,
|
||||
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> {
|
||||
@ -270,12 +281,13 @@ pub trait ModeReplySender {
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod alloc_mod {
|
||||
use crate::request::{
|
||||
MessageSender, MessageSenderAndReceiver, MessageSenderMap, RequestAndReplySenderAndReceiver,
|
||||
MessageSenderAndReceiver, MessageSenderMap, MessageSenderProvider,
|
||||
MessageSenderStoreProvider, RequestAndReplySenderAndReceiver,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
impl<S: MessageSender<ModeReply>> MessageSenderMap<ModeReply, S> {
|
||||
impl<S: MessageSenderProvider<ModeReply>> MessageSenderMap<ModeReply, S> {
|
||||
pub fn send_mode_reply(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
@ -290,8 +302,13 @@ pub mod alloc_mod {
|
||||
}
|
||||
}
|
||||
|
||||
impl<FROM, S: MessageSender<ModeReply>, R: MessageReceiver<FROM>> ModeReplySender
|
||||
for MessageSenderAndReceiver<ModeReply, FROM, S, R>
|
||||
impl<
|
||||
From,
|
||||
Sender: MessageSenderProvider<ModeReply>,
|
||||
Receiver: MessageReceiverProvider<From>,
|
||||
SenderStore: MessageSenderStoreProvider<ModeReply, Sender>,
|
||||
> ModeReplySender
|
||||
for MessageSenderAndReceiver<ModeReply, From, Sender, Receiver, SenderStore>
|
||||
{
|
||||
fn local_channel_id(&self) -> ComponentId {
|
||||
self.local_channel_id_generic()
|
||||
@ -302,7 +319,7 @@ pub mod alloc_mod {
|
||||
requestor_info: MessageMetadata,
|
||||
request: ModeReply,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.message_sender_map.send_mode_reply(
|
||||
self.message_sender_store.send_message(
|
||||
MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()),
|
||||
requestor_info.sender_id(),
|
||||
request,
|
||||
@ -310,8 +327,13 @@ pub mod alloc_mod {
|
||||
}
|
||||
}
|
||||
|
||||
impl<TO, S: MessageSender<TO>, R: MessageReceiver<ModeReply>> ModeReplyReceiver
|
||||
for MessageSenderAndReceiver<TO, ModeReply, S, R>
|
||||
impl<
|
||||
To,
|
||||
Sender: MessageSenderProvider<To>,
|
||||
Receiver: MessageReceiverProvider<ModeReply>,
|
||||
SenderStore: MessageSenderStoreProvider<To, Sender>,
|
||||
> ModeReplyReceiver
|
||||
for MessageSenderAndReceiver<To, ModeReply, Sender, Receiver, SenderStore>
|
||||
{
|
||||
fn try_recv_mode_reply(
|
||||
&self,
|
||||
@ -321,26 +343,51 @@ pub mod alloc_mod {
|
||||
}
|
||||
|
||||
impl<
|
||||
REQUEST,
|
||||
S0: MessageSender<REQUEST>,
|
||||
R0: MessageReceiver<ModeReply>,
|
||||
S1: MessageSender<ModeReply>,
|
||||
R1: MessageReceiver<REQUEST>,
|
||||
> RequestAndReplySenderAndReceiver<REQUEST, ModeReply, S0, R0, S1, R1>
|
||||
Request,
|
||||
ReqSender: MessageSenderProvider<Request>,
|
||||
ReqReceiver: MessageReceiverProvider<Request>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
|
||||
Reply,
|
||||
ReplySender: MessageSenderProvider<Reply>,
|
||||
ReplyReceiver: MessageReceiverProvider<Reply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
|
||||
>
|
||||
RequestAndReplySenderAndReceiver<
|
||||
Request,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
Reply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
pub fn add_reply_target(&mut self, target_id: ComponentId, reply_sender: S1) {
|
||||
self.reply_sender_map
|
||||
pub fn add_reply_target(&mut self, target_id: ComponentId, reply_sender: ReplySender) {
|
||||
self.reply_sender_store
|
||||
.add_message_target(target_id, reply_sender)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
REQUEST,
|
||||
S0: MessageSender<REQUEST>,
|
||||
R0: MessageReceiver<ModeReply>,
|
||||
S1: MessageSender<ModeReply>,
|
||||
R1: MessageReceiver<REQUEST>,
|
||||
> ModeReplySender for RequestAndReplySenderAndReceiver<REQUEST, ModeReply, S0, R0, S1, R1>
|
||||
Request,
|
||||
ReqSender: MessageSenderProvider<Request>,
|
||||
ReqReceiver: MessageReceiverProvider<Request>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
|
||||
ReplySender: MessageSenderProvider<ModeReply>,
|
||||
ReplyReceiver: MessageReceiverProvider<ModeReply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<ModeReply, ReplySender>,
|
||||
> ModeReplySender
|
||||
for RequestAndReplySenderAndReceiver<
|
||||
Request,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
ModeReply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
fn local_channel_id(&self) -> ComponentId {
|
||||
self.local_channel_id_generic()
|
||||
@ -349,24 +396,35 @@ pub mod alloc_mod {
|
||||
fn send_mode_reply(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
request: ModeReply,
|
||||
reply: ModeReply,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.reply_sender_map.send_mode_reply(
|
||||
self.reply_sender_store.send_message(
|
||||
MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()),
|
||||
requestor_info.sender_id(),
|
||||
request,
|
||||
reply,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
REQUEST,
|
||||
S0: MessageSender<REQUEST>,
|
||||
R0: MessageReceiver<ModeReply>,
|
||||
S1: MessageSender<ModeReply>,
|
||||
R1: MessageReceiver<REQUEST>,
|
||||
Request,
|
||||
ReqSender: MessageSenderProvider<Request>,
|
||||
ReqReceiver: MessageReceiverProvider<Request>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
|
||||
ReplySender: MessageSenderProvider<ModeReply>,
|
||||
ReplyReceiver: MessageReceiverProvider<ModeReply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<ModeReply, ReplySender>,
|
||||
> ModeReplyReceiver
|
||||
for RequestAndReplySenderAndReceiver<REQUEST, ModeReply, S0, R0, S1, R1>
|
||||
for RequestAndReplySenderAndReceiver<
|
||||
Request,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
ModeReply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
fn try_recv_mode_reply(
|
||||
&self,
|
||||
@ -376,11 +434,14 @@ pub mod alloc_mod {
|
||||
}
|
||||
|
||||
/// Helper type definition for a mode handler which can handle mode requests.
|
||||
pub type ModeRequestHandlerInterface<S, R> =
|
||||
MessageSenderAndReceiver<ModeReply, ModeRequest, S, R>;
|
||||
pub type ModeRequestHandlerInterface<Sender, Receiver, ReplySenderStore> =
|
||||
MessageSenderAndReceiver<ModeReply, ModeRequest, Sender, Receiver, ReplySenderStore>;
|
||||
|
||||
impl<S: MessageSender<ModeReply>, R: MessageReceiver<ModeRequest>>
|
||||
ModeRequestHandlerInterface<S, R>
|
||||
impl<
|
||||
Sender: MessageSenderProvider<ModeReply>,
|
||||
Receiver: MessageReceiverProvider<ModeRequest>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<ModeReply, Sender>,
|
||||
> ModeRequestHandlerInterface<Sender, Receiver, ReplySenderStore>
|
||||
{
|
||||
pub fn try_recv_mode_request(
|
||||
&self,
|
||||
@ -403,9 +464,15 @@ pub mod alloc_mod {
|
||||
|
||||
/// Helper type defintion for a mode handler object which can send mode requests and receive
|
||||
/// mode replies.
|
||||
pub type ModeRequestorInterface<S, R> = MessageSenderAndReceiver<ModeRequest, ModeReply, S, R>;
|
||||
pub type ModeRequestorInterface<Sender, Receiver, RequestSenderStore> =
|
||||
MessageSenderAndReceiver<ModeRequest, ModeReply, Sender, Receiver, RequestSenderStore>;
|
||||
|
||||
impl<S: MessageSender<ModeRequest>, R: MessageReceiver<ModeReply>> ModeRequestorInterface<S, R> {
|
||||
impl<
|
||||
Sender: MessageSenderProvider<ModeRequest>,
|
||||
Receiver: MessageReceiverProvider<ModeReply>,
|
||||
RequestSenderStore: MessageSenderStoreProvider<ModeRequest, Sender>,
|
||||
> ModeRequestorInterface<Sender, Receiver, RequestSenderStore>
|
||||
{
|
||||
pub fn try_recv_mode_reply(
|
||||
&self,
|
||||
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> {
|
||||
@ -424,10 +491,25 @@ pub mod alloc_mod {
|
||||
|
||||
/// Helper type defintion for a mode handler object which can both send mode requests and
|
||||
/// process mode requests.
|
||||
pub type ModeInterface<S0, R0, S1, R1> =
|
||||
RequestAndReplySenderAndReceiver<ModeRequest, ModeReply, S0, R0, S1, R1>;
|
||||
pub type ModeInterface<
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
> = RequestAndReplySenderAndReceiver<
|
||||
ModeRequest,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
ModeReply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>;
|
||||
|
||||
impl<S: MessageSender<ModeRequest>> MessageSenderMap<ModeRequest, S> {
|
||||
impl<S: MessageSenderProvider<ModeRequest>> MessageSenderMap<ModeRequest, S> {
|
||||
pub fn send_mode_request(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
@ -442,25 +524,13 @@ pub mod alloc_mod {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<S: MessageSender<ModeRequest>> ModeRequestSender for MessageSenderMapWithId<ModeRequest, S> {
|
||||
fn local_channel_id(&self) -> ComponentId {
|
||||
self.local_channel_id
|
||||
}
|
||||
|
||||
fn send_mode_request(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
target_id: ComponentId,
|
||||
request: ModeRequest,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.send_message(request_id, target_id, request)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<TO, S: MessageSender<TO>, R: MessageReceiver<ModeRequest>> ModeRequestReceiver
|
||||
for MessageSenderAndReceiver<TO, ModeRequest, S, R>
|
||||
impl<
|
||||
To,
|
||||
Sender: MessageSenderProvider<To>,
|
||||
Receiver: MessageReceiverProvider<ModeRequest>,
|
||||
SenderStore: MessageSenderStoreProvider<To, Sender>,
|
||||
> ModeRequestReceiver
|
||||
for MessageSenderAndReceiver<To, ModeRequest, Sender, Receiver, SenderStore>
|
||||
{
|
||||
fn try_recv_mode_request(
|
||||
&self,
|
||||
@ -469,8 +539,13 @@ pub mod alloc_mod {
|
||||
}
|
||||
}
|
||||
|
||||
impl<FROM, S: MessageSender<ModeRequest>, R: MessageReceiver<FROM>> ModeRequestSender
|
||||
for MessageSenderAndReceiver<ModeRequest, FROM, S, R>
|
||||
impl<
|
||||
From,
|
||||
Sender: MessageSenderProvider<ModeRequest>,
|
||||
Receiver: MessageReceiverProvider<From>,
|
||||
SenderStore: MessageSenderStoreProvider<ModeRequest, Sender>,
|
||||
> ModeRequestSender
|
||||
for MessageSenderAndReceiver<ModeRequest, From, Sender, Receiver, SenderStore>
|
||||
{
|
||||
fn local_channel_id(&self) -> ComponentId {
|
||||
self.local_channel_id_generic()
|
||||
@ -482,7 +557,7 @@ pub mod alloc_mod {
|
||||
target_id: ComponentId,
|
||||
request: ModeRequest,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.message_sender_map.send_mode_request(
|
||||
self.message_sender_store.send_message(
|
||||
MessageMetadata::new(request_id, self.local_channel_id()),
|
||||
target_id,
|
||||
request,
|
||||
@ -491,27 +566,50 @@ pub mod alloc_mod {
|
||||
}
|
||||
|
||||
impl<
|
||||
REPLY,
|
||||
S0: MessageSender<ModeRequest>,
|
||||
R0: MessageReceiver<REPLY>,
|
||||
S1: MessageSender<REPLY>,
|
||||
R1: MessageReceiver<ModeRequest>,
|
||||
> RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
|
||||
ReqSender: MessageSenderProvider<ModeRequest>,
|
||||
ReqReceiver: MessageReceiverProvider<ModeRequest>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<ModeRequest, ReqSender>,
|
||||
Reply,
|
||||
ReplySender: MessageSenderProvider<Reply>,
|
||||
ReplyReceiver: MessageReceiverProvider<Reply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
|
||||
>
|
||||
RequestAndReplySenderAndReceiver<
|
||||
ModeRequest,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
Reply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: S0) {
|
||||
self.request_sender_map
|
||||
pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: ReqSender) {
|
||||
self.request_sender_store
|
||||
.add_message_target(target_id, request_sender)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
REPLY,
|
||||
S0: MessageSender<ModeRequest>,
|
||||
R0: MessageReceiver<REPLY>,
|
||||
S1: MessageSender<REPLY>,
|
||||
R1: MessageReceiver<ModeRequest>,
|
||||
ReqSender: MessageSenderProvider<ModeRequest>,
|
||||
ReqReceiver: MessageReceiverProvider<ModeRequest>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<ModeRequest, ReqSender>,
|
||||
Reply,
|
||||
ReplySender: MessageSenderProvider<Reply>,
|
||||
ReplyReceiver: MessageReceiverProvider<Reply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
|
||||
> ModeRequestSender
|
||||
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
|
||||
for RequestAndReplySenderAndReceiver<
|
||||
ModeRequest,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
Reply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
fn local_channel_id(&self) -> ComponentId {
|
||||
self.local_channel_id_generic()
|
||||
@ -523,7 +621,7 @@ pub mod alloc_mod {
|
||||
target_id: ComponentId,
|
||||
request: ModeRequest,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.request_sender_map.send_mode_request(
|
||||
self.request_sender_store.send_message(
|
||||
MessageMetadata::new(request_id, self.local_channel_id()),
|
||||
target_id,
|
||||
request,
|
||||
@ -532,13 +630,24 @@ pub mod alloc_mod {
|
||||
}
|
||||
|
||||
impl<
|
||||
REPLY,
|
||||
S0: MessageSender<ModeRequest>,
|
||||
R0: MessageReceiver<REPLY>,
|
||||
S1: MessageSender<REPLY>,
|
||||
R1: MessageReceiver<ModeRequest>,
|
||||
ReqSender: MessageSenderProvider<ModeRequest>,
|
||||
ReqReceiver: MessageReceiverProvider<ModeRequest>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<ModeRequest, ReqSender>,
|
||||
Reply,
|
||||
ReplySender: MessageSenderProvider<Reply>,
|
||||
ReplyReceiver: MessageReceiverProvider<Reply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
|
||||
> ModeRequestReceiver
|
||||
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
|
||||
for RequestAndReplySenderAndReceiver<
|
||||
ModeRequest,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
Reply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
fn try_recv_mode_request(
|
||||
&self,
|
||||
@ -552,37 +661,57 @@ pub mod alloc_mod {
|
||||
pub mod std_mod {
|
||||
use std::sync::mpsc;
|
||||
|
||||
use crate::request::{MessageSenderList, OneMessageSender};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub type ModeRequestHandlerMpsc = ModeRequestHandlerInterface<
|
||||
mpsc::Sender<GenericMessage<ModeReply>>,
|
||||
mpsc::Receiver<GenericMessage<ModeRequest>>,
|
||||
MessageSenderList<ModeReply, mpsc::Sender<GenericMessage<ModeReply>>>,
|
||||
>;
|
||||
pub type ModeRequestHandlerMpscBounded = ModeRequestHandlerInterface<
|
||||
mpsc::SyncSender<GenericMessage<ModeReply>>,
|
||||
mpsc::Receiver<GenericMessage<ModeRequest>>,
|
||||
MessageSenderList<ModeReply, mpsc::SyncSender<GenericMessage<ModeReply>>>,
|
||||
>;
|
||||
|
||||
pub type ModeRequestorMpsc = ModeRequestorInterface<
|
||||
pub type ModeRequestorOneChildMpsc = ModeRequestorInterface<
|
||||
mpsc::Sender<GenericMessage<ModeRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
OneMessageSender<ModeRequest, mpsc::Sender<GenericMessage<ModeRequest>>>,
|
||||
>;
|
||||
pub type ModeRequestorBoundedMpsc = ModeRequestorInterface<
|
||||
pub type ModeRequestorOneChildBoundedMpsc = ModeRequestorInterface<
|
||||
mpsc::SyncSender<GenericMessage<ModeRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
OneMessageSender<ModeRequest, mpsc::SyncSender<GenericMessage<ModeRequest>>>,
|
||||
>;
|
||||
pub type ModeRequestorChildListMpsc = ModeRequestorInterface<
|
||||
mpsc::Sender<GenericMessage<ModeRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
MessageSenderList<ModeRequest, mpsc::Sender<GenericMessage<ModeRequest>>>,
|
||||
>;
|
||||
pub type ModeRequestorChildListBoundedMpsc = ModeRequestorInterface<
|
||||
mpsc::SyncSender<GenericMessage<ModeRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
MessageSenderList<ModeRequest, mpsc::SyncSender<GenericMessage<ModeRequest>>>,
|
||||
>;
|
||||
|
||||
pub type ModeRequestorAndHandlerMpsc = ModeInterface<
|
||||
mpsc::Sender<GenericMessage<ModeRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
mpsc::Sender<GenericMessage<ModeReply>>,
|
||||
mpsc::Receiver<GenericMessage<ModeRequest>>,
|
||||
MessageSenderList<ModeRequest, mpsc::Sender<GenericMessage<ModeRequest>>>,
|
||||
mpsc::Sender<GenericMessage<ModeReply>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
MessageSenderList<ModeReply, mpsc::Sender<GenericMessage<ModeReply>>>,
|
||||
>;
|
||||
pub type ModeRequestorAndHandlerMpscBounded = ModeInterface<
|
||||
mpsc::SyncSender<GenericMessage<ModeRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
mpsc::SyncSender<GenericMessage<ModeReply>>,
|
||||
mpsc::Receiver<GenericMessage<ModeRequest>>,
|
||||
MessageSenderList<ModeRequest, mpsc::SyncSender<GenericMessage<ModeRequest>>>,
|
||||
mpsc::SyncSender<GenericMessage<ModeReply>>,
|
||||
mpsc::Receiver<GenericMessage<ModeReply>>,
|
||||
MessageSenderList<ModeReply, mpsc::SyncSender<GenericMessage<ModeReply>>>,
|
||||
>;
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,57 @@ use alloc::vec::Vec;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
use crate::{
|
||||
mode::{Mode, ModeAndSubmode, Submode},
|
||||
mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, Submode},
|
||||
request::MessageSenderProvider,
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub use alloc_mod::*;
|
||||
|
||||
/// Common trait for node modes which can have mode parents or mode children.
|
||||
pub trait ModeNode {
|
||||
fn id(&self) -> ComponentId;
|
||||
}
|
||||
/// Trait which denotes that an object is a parent in a mode tree.
|
||||
///
|
||||
/// A mode parent is capable of sending mode requests to child objects and has a unique component
|
||||
/// ID.
|
||||
pub trait ModeParent: ModeNode {
|
||||
type Sender: MessageSenderProvider<ModeRequest>;
|
||||
|
||||
fn add_mode_child(&mut self, id: ComponentId, request_sender: Self::Sender);
|
||||
}
|
||||
|
||||
/// Trait which denotes that an object is a child in a mode tree.
|
||||
///
|
||||
/// A child is capable of sending mode replies to parent objects and has a unique component ID.
|
||||
pub trait ModeChild: ModeNode {
|
||||
type Sender: MessageSenderProvider<ModeReply>;
|
||||
|
||||
fn add_mode_parent(&mut self, id: ComponentId, reply_sender: Self::Sender);
|
||||
}
|
||||
|
||||
/// Utility method which connects a mode tree parent object to a child object by calling
|
||||
/// [ModeParent::add_mode_child] on the [parent][ModeParent] and calling
|
||||
/// [ModeChild::add_mode_parent] on the [child][ModeChild].
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `parent` - The parent object which implements [ModeParent].
|
||||
/// * `request_sender` - Sender object to send mode requests to the child.
|
||||
/// * `child` - The child object which implements [ModeChild].
|
||||
/// * `reply_sender` - Sender object to send mode replies to the parent.
|
||||
pub fn connect_mode_nodes<ReqSender, ReplySender>(
|
||||
parent: &mut impl ModeParent<Sender = ReqSender>,
|
||||
request_sender: ReqSender,
|
||||
child: &mut impl ModeChild<Sender = ReplySender>,
|
||||
reply_sender: ReplySender,
|
||||
) {
|
||||
parent.add_mode_child(child.id(), request_sender);
|
||||
child.add_mode_parent(parent.id(), reply_sender);
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum TableEntryType {
|
||||
/// Target table containing information of the expected children modes for given mode.
|
||||
@ -15,23 +62,508 @@ pub enum TableEntryType {
|
||||
Sequence,
|
||||
}
|
||||
|
||||
pub struct ModeTableEntry {
|
||||
/// Common fields required for both target and sequence table entries.
|
||||
///
|
||||
/// The most important parameters here are the target ID which this entry belongs to, and the mode
|
||||
/// and submode the entry either will be commanded to for sequence table entries or which will be
|
||||
/// monitored for target table entries.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ModeTableEntryCommon {
|
||||
/// Name of respective table entry.
|
||||
pub name: &'static str,
|
||||
/// Target channel ID.
|
||||
pub channel_id: ComponentId,
|
||||
/// Target component ID.
|
||||
pub target_id: ComponentId,
|
||||
/// Has a different meaning depending on whether this is a sequence table or a target table.
|
||||
///
|
||||
/// - For sequence tables, this denotes the mode which will be commanded
|
||||
/// - For target tables, this is the mode which the target children should have and which
|
||||
/// might be monitored depending on configuration.
|
||||
pub mode_submode: ModeAndSubmode,
|
||||
/// This mask allows to specify multiple allowed submodes for a given mode.
|
||||
pub allowed_submode_mask: Option<Submode>,
|
||||
}
|
||||
|
||||
impl ModeTableEntryCommon {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode) {
|
||||
self.allowed_submode_mask = Some(mask);
|
||||
}
|
||||
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode> {
|
||||
self.allowed_submode_mask
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry for the target tables.
|
||||
#[derive(Debug)]
|
||||
pub struct TargetTableEntry {
|
||||
pub common: ModeTableEntryCommon,
|
||||
pub monitor_state: bool,
|
||||
}
|
||||
|
||||
impl TargetTableEntry {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
target_id: ComponentId,
|
||||
mode_submode: ModeAndSubmode,
|
||||
allowed_submode_mask: Option<Submode>,
|
||||
) -> Self {
|
||||
Self {
|
||||
common: ModeTableEntryCommon {
|
||||
name,
|
||||
target_id,
|
||||
mode_submode,
|
||||
allowed_submode_mask,
|
||||
},
|
||||
monitor_state: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_precise_submode(
|
||||
name: &'static str,
|
||||
target_id: ComponentId,
|
||||
mode_submode: ModeAndSubmode,
|
||||
) -> Self {
|
||||
Self {
|
||||
common: ModeTableEntryCommon {
|
||||
name,
|
||||
target_id,
|
||||
mode_submode,
|
||||
allowed_submode_mask: None,
|
||||
},
|
||||
monitor_state: true,
|
||||
}
|
||||
}
|
||||
|
||||
delegate::delegate! {
|
||||
to self.common {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode);
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An entry for the sequence tables.
|
||||
///
|
||||
/// The [Self::check_success] field specifies that a mode sequence executor should check that the
|
||||
/// target mode was actually reached before executing the next sequence.
|
||||
#[derive(Debug)]
|
||||
pub struct SequenceTableEntry {
|
||||
pub common: ModeTableEntryCommon,
|
||||
pub check_success: bool,
|
||||
}
|
||||
|
||||
pub struct ModeTableMapValue {
|
||||
/// Name for a given mode table entry.
|
||||
pub name: &'static str,
|
||||
pub entries: Vec<ModeTableEntry>,
|
||||
impl SequenceTableEntry {
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
target_id: ComponentId,
|
||||
mode_submode: ModeAndSubmode,
|
||||
check_success: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
common: ModeTableEntryCommon {
|
||||
name,
|
||||
target_id,
|
||||
mode_submode,
|
||||
allowed_submode_mask: None,
|
||||
},
|
||||
check_success,
|
||||
}
|
||||
}
|
||||
|
||||
delegate::delegate! {
|
||||
to self.common {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode);
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ModeTable = HashMap<Mode, ModeTableMapValue>;
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("target {0} not in mode store")]
|
||||
pub struct TargetNotInModeStoreError(pub ComponentId);
|
||||
|
||||
/// Mode store value type.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ModeStoreValue {
|
||||
/// ID of the mode component.
|
||||
id: ComponentId,
|
||||
/// Current mode and submode of the component.
|
||||
pub mode_and_submode: ModeAndSubmode,
|
||||
/// State information to track whether a reply should be awaited for the mode component.
|
||||
pub awaiting_reply: bool,
|
||||
}
|
||||
|
||||
impl ModeStoreValue {
|
||||
pub fn new(id: ComponentId, mode_and_submode: ModeAndSubmode) -> Self {
|
||||
Self {
|
||||
id,
|
||||
mode_and_submode,
|
||||
awaiting_reply: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> ComponentId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn mode_and_submode(&self) -> ModeAndSubmode {
|
||||
self.mode_and_submode
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ModeStoreProvider {
|
||||
fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode);
|
||||
|
||||
fn has_component(&self, target_id: ComponentId) -> bool;
|
||||
|
||||
fn get(&self, target_id: ComponentId) -> Option<&ModeStoreValue>;
|
||||
|
||||
fn get_mut(&mut self, target_id: ComponentId) -> Option<&mut ModeStoreValue>;
|
||||
|
||||
/// Generic handler for mode replies received from child components.
|
||||
///
|
||||
/// Implementation should clear the awaition flag if the `handle_reply_awaition` argument is
|
||||
/// true and returns whether any children are still awaiting replies. If the flag is not set
|
||||
fn mode_reply_handler_with_reply_awaition(
|
||||
&mut self,
|
||||
sender_id: ComponentId,
|
||||
reported_mode_and_submode: Option<ModeAndSubmode>,
|
||||
) -> bool {
|
||||
self.mode_reply_handler(sender_id, reported_mode_and_submode, true)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn mode_reply_handler_without_reply_awaition(
|
||||
&mut self,
|
||||
sender_id: ComponentId,
|
||||
reported_mode_and_submode: Option<ModeAndSubmode>,
|
||||
) {
|
||||
self.mode_reply_handler(sender_id, reported_mode_and_submode, false);
|
||||
}
|
||||
|
||||
fn mode_reply_handler(
|
||||
&mut self,
|
||||
sender_id: ComponentId,
|
||||
reported_mode_and_submode: Option<ModeAndSubmode>,
|
||||
with_reply_awaition: bool,
|
||||
) -> Option<bool>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod alloc_mod {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TargetTablesMapValue {
|
||||
/// Name for a given mode table entry.
|
||||
pub name: &'static str,
|
||||
/// Optional fallback mode if the target mode can not be kept.
|
||||
pub fallback_mode: Option<Mode>,
|
||||
/// These are the rows of the a target table.
|
||||
pub entries: Vec<TargetTableEntry>,
|
||||
}
|
||||
|
||||
impl TargetTablesMapValue {
|
||||
pub fn new(name: &'static str, fallback_mode: Option<Mode>) -> Self {
|
||||
Self {
|
||||
name,
|
||||
fallback_mode,
|
||||
entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, entry: TargetTableEntry) {
|
||||
self.entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// One sequence of a [SequenceTablesMapValue] in a [SequenceModeTables].
|
||||
///
|
||||
/// It contains all mode requests which need to be executed for a sequence step and it also
|
||||
/// associates a [Self::name] with the sequence.
|
||||
#[derive(Debug)]
|
||||
pub struct SequenceTableMapTable {
|
||||
/// Name for a given mode sequence.
|
||||
pub name: &'static str,
|
||||
/// These are the rows of the a sequence table.
|
||||
pub entries: Vec<SequenceTableEntry>,
|
||||
}
|
||||
|
||||
impl SequenceTableMapTable {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, entry: SequenceTableEntry) {
|
||||
self.entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// A sequence table entry.
|
||||
///
|
||||
/// This is simply a list of [SequenceTableMapTable]s which also associates a [Self::name]
|
||||
/// with the sequence. The order of sub-tables in the list also specifies the execution order
|
||||
/// in the mode sequence.
|
||||
#[derive(Debug)]
|
||||
pub struct SequenceTablesMapValue {
|
||||
/// Name for a given mode sequence.
|
||||
pub name: &'static str,
|
||||
/// Each sequence can consists of multiple sequences that are executed consecutively.
|
||||
pub entries: Vec<SequenceTableMapTable>,
|
||||
}
|
||||
|
||||
impl SequenceTablesMapValue {
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
name,
|
||||
entries: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sequence_table(&mut self, entry: SequenceTableMapTable) {
|
||||
self.entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TargetModeTables(pub HashMap<Mode, TargetTablesMapValue>);
|
||||
|
||||
/// This is the core data structure used to store mode sequence tables.
|
||||
///
|
||||
/// A mode sequence table specifies which commands have to be sent in which order
|
||||
/// to reach a certain [Mode]. Therefore, it simply maps a [Mode] to a [SequenceTablesMapValue].
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SequenceModeTables(pub HashMap<Mode, SequenceTablesMapValue>);
|
||||
|
||||
/// Mode store which tracks the [mode information][ModeStoreValue] inside a [Vec]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ModeStoreVec(pub alloc::vec::Vec<ModeStoreValue>);
|
||||
|
||||
/// Mode store which tracks the mode information inside a [hashbrown::HashMap]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ModeStoreMap(pub hashbrown::HashMap<ComponentId, ModeStoreValue>);
|
||||
|
||||
impl ModeStoreProvider for ModeStoreVec {
|
||||
fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) {
|
||||
self.0.push(ModeStoreValue::new(target_id, mode));
|
||||
}
|
||||
|
||||
fn has_component(&self, target_id: ComponentId) -> bool {
|
||||
self.0.iter().any(|val| val.id == target_id)
|
||||
}
|
||||
|
||||
fn get(&self, target_id: ComponentId) -> Option<&ModeStoreValue> {
|
||||
self.0.iter().find(|val| val.id == target_id)
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, target_id: ComponentId) -> Option<&mut ModeStoreValue> {
|
||||
self.0.iter_mut().find(|val| val.id == target_id)
|
||||
}
|
||||
|
||||
fn mode_reply_handler(
|
||||
&mut self,
|
||||
sender_id: ComponentId,
|
||||
reported_mode_and_submode: Option<ModeAndSubmode>,
|
||||
handle_reply_awaition: bool,
|
||||
) -> Option<bool> {
|
||||
let mut still_awating_replies = None;
|
||||
if handle_reply_awaition {
|
||||
still_awating_replies = Some(false);
|
||||
}
|
||||
self.0.iter_mut().for_each(|val| {
|
||||
if val.id() == sender_id {
|
||||
if let Some(mode_and_submode) = reported_mode_and_submode {
|
||||
val.mode_and_submode = mode_and_submode;
|
||||
}
|
||||
if handle_reply_awaition {
|
||||
val.awaiting_reply = false;
|
||||
}
|
||||
}
|
||||
if handle_reply_awaition && val.awaiting_reply {
|
||||
still_awating_replies = Some(true);
|
||||
}
|
||||
});
|
||||
still_awating_replies
|
||||
}
|
||||
}
|
||||
|
||||
impl ModeStoreProvider for ModeStoreMap {
|
||||
fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) {
|
||||
self.0
|
||||
.insert(target_id, ModeStoreValue::new(target_id, mode));
|
||||
}
|
||||
|
||||
fn has_component(&self, target_id: ComponentId) -> bool {
|
||||
self.0.contains_key(&target_id)
|
||||
}
|
||||
|
||||
fn get(&self, target_id: ComponentId) -> Option<&ModeStoreValue> {
|
||||
self.0.get(&target_id)
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, target_id: ComponentId) -> Option<&mut ModeStoreValue> {
|
||||
self.0.get_mut(&target_id)
|
||||
}
|
||||
|
||||
fn mode_reply_handler(
|
||||
&mut self,
|
||||
sender_id: ComponentId,
|
||||
reported_mode_and_submode: Option<ModeAndSubmode>,
|
||||
handle_reply_awaition: bool,
|
||||
) -> Option<bool> {
|
||||
let mut still_awating_replies = None;
|
||||
if handle_reply_awaition {
|
||||
still_awating_replies = Some(false);
|
||||
}
|
||||
for val in self.0.values_mut() {
|
||||
if val.id() == sender_id {
|
||||
if let Some(mode_and_submode) = reported_mode_and_submode {
|
||||
val.mode_and_submode = mode_and_submode;
|
||||
}
|
||||
if handle_reply_awaition {
|
||||
val.awaiting_reply = false;
|
||||
}
|
||||
}
|
||||
if handle_reply_awaition && val.awaiting_reply {
|
||||
still_awating_replies = Some(true);
|
||||
}
|
||||
}
|
||||
still_awating_replies
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn generic_test(mode_store: &mut impl ModeStoreProvider) {
|
||||
mode_store.add_component(1, ModeAndSubmode::new(0, 0));
|
||||
mode_store.add_component(2, ModeAndSubmode::new(1, 0));
|
||||
assert!(mode_store.has_component(1));
|
||||
assert!(mode_store.has_component(2));
|
||||
assert_eq!(
|
||||
mode_store.get(1).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(0, 0)
|
||||
);
|
||||
assert!(!mode_store.get(1).unwrap().awaiting_reply);
|
||||
assert!(!mode_store.get(2).unwrap().awaiting_reply);
|
||||
assert_eq!(mode_store.get(1).unwrap().id, 1);
|
||||
assert_eq!(mode_store.get(2).unwrap().id, 2);
|
||||
assert!(mode_store.get(3).is_none());
|
||||
assert!(mode_store.get_mut(3).is_none());
|
||||
}
|
||||
|
||||
fn generic_reply_handling_with_reply_awaition(mode_store: &mut impl ModeStoreProvider) {
|
||||
mode_store.add_component(1, ModeAndSubmode::new(0, 0));
|
||||
mode_store.add_component(2, ModeAndSubmode::new(1, 0));
|
||||
mode_store.get_mut(1).unwrap().awaiting_reply = true;
|
||||
mode_store.get_mut(2).unwrap().awaiting_reply = true;
|
||||
let mut reply_awation_pending =
|
||||
mode_store.mode_reply_handler_with_reply_awaition(1, Some(ModeAndSubmode::new(2, 0)));
|
||||
assert!(reply_awation_pending);
|
||||
reply_awation_pending = mode_store.mode_reply_handler_with_reply_awaition(2, None);
|
||||
assert!(!reply_awation_pending);
|
||||
assert!(!mode_store.get(1).unwrap().awaiting_reply);
|
||||
assert!(!mode_store.get(2).unwrap().awaiting_reply);
|
||||
assert_eq!(
|
||||
mode_store.get(1).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(2, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
mode_store.get(2).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(1, 0)
|
||||
);
|
||||
}
|
||||
|
||||
fn generic_reply_handling_test_no_reply_awaition(mode_store: &mut impl ModeStoreProvider) {
|
||||
mode_store.add_component(1, ModeAndSubmode::new(0, 0));
|
||||
mode_store.add_component(2, ModeAndSubmode::new(1, 0));
|
||||
mode_store.get_mut(1).unwrap().awaiting_reply = true;
|
||||
mode_store.get_mut(2).unwrap().awaiting_reply = true;
|
||||
mode_store.mode_reply_handler_without_reply_awaition(1, Some(ModeAndSubmode::new(2, 0)));
|
||||
mode_store.mode_reply_handler_without_reply_awaition(2, None);
|
||||
assert!(mode_store.get(1).unwrap().awaiting_reply);
|
||||
assert!(mode_store.get(2).unwrap().awaiting_reply);
|
||||
assert_eq!(
|
||||
mode_store.get(1).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(2, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
mode_store.get(2).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(1, 0)
|
||||
);
|
||||
}
|
||||
|
||||
fn generic_reply_handling_with_reply_awaition_2(mode_store: &mut impl ModeStoreProvider) {
|
||||
mode_store.add_component(1, ModeAndSubmode::new(0, 0));
|
||||
mode_store.add_component(2, ModeAndSubmode::new(1, 0));
|
||||
mode_store.get_mut(1).unwrap().awaiting_reply = true;
|
||||
mode_store.get_mut(2).unwrap().awaiting_reply = true;
|
||||
let mut reply_awation_pending =
|
||||
mode_store.mode_reply_handler(1, Some(ModeAndSubmode::new(2, 0)), true);
|
||||
assert!(reply_awation_pending.unwrap());
|
||||
reply_awation_pending = mode_store.mode_reply_handler(2, None, true);
|
||||
assert!(!reply_awation_pending.unwrap());
|
||||
assert!(!mode_store.get(1).unwrap().awaiting_reply);
|
||||
assert!(!mode_store.get(2).unwrap().awaiting_reply);
|
||||
assert_eq!(
|
||||
mode_store.get(1).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(2, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
mode_store.get(2).unwrap().mode_and_submode(),
|
||||
ModeAndSubmode::new(1, 0)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec_mode_store() {
|
||||
let mut mode_store = ModeStoreVec::default();
|
||||
generic_test(&mut mode_store);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_map_mode_store() {
|
||||
let mut mode_store = ModeStoreMap::default();
|
||||
generic_test(&mut mode_store);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_reply_handler_vec_with_reply_awaition() {
|
||||
let mut mode_store = ModeStoreVec::default();
|
||||
generic_reply_handling_with_reply_awaition(&mut mode_store);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_reply_handler_vec_with_reply_awaition_2() {
|
||||
let mut mode_store = ModeStoreVec::default();
|
||||
generic_reply_handling_with_reply_awaition_2(&mut mode_store);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_reply_handler_map_with_reply_awaition() {
|
||||
let mut mode_store = ModeStoreMap::default();
|
||||
generic_reply_handling_with_reply_awaition(&mut mode_store);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_reply_handler_map_with_reply_awaition_2() {
|
||||
let mut mode_store = ModeStoreMap::default();
|
||||
generic_reply_handling_with_reply_awaition_2(&mut mode_store);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_reply_handler_vec_no_reply_awaition() {
|
||||
let mut mode_store = ModeStoreVec::default();
|
||||
generic_reply_handling_test_no_reply_awaition(&mut mode_store);
|
||||
}
|
||||
#[test]
|
||||
fn test_generic_reply_handler_map_no_reply_awaition() {
|
||||
let mut mode_store = ModeStoreMap::default();
|
||||
generic_reply_handling_test_no_reply_awaition(&mut mode_store);
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,8 @@ pub mod alloc_mod {
|
||||
action::ActionRequest,
|
||||
queue::GenericTargetedMessagingError,
|
||||
request::{
|
||||
GenericMessage, MessageReceiver, MessageSender, MessageSenderAndReceiver, RequestId,
|
||||
GenericMessage, MessageReceiverProvider, MessageSenderAndReceiver,
|
||||
MessageSenderProvider, MessageSenderStoreProvider, RequestId,
|
||||
},
|
||||
ComponentId,
|
||||
};
|
||||
@ -76,11 +77,14 @@ pub mod alloc_mod {
|
||||
use super::ActionReplyPus;
|
||||
|
||||
/// Helper type definition for a mode handler which can handle mode requests.
|
||||
pub type ActionRequestHandlerInterface<S, R> =
|
||||
MessageSenderAndReceiver<ActionReplyPus, ActionRequest, S, R>;
|
||||
pub type ActionRequestHandlerInterface<Sender, Receiver, ReplySenderStore> =
|
||||
MessageSenderAndReceiver<ActionReplyPus, ActionRequest, Sender, Receiver, ReplySenderStore>;
|
||||
|
||||
impl<S: MessageSender<ActionReplyPus>, R: MessageReceiver<ActionRequest>>
|
||||
ActionRequestHandlerInterface<S, R>
|
||||
impl<
|
||||
Sender: MessageSenderProvider<ActionReplyPus>,
|
||||
Receiver: MessageReceiverProvider<ActionRequest>,
|
||||
ReplySender: MessageSenderStoreProvider<ActionReplyPus, Sender>,
|
||||
> ActionRequestHandlerInterface<Sender, Receiver, ReplySender>
|
||||
{
|
||||
pub fn try_recv_action_request(
|
||||
&self,
|
||||
@ -100,11 +104,20 @@ pub mod alloc_mod {
|
||||
|
||||
/// Helper type defintion for a mode handler object which can send mode requests and receive
|
||||
/// mode replies.
|
||||
pub type ActionRequestorInterface<S, R> =
|
||||
MessageSenderAndReceiver<ActionRequest, ActionReplyPus, S, R>;
|
||||
pub type ActionRequestorInterface<Sender, Receiver, RequestSenderStore> =
|
||||
MessageSenderAndReceiver<
|
||||
ActionRequest,
|
||||
ActionReplyPus,
|
||||
Sender,
|
||||
Receiver,
|
||||
RequestSenderStore,
|
||||
>;
|
||||
|
||||
impl<S: MessageSender<ActionRequest>, R: MessageReceiver<ActionReplyPus>>
|
||||
ActionRequestorInterface<S, R>
|
||||
impl<
|
||||
Sender: MessageSenderProvider<ActionRequest>,
|
||||
Receiver: MessageReceiverProvider<ActionReplyPus>,
|
||||
RequestSenderStore: MessageSenderStoreProvider<ActionRequest, Sender>,
|
||||
> ActionRequestorInterface<Sender, Receiver, RequestSenderStore>
|
||||
{
|
||||
pub fn try_recv_action_reply(
|
||||
&self,
|
||||
@ -132,6 +145,7 @@ pub mod std_mod {
|
||||
verification::{self, TcStateToken},
|
||||
ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap,
|
||||
},
|
||||
request::{MessageSenderMap, OneMessageSender},
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
@ -174,22 +188,38 @@ pub mod std_mod {
|
||||
}
|
||||
pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap<ActivePusActionRequestStd>;
|
||||
|
||||
pub type ActionRequestHandlerMpsc = ActionRequestHandlerInterface<
|
||||
pub type ActionRequestHandlerOneSenderMpsc = ActionRequestHandlerInterface<
|
||||
mpsc::Sender<GenericMessage<ActionReplyPus>>,
|
||||
mpsc::Receiver<GenericMessage<ActionRequest>>,
|
||||
OneMessageSender<
|
||||
GenericMessage<ActionReplyPus>,
|
||||
mpsc::Sender<GenericMessage<ActionReplyPus>>,
|
||||
>,
|
||||
>;
|
||||
pub type ActionRequestHandlerMpscBounded = ActionRequestHandlerInterface<
|
||||
pub type ActionRequestHandlerOneSenderMpscBounded = ActionRequestHandlerInterface<
|
||||
mpsc::SyncSender<GenericMessage<ActionReplyPus>>,
|
||||
mpsc::Receiver<GenericMessage<ActionRequest>>,
|
||||
OneMessageSender<
|
||||
GenericMessage<ActionReplyPus>,
|
||||
mpsc::SyncSender<GenericMessage<ActionReplyPus>>,
|
||||
>,
|
||||
>;
|
||||
|
||||
pub type ActionRequestorMpsc = ActionRequestorInterface<
|
||||
pub type ActionRequestorWithSenderMapMpsc = ActionRequestorInterface<
|
||||
mpsc::Sender<GenericMessage<ActionRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ActionReplyPus>>,
|
||||
MessageSenderMap<
|
||||
GenericMessage<ActionRequest>,
|
||||
mpsc::Sender<GenericMessage<ActionRequest>>,
|
||||
>,
|
||||
>;
|
||||
pub type ActionRequestorBoundedMpsc = ActionRequestorInterface<
|
||||
pub type ActionRequestorWithSenderMapBoundedMpsc = ActionRequestorInterface<
|
||||
mpsc::SyncSender<GenericMessage<ActionRequest>>,
|
||||
mpsc::Receiver<GenericMessage<ActionReplyPus>>,
|
||||
MessageSenderMap<
|
||||
GenericMessage<ActionRequest>,
|
||||
mpsc::SyncSender<GenericMessage<ActionRequest>>,
|
||||
>,
|
||||
>;
|
||||
}
|
||||
|
||||
|
@ -1221,9 +1221,10 @@ pub(crate) fn source_buffer_large_enough(
|
||||
|
||||
#[cfg(any(feature = "test_util", test))]
|
||||
pub mod test_util {
|
||||
use crate::request::UniqueApidTargetId;
|
||||
use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader};
|
||||
|
||||
use crate::request::UniqueApidTargetId;
|
||||
|
||||
use super::{
|
||||
verification::{self, TcStateAccepted, VerificationToken},
|
||||
DirectPusPacketHandlerResult, PusPacketHandlingError,
|
||||
@ -1232,6 +1233,7 @@ pub mod test_util {
|
||||
pub const TEST_APID: u16 = 0x101;
|
||||
pub const TEST_UNIQUE_ID_0: u32 = 0x05;
|
||||
pub const TEST_UNIQUE_ID_1: u32 = 0x06;
|
||||
|
||||
pub const TEST_COMPONENT_ID_0: UniqueApidTargetId =
|
||||
UniqueApidTargetId::new(TEST_APID, TEST_UNIQUE_ID_0);
|
||||
pub const TEST_COMPONENT_ID_1: UniqueApidTargetId =
|
||||
@ -1268,14 +1270,13 @@ pub mod tests {
|
||||
use spacepackets::ecss::tm::{GenericPusTmSecondaryHeader, PusTmCreator, PusTmReader};
|
||||
use spacepackets::ecss::{PusPacket, WritablePusPacket};
|
||||
use spacepackets::CcsdsPacket;
|
||||
use test_util::{TEST_APID, TEST_COMPONENT_ID_0};
|
||||
|
||||
use crate::pool::{PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig};
|
||||
use crate::pus::verification::{RequestId, VerificationReporter};
|
||||
use crate::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool, SharedPacketPool};
|
||||
use crate::ComponentId;
|
||||
|
||||
use super::test_util::{TEST_APID, TEST_COMPONENT_ID_0};
|
||||
|
||||
use super::verification::test_util::TestVerificationReporter;
|
||||
use super::verification::{
|
||||
TcStateAccepted, VerificationReporterCfg, VerificationReportingProvider, VerificationToken,
|
||||
|
@ -39,7 +39,7 @@ mod tests {
|
||||
use crate::{
|
||||
mode::{
|
||||
ModeAndSubmode, ModeReply, ModeReplySender, ModeRequest, ModeRequestSender,
|
||||
ModeRequestorAndHandlerMpsc, ModeRequestorMpsc,
|
||||
ModeRequestorAndHandlerMpsc, ModeRequestorOneChildMpsc,
|
||||
},
|
||||
request::{GenericMessage, MessageMetadata},
|
||||
};
|
||||
@ -52,7 +52,8 @@ mod tests {
|
||||
fn test_simple_mode_requestor() {
|
||||
let (reply_sender, reply_receiver) = mpsc::channel();
|
||||
let (request_sender, request_receiver) = mpsc::channel();
|
||||
let mut mode_requestor = ModeRequestorMpsc::new(TEST_COMPONENT_ID_0, reply_receiver);
|
||||
let mut mode_requestor =
|
||||
ModeRequestorOneChildMpsc::new(TEST_COMPONENT_ID_0, reply_receiver);
|
||||
mode_requestor.add_message_target(TEST_COMPONENT_ID_1, request_sender);
|
||||
|
||||
// Send a request and verify it arrives at the receiver.
|
||||
|
@ -1,6 +1,3 @@
|
||||
use core::fmt::{Display, Formatter};
|
||||
#[cfg(feature = "std")]
|
||||
use std::error::Error;
|
||||
#[cfg(feature = "std")]
|
||||
use std::sync::mpsc;
|
||||
|
||||
@ -10,89 +7,31 @@ use crate::ComponentId;
|
||||
pub type ChannelId = u32;
|
||||
|
||||
/// Generic error type for sending something via a message queue.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
|
||||
pub enum GenericSendError {
|
||||
#[error("rx side has disconnected")]
|
||||
RxDisconnected,
|
||||
#[error("queue with max capacity of {0:?} is full")]
|
||||
QueueFull(Option<u32>),
|
||||
#[error("target queue with ID {0} does not exist")]
|
||||
TargetDoesNotExist(ComponentId),
|
||||
}
|
||||
|
||||
impl Display for GenericSendError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
GenericSendError::RxDisconnected => {
|
||||
write!(f, "rx side has disconnected")
|
||||
}
|
||||
GenericSendError::QueueFull(max_cap) => {
|
||||
write!(f, "queue with max capacity of {max_cap:?} is full")
|
||||
}
|
||||
GenericSendError::TargetDoesNotExist(target) => {
|
||||
write!(f, "target queue with ID {target} does not exist")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for GenericSendError {}
|
||||
|
||||
/// Generic error type for sending something via a message queue.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)]
|
||||
pub enum GenericReceiveError {
|
||||
#[error("nothing to receive")]
|
||||
Empty,
|
||||
#[error("tx side with id {0:?} has disconnected")]
|
||||
TxDisconnected(Option<ComponentId>),
|
||||
}
|
||||
|
||||
impl Display for GenericReceiveError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::TxDisconnected(channel_id) => {
|
||||
write!(f, "tx side with id {channel_id:?} has disconnected")
|
||||
}
|
||||
Self::Empty => {
|
||||
write!(f, "nothing to receive")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for GenericReceiveError {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, thiserror::Error)]
|
||||
pub enum GenericTargetedMessagingError {
|
||||
Send(GenericSendError),
|
||||
Receive(GenericReceiveError),
|
||||
}
|
||||
impl From<GenericSendError> for GenericTargetedMessagingError {
|
||||
fn from(value: GenericSendError) -> Self {
|
||||
Self::Send(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GenericReceiveError> for GenericTargetedMessagingError {
|
||||
fn from(value: GenericReceiveError) -> Self {
|
||||
Self::Receive(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for GenericTargetedMessagingError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
Self::Send(err) => write!(f, "generic targeted messaging error: {}", err),
|
||||
Self::Receive(err) => write!(f, "generic targeted messaging error: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Error for GenericTargetedMessagingError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
GenericTargetedMessagingError::Send(send) => Some(send),
|
||||
GenericTargetedMessagingError::Receive(receive) => Some(receive),
|
||||
}
|
||||
}
|
||||
#[error("generic targeted messaging send error: {0}")]
|
||||
Send(#[from] GenericSendError),
|
||||
#[error("generic targeted messaging receive error: {0}")]
|
||||
Receive(#[from] GenericReceiveError),
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
@ -140,24 +140,27 @@ impl<Message> GenericMessage<Message> {
|
||||
}
|
||||
|
||||
/// Generic trait for objects which can send targeted messages.
|
||||
pub trait MessageSender<MSG>: Send {
|
||||
pub trait MessageSenderProvider<MSG>: Send {
|
||||
fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError>;
|
||||
}
|
||||
|
||||
// Generic trait for objects which can receive targeted messages.
|
||||
pub trait MessageReceiver<MSG> {
|
||||
pub trait MessageReceiverProvider<MSG> {
|
||||
fn try_recv(&self) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError>;
|
||||
}
|
||||
|
||||
pub struct MessageWithSenderIdReceiver<MSG, R: MessageReceiver<MSG>>(pub R, PhantomData<MSG>);
|
||||
pub struct MessageWithSenderIdReceiver<Msg, Receiver: MessageReceiverProvider<Msg>>(
|
||||
pub Receiver,
|
||||
PhantomData<Msg>,
|
||||
);
|
||||
|
||||
impl<MSG, R: MessageReceiver<MSG>> From<R> for MessageWithSenderIdReceiver<MSG, R> {
|
||||
impl<MSG, R: MessageReceiverProvider<MSG>> From<R> for MessageWithSenderIdReceiver<MSG, R> {
|
||||
fn from(receiver: R) -> Self {
|
||||
MessageWithSenderIdReceiver(receiver, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MSG, R: MessageReceiver<MSG>> MessageWithSenderIdReceiver<MSG, R> {
|
||||
impl<MSG, R: MessageReceiverProvider<MSG>> MessageWithSenderIdReceiver<MSG, R> {
|
||||
pub fn try_recv_message(
|
||||
&self,
|
||||
) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
|
||||
@ -165,12 +168,12 @@ impl<MSG, R: MessageReceiver<MSG>> MessageWithSenderIdReceiver<MSG, R> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MessageReceiverWithId<MSG, R: MessageReceiver<MSG>> {
|
||||
pub struct MessageReceiverWithId<MSG, R: MessageReceiverProvider<MSG>> {
|
||||
local_channel_id: ComponentId,
|
||||
reply_receiver: MessageWithSenderIdReceiver<MSG, R>,
|
||||
}
|
||||
|
||||
impl<MSG, R: MessageReceiver<MSG>> MessageReceiverWithId<MSG, R> {
|
||||
impl<MSG, R: MessageReceiverProvider<MSG>> MessageReceiverWithId<MSG, R> {
|
||||
pub fn new(local_channel_id: ComponentId, reply_receiver: R) -> Self {
|
||||
Self {
|
||||
local_channel_id,
|
||||
@ -183,7 +186,7 @@ impl<MSG, R: MessageReceiver<MSG>> MessageReceiverWithId<MSG, R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<MSG, R: MessageReceiver<MSG>> MessageReceiverWithId<MSG, R> {
|
||||
impl<MSG, R: MessageReceiverProvider<MSG>> MessageReceiverWithId<MSG, R> {
|
||||
pub fn try_recv_message(
|
||||
&self,
|
||||
) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
|
||||
@ -191,34 +194,122 @@ impl<MSG, R: MessageReceiver<MSG>> MessageReceiverWithId<MSG, R> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MessageSenderStoreProvider<Message, Sender>: Default {
|
||||
fn add_message_target(&mut self, target_id: ComponentId, message_sender: Sender);
|
||||
|
||||
fn send_message(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
target_channel_id: ComponentId,
|
||||
message: Message,
|
||||
) -> Result<(), GenericTargetedMessagingError>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod alloc_mod {
|
||||
use crate::queue::GenericSendError;
|
||||
use std::convert::From;
|
||||
|
||||
use super::*;
|
||||
use hashbrown::HashMap;
|
||||
|
||||
pub struct MessageSenderMap<MSG, S: MessageSender<MSG>>(
|
||||
pub HashMap<ComponentId, S>,
|
||||
pub struct OneMessageSender<Msg, S: MessageSenderProvider<Msg>> {
|
||||
pub id_and_sender: Option<(ComponentId, S)>,
|
||||
pub(crate) phantom: PhantomData<Msg>,
|
||||
}
|
||||
|
||||
impl<Msg, S: MessageSenderProvider<Msg>> Default for OneMessageSender<Msg, S> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id_and_sender: Default::default(),
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Msg, Sender: MessageSenderProvider<Msg>> MessageSenderStoreProvider<Msg, Sender>
|
||||
for OneMessageSender<Msg, Sender>
|
||||
{
|
||||
fn add_message_target(&mut self, target_id: ComponentId, message_sender: Sender) {
|
||||
if self.id_and_sender.is_some() {
|
||||
return;
|
||||
}
|
||||
self.id_and_sender = Some((target_id, message_sender));
|
||||
}
|
||||
|
||||
fn send_message(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
target_channel_id: ComponentId,
|
||||
message: Msg,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
if let Some((current_id, sender)) = &self.id_and_sender {
|
||||
if *current_id == target_channel_id {
|
||||
sender.send(GenericMessage::new(requestor_info, message))?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(GenericSendError::TargetDoesNotExist(target_channel_id).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MessageSenderList<MSG, S: MessageSenderProvider<MSG>>(
|
||||
pub alloc::vec::Vec<(ComponentId, S)>,
|
||||
pub(crate) PhantomData<MSG>,
|
||||
);
|
||||
|
||||
impl<MSG, S: MessageSender<MSG>> Default for MessageSenderMap<MSG, S> {
|
||||
impl<MSG, S: MessageSenderProvider<MSG>> Default for MessageSenderList<MSG, S> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<MSG, S: MessageSender<MSG>> MessageSenderMap<MSG, S> {
|
||||
pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) {
|
||||
self.0.insert(target_id, message_sender);
|
||||
impl<Msg, Sender: MessageSenderProvider<Msg>> MessageSenderStoreProvider<Msg, Sender>
|
||||
for MessageSenderList<Msg, Sender>
|
||||
{
|
||||
fn add_message_target(&mut self, target_id: ComponentId, message_sender: Sender) {
|
||||
self.0.push((target_id, message_sender));
|
||||
}
|
||||
|
||||
pub fn send_message(
|
||||
fn send_message(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
target_channel_id: ComponentId,
|
||||
message: MSG,
|
||||
message: Msg,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
for (current_id, sender) in &self.0 {
|
||||
if *current_id == target_channel_id {
|
||||
sender.send(GenericMessage::new(requestor_info, message))?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(GenericSendError::TargetDoesNotExist(target_channel_id).into())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MessageSenderMap<MSG, S: MessageSenderProvider<MSG>>(
|
||||
pub HashMap<ComponentId, S>,
|
||||
pub(crate) PhantomData<MSG>,
|
||||
);
|
||||
|
||||
impl<MSG, S: MessageSenderProvider<MSG>> Default for MessageSenderMap<MSG, S> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default(), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Msg, Sender: MessageSenderProvider<Msg>> MessageSenderStoreProvider<Msg, Sender>
|
||||
for MessageSenderMap<Msg, Sender>
|
||||
{
|
||||
fn add_message_target(&mut self, target_id: ComponentId, message_sender: Sender) {
|
||||
self.0.insert(target_id, message_sender);
|
||||
}
|
||||
|
||||
fn send_message(
|
||||
&self,
|
||||
requestor_info: MessageMetadata,
|
||||
target_channel_id: ComponentId,
|
||||
message: Msg,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
if self.0.contains_key(&target_channel_id) {
|
||||
return self
|
||||
@ -231,25 +322,38 @@ pub mod alloc_mod {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MessageSenderAndReceiver<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>> {
|
||||
pub struct MessageSenderAndReceiver<
|
||||
To,
|
||||
From,
|
||||
Sender: MessageSenderProvider<To>,
|
||||
Receiver: MessageReceiverProvider<From>,
|
||||
SenderStore: MessageSenderStoreProvider<To, Sender>,
|
||||
> {
|
||||
pub local_channel_id: ComponentId,
|
||||
pub message_sender_map: MessageSenderMap<TO, S>,
|
||||
pub message_receiver: MessageWithSenderIdReceiver<FROM, R>,
|
||||
pub message_sender_store: SenderStore,
|
||||
pub message_receiver: MessageWithSenderIdReceiver<From, Receiver>,
|
||||
pub(crate) phantom: PhantomData<(To, Sender)>,
|
||||
}
|
||||
|
||||
impl<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>>
|
||||
MessageSenderAndReceiver<TO, FROM, S, R>
|
||||
impl<
|
||||
To,
|
||||
From,
|
||||
Sender: MessageSenderProvider<To>,
|
||||
Receiver: MessageReceiverProvider<From>,
|
||||
SenderStore: MessageSenderStoreProvider<To, Sender>,
|
||||
> MessageSenderAndReceiver<To, From, Sender, Receiver, SenderStore>
|
||||
{
|
||||
pub fn new(local_channel_id: ComponentId, message_receiver: R) -> Self {
|
||||
pub fn new(local_channel_id: ComponentId, message_receiver: Receiver) -> Self {
|
||||
Self {
|
||||
local_channel_id,
|
||||
message_sender_map: Default::default(),
|
||||
message_sender_store: Default::default(),
|
||||
message_receiver: MessageWithSenderIdReceiver::from(message_receiver),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) {
|
||||
self.message_sender_map
|
||||
pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: Sender) {
|
||||
self.message_sender_store
|
||||
.add_message_target(target_id, message_sender)
|
||||
}
|
||||
|
||||
@ -262,9 +366,9 @@ pub mod alloc_mod {
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
target_id: ComponentId,
|
||||
message: TO,
|
||||
message: To,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.message_sender_map.send_message(
|
||||
self.message_sender_store.send_message(
|
||||
MessageMetadata::new(request_id, self.local_channel_id_generic()),
|
||||
target_id,
|
||||
message,
|
||||
@ -274,48 +378,64 @@ pub mod alloc_mod {
|
||||
/// Try to receive a message, which can be a reply or a request, depending on the generics.
|
||||
pub fn try_recv_message(
|
||||
&self,
|
||||
) -> Result<Option<GenericMessage<FROM>>, GenericTargetedMessagingError> {
|
||||
) -> Result<Option<GenericMessage<From>>, GenericTargetedMessagingError> {
|
||||
self.message_receiver.try_recv_message()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RequestAndReplySenderAndReceiver<
|
||||
REQUEST,
|
||||
REPLY,
|
||||
S0: MessageSender<REQUEST>,
|
||||
R0: MessageReceiver<REPLY>,
|
||||
S1: MessageSender<REPLY>,
|
||||
R1: MessageReceiver<REQUEST>,
|
||||
Request,
|
||||
ReqSender: MessageSenderProvider<Request>,
|
||||
ReqReceiver: MessageReceiverProvider<Request>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
|
||||
Reply,
|
||||
ReplySender: MessageSenderProvider<Reply>,
|
||||
ReplyReceiver: MessageReceiverProvider<Reply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
|
||||
> {
|
||||
pub local_channel_id: ComponentId,
|
||||
// These 2 are a functional group.
|
||||
pub request_sender_map: MessageSenderMap<REQUEST, S0>,
|
||||
pub reply_receiver: MessageWithSenderIdReceiver<REPLY, R0>,
|
||||
pub request_sender_store: ReqSenderStore,
|
||||
pub reply_receiver: MessageWithSenderIdReceiver<Reply, ReplyReceiver>,
|
||||
// These 2 are a functional group.
|
||||
pub request_receiver: MessageWithSenderIdReceiver<REQUEST, R1>,
|
||||
pub reply_sender_map: MessageSenderMap<REPLY, S1>,
|
||||
pub request_receiver: MessageWithSenderIdReceiver<Request, ReqReceiver>,
|
||||
pub reply_sender_store: ReplySenderStore,
|
||||
phantom: PhantomData<(ReqSender, ReplySender)>,
|
||||
}
|
||||
|
||||
impl<
|
||||
REQUEST,
|
||||
REPLY,
|
||||
S0: MessageSender<REQUEST>,
|
||||
R0: MessageReceiver<REPLY>,
|
||||
S1: MessageSender<REPLY>,
|
||||
R1: MessageReceiver<REQUEST>,
|
||||
> RequestAndReplySenderAndReceiver<REQUEST, REPLY, S0, R0, S1, R1>
|
||||
Request,
|
||||
ReqSender: MessageSenderProvider<Request>,
|
||||
ReqReceiver: MessageReceiverProvider<Request>,
|
||||
ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
|
||||
Reply,
|
||||
ReplySender: MessageSenderProvider<Reply>,
|
||||
ReplyReceiver: MessageReceiverProvider<Reply>,
|
||||
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
|
||||
>
|
||||
RequestAndReplySenderAndReceiver<
|
||||
Request,
|
||||
ReqSender,
|
||||
ReqReceiver,
|
||||
ReqSenderStore,
|
||||
Reply,
|
||||
ReplySender,
|
||||
ReplyReceiver,
|
||||
ReplySenderStore,
|
||||
>
|
||||
{
|
||||
pub fn new(
|
||||
local_channel_id: ComponentId,
|
||||
request_receiver: R1,
|
||||
reply_receiver: R0,
|
||||
request_receiver: ReqReceiver,
|
||||
reply_receiver: ReplyReceiver,
|
||||
) -> Self {
|
||||
Self {
|
||||
local_channel_id,
|
||||
request_receiver: request_receiver.into(),
|
||||
reply_receiver: reply_receiver.into(),
|
||||
request_sender_map: Default::default(),
|
||||
reply_sender_map: Default::default(),
|
||||
request_sender_store: Default::default(),
|
||||
reply_sender_store: Default::default(),
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -333,14 +453,14 @@ pub mod std_mod {
|
||||
|
||||
use crate::queue::{GenericReceiveError, GenericSendError};
|
||||
|
||||
impl<MSG: Send> MessageSender<MSG> for mpsc::Sender<GenericMessage<MSG>> {
|
||||
impl<MSG: Send> MessageSenderProvider<MSG> for mpsc::Sender<GenericMessage<MSG>> {
|
||||
fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.send(message)
|
||||
.map_err(|_| GenericSendError::RxDisconnected)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<MSG: Send> MessageSender<MSG> for mpsc::SyncSender<GenericMessage<MSG>> {
|
||||
impl<MSG: Send> MessageSenderProvider<MSG> for mpsc::SyncSender<GenericMessage<MSG>> {
|
||||
fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError> {
|
||||
if let Err(e) = self.try_send(message) {
|
||||
return match e {
|
||||
@ -357,7 +477,7 @@ pub mod std_mod {
|
||||
pub type MessageSenderMapMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::Sender<MSG>>;
|
||||
pub type MessageSenderMapBoundedMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::SyncSender<MSG>>;
|
||||
|
||||
impl<MSG> MessageReceiver<MSG> for mpsc::Receiver<GenericMessage<MSG>> {
|
||||
impl<MSG> MessageReceiverProvider<MSG> for mpsc::Receiver<GenericMessage<MSG>> {
|
||||
fn try_recv(&self) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
|
||||
match self.try_recv() {
|
||||
Ok(msg) => Ok(Some(msg)),
|
||||
@ -386,7 +506,7 @@ mod tests {
|
||||
|
||||
use crate::{
|
||||
queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError},
|
||||
request::{MessageMetadata, MessageSenderMap},
|
||||
request::{MessageMetadata, MessageSenderMap, MessageSenderStoreProvider},
|
||||
};
|
||||
|
||||
use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId};
|
||||
|
@ -154,7 +154,7 @@ pub mod std_mod {
|
||||
}
|
||||
|
||||
/// Can be used to set the start of the slot to the current time. This is useful if a custom
|
||||
/// runner implementation is used instead of the [Self::start] method.
|
||||
/// runner implementation is used instead of the [Self::run_one_task_cycle] method.
|
||||
pub fn init_start_of_slot(&mut self) {
|
||||
self.start_of_slot = Instant::now();
|
||||
}
|
||||
|
998
satrs/src/subsystem.rs
Normal file
998
satrs/src/subsystem.rs
Normal file
@ -0,0 +1,998 @@
|
||||
use crate::{
|
||||
mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender, UNKNOWN_MODE},
|
||||
mode_tree::{
|
||||
ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableMapTable,
|
||||
SequenceTablesMapValue, TargetModeTables, TargetNotInModeStoreError, TargetTablesMapValue,
|
||||
},
|
||||
queue::GenericTargetedMessagingError,
|
||||
request::{GenericMessage, RequestId},
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum SequenceExecutionHelperState {
|
||||
/// The sequence execution is IDLE, no command is loaded or the sequence exection has
|
||||
/// finished
|
||||
Idle,
|
||||
/// The sequence helper is executing a sequence and no replies need to be awaited.
|
||||
Busy,
|
||||
/// The sequence helper is still awaiting a reply from a mode children. The reply awaition
|
||||
/// is a property of a mode commanding sequence
|
||||
AwaitingSuccessCheck,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TargetKeepingResult {
|
||||
Ok,
|
||||
Violated { fallback_mode: Option<Mode> },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ModeCommandingResult {
|
||||
/// The commanding of all children is finished
|
||||
Done,
|
||||
/// One step of a commanding chain is finished
|
||||
StepDone,
|
||||
/// Reply awaition is required for some children
|
||||
AwaitingSuccessCheck,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Mode {0} does not exist")]
|
||||
pub struct ModeDoesNotExistError(Mode);
|
||||
|
||||
/// This sequence execution helper includes some boilerplate logic to
|
||||
/// execute [SequenceModeTables].
|
||||
///
|
||||
/// It takes care of commanding the [ModeRequest]s specified in those tables and also includes the
|
||||
/// states required to track the current progress of a sequence execution and take care of
|
||||
/// reply and success awaition.
|
||||
#[derive(Debug)]
|
||||
pub struct SequenceExecutionHelper {
|
||||
target_mode: Option<Mode>,
|
||||
state: SequenceExecutionHelperState,
|
||||
request_id: Option<RequestId>,
|
||||
current_sequence_index: Option<usize>,
|
||||
last_sequence_index: Option<usize>,
|
||||
}
|
||||
|
||||
impl Default for SequenceExecutionHelper {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
target_mode: None,
|
||||
state: SequenceExecutionHelperState::Idle,
|
||||
request_id: None,
|
||||
current_sequence_index: None,
|
||||
last_sequence_index: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SequenceExecutionHelper {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Load a new mode sequence to be executed
|
||||
pub fn load(
|
||||
&mut self,
|
||||
mode: Mode,
|
||||
request_id: RequestId,
|
||||
sequence_tables: &SequenceModeTables,
|
||||
) -> Result<(), ModeDoesNotExistError> {
|
||||
if !sequence_tables.0.contains_key(&mode) {
|
||||
return Err(ModeDoesNotExistError(mode));
|
||||
}
|
||||
self.target_mode = Some(mode);
|
||||
self.request_id = Some(request_id);
|
||||
self.state = SequenceExecutionHelperState::Busy;
|
||||
self.current_sequence_index = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Run the sequence execution helper.
|
||||
///
|
||||
/// This function will execute the sequence in the given [SequenceModeTables] based on the
|
||||
/// mode loaded in [Self::load]. It calls [Self::execute_sequence_and_map_to_result] and
|
||||
/// automatically takes care of state management, including increments of the sequence table
|
||||
/// index.
|
||||
///
|
||||
/// The returnvalues of the helper have the following meaning.
|
||||
///
|
||||
/// * [ModeCommandingResult::AwaitingSuccessCheck] - The sequence is still awaiting a success.
|
||||
/// The user should check whether all children have reached the commanded target mode, for
|
||||
/// example by checking [mode replies][ModeReply] received by the children components, and
|
||||
/// then calling [Self::confirm_sequence_done] to advance to the sequence or complete the
|
||||
/// sequence.
|
||||
/// * [ModeCommandingResult::CommandingDone] - The sequence is done. The user can load a new
|
||||
/// sequence now without overwriting the last one. The sequence executor is in
|
||||
/// [SequenceExecutionHelperState::Idle] again.
|
||||
/// * [ModeCommandingResult::CommandingStepDone] - The sequence has advanced one step. The user
|
||||
/// can now call [Self::run] again to immediately execute the next step in the sequence.
|
||||
///
|
||||
/// Generally, periodic execution of the [Self::run] method should be performed while
|
||||
/// [Self::state] is not [SequenceExecutionHelperState::Idle].
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `table` - This table contains the sequence tables to reach the mode previously loaded
|
||||
/// with [Self::load]
|
||||
/// * `sender` - The sender to send mode requests to the components
|
||||
/// * `children_mode_store` - The mode store vector to keep track of the mode states of
|
||||
/// children components
|
||||
pub fn run(
|
||||
&mut self,
|
||||
table: &SequenceModeTables,
|
||||
sender: &impl ModeRequestSender,
|
||||
children_mode_store: &mut ModeStoreVec,
|
||||
) -> Result<ModeCommandingResult, GenericTargetedMessagingError> {
|
||||
if self.state == SequenceExecutionHelperState::Idle {
|
||||
return Ok(ModeCommandingResult::Done);
|
||||
}
|
||||
if self.state == SequenceExecutionHelperState::AwaitingSuccessCheck {
|
||||
return Ok(ModeCommandingResult::AwaitingSuccessCheck);
|
||||
}
|
||||
if self.target_mode.is_none() {
|
||||
return Ok(ModeCommandingResult::Done);
|
||||
}
|
||||
match self.current_sequence_index {
|
||||
Some(idx) => {
|
||||
// Execute the sequence.
|
||||
let seq_table_value = table.0.get(&self.target_mode.unwrap()).unwrap();
|
||||
self.execute_sequence_and_map_to_result(
|
||||
seq_table_value,
|
||||
idx,
|
||||
sender,
|
||||
children_mode_store,
|
||||
)
|
||||
}
|
||||
None => {
|
||||
// Find the first sequence
|
||||
let seq_table_value = table.0.get(&self.target_mode.unwrap()).unwrap();
|
||||
self.last_sequence_index = Some(seq_table_value.entries.len() - 1);
|
||||
if seq_table_value.entries.is_empty() {
|
||||
Ok(ModeCommandingResult::Done)
|
||||
} else {
|
||||
self.current_sequence_index = Some(0);
|
||||
self.execute_sequence_and_map_to_result(
|
||||
seq_table_value,
|
||||
0,
|
||||
sender,
|
||||
children_mode_store,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the currently loaded target mode
|
||||
pub fn target_mode(&self) -> Option<Mode> {
|
||||
self.target_mode
|
||||
}
|
||||
|
||||
/// Confirm that a sequence which is awaiting a success check is done
|
||||
pub fn confirm_sequence_done(&mut self) {
|
||||
if let SequenceExecutionHelperState::AwaitingSuccessCheck = self.state {
|
||||
self.state = SequenceExecutionHelperState::Busy;
|
||||
if let (Some(last_sequence_index), Some(current_sequence_index)) =
|
||||
(self.last_sequence_index, self.current_sequence_index)
|
||||
{
|
||||
if current_sequence_index == last_sequence_index {
|
||||
self.state = SequenceExecutionHelperState::Idle;
|
||||
}
|
||||
}
|
||||
self.current_sequence_index = Some(self.current_sequence_index.unwrap() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal state of the execution helper.
|
||||
pub fn state(&self) -> SequenceExecutionHelperState {
|
||||
self.state
|
||||
}
|
||||
|
||||
pub fn awaiting_success_check(&self) -> bool {
|
||||
self.state == SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
}
|
||||
|
||||
pub fn current_sequence_index(&self) -> Option<usize> {
|
||||
self.current_sequence_index
|
||||
}
|
||||
|
||||
/// Execute a sequence at the given sequence index for a given [SequenceTablesMapValue].
|
||||
///
|
||||
/// This method calls [Self::execute_sequence] and maps the result to a [ModeCommandingResult].
|
||||
/// It is also called by the [Self::run] method of this helper.
|
||||
pub fn execute_sequence_and_map_to_result(
|
||||
&mut self,
|
||||
seq_table_value: &SequenceTablesMapValue,
|
||||
sequence_idx: usize,
|
||||
sender: &impl ModeRequestSender,
|
||||
mode_store_vec: &mut ModeStoreVec,
|
||||
) -> Result<ModeCommandingResult, GenericTargetedMessagingError> {
|
||||
if self.state() == SequenceExecutionHelperState::Idle || self.request_id.is_none() {
|
||||
return Ok(ModeCommandingResult::Done);
|
||||
}
|
||||
if Self::execute_sequence(
|
||||
self.request_id.unwrap(),
|
||||
&seq_table_value.entries[sequence_idx],
|
||||
sender,
|
||||
mode_store_vec,
|
||||
)? {
|
||||
self.state = SequenceExecutionHelperState::AwaitingSuccessCheck;
|
||||
Ok(ModeCommandingResult::AwaitingSuccessCheck)
|
||||
} else if seq_table_value.entries.len() - 1 == sequence_idx {
|
||||
self.state = SequenceExecutionHelperState::Idle;
|
||||
return Ok(ModeCommandingResult::Done);
|
||||
} else {
|
||||
self.current_sequence_index = Some(sequence_idx + 1);
|
||||
return Ok(ModeCommandingResult::StepDone);
|
||||
}
|
||||
}
|
||||
|
||||
/// Generic stateless execution helper method.
|
||||
///
|
||||
/// The [RequestId] and the [SequenceTableMapTable] to be executed are passed explicitely
|
||||
/// here. This method is called by [Self::execute_sequence_and_map_to_result].
|
||||
///
|
||||
/// This method itereates through the entries of the given sequence table and sends out
|
||||
/// [ModeRequest]s to set the modes of the children according to the table entries.
|
||||
/// It also sets the reply awaition field in the children mode store where a success
|
||||
/// check is required to true.
|
||||
///
|
||||
/// It returns whether any commanding success check is required by any entry in the table.
|
||||
pub fn execute_sequence(
|
||||
request_id: RequestId,
|
||||
map_table: &SequenceTableMapTable,
|
||||
sender: &impl ModeRequestSender,
|
||||
children_mode_store: &mut ModeStoreVec,
|
||||
) -> Result<bool, GenericTargetedMessagingError> {
|
||||
let mut some_succes_check_required = false;
|
||||
for entry in &map_table.entries {
|
||||
sender.send_mode_request(
|
||||
request_id,
|
||||
entry.common.target_id,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: entry.common.mode_submode,
|
||||
forced: false,
|
||||
},
|
||||
)?;
|
||||
if entry.check_success {
|
||||
children_mode_store.0.iter_mut().for_each(|val| {
|
||||
if val.id() == entry.common.target_id {
|
||||
val.awaiting_reply = true;
|
||||
}
|
||||
});
|
||||
some_succes_check_required = true;
|
||||
}
|
||||
}
|
||||
Ok(some_succes_check_required)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub enum ModeTreeHelperState {
|
||||
#[default]
|
||||
Idle,
|
||||
/// The helper is currently trying to keep a target mode.
|
||||
TargetKeeping,
|
||||
/// The helper is currently busy to command a mode.
|
||||
ModeCommanding,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub enum SubsystemHelperResult {
|
||||
#[default]
|
||||
Idle,
|
||||
/// Result of a target keeping operation
|
||||
TargetKeeping(TargetKeepingResult),
|
||||
/// Result of a mode commanding operation
|
||||
ModeCommanding(ModeCommandingResult),
|
||||
}
|
||||
|
||||
impl From<TargetKeepingResult> for SubsystemHelperResult {
|
||||
fn from(value: TargetKeepingResult) -> Self {
|
||||
Self::TargetKeeping(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ModeCommandingResult> for SubsystemHelperResult {
|
||||
fn from(value: ModeCommandingResult) -> Self {
|
||||
Self::ModeCommanding(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum ModeTreeHelperError {
|
||||
#[error("generic targeted messaging error: {0}")]
|
||||
Message(#[from] GenericTargetedMessagingError),
|
||||
#[error("current mode {0} is not contained in target table")]
|
||||
CurrentModeNotInTargetTable(Mode),
|
||||
}
|
||||
|
||||
/// This is a helper object which can be used by a subsystem component to execute mode sequences
|
||||
/// and perform target keeping.
|
||||
///
|
||||
/// This helper object tries to compose as much data and state information as possible which is
|
||||
/// required for this process.
|
||||
pub struct SubsystemCommandingHelper {
|
||||
/// Current mode of the owner subsystem.
|
||||
pub current_mode: ModeAndSubmode,
|
||||
/// State of the helper.
|
||||
pub state: ModeTreeHelperState,
|
||||
/// This data structure is used to track all mode children.
|
||||
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>,
|
||||
/// 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.
|
||||
pub target_tables: TargetModeTables,
|
||||
/// The primary data structure to keep the sequence commanding information for commanded
|
||||
/// subsystem [modes][Mode]. It specifies the actual commands and the order they should be
|
||||
/// sent in to reach a certain [mode][Mode].
|
||||
pub sequence_tables: SequenceModeTables,
|
||||
/// The sequence execution helper is used to execute sequences in the [Self::sequence_tables].
|
||||
pub seq_exec_helper: SequenceExecutionHelper,
|
||||
}
|
||||
|
||||
impl Default for SubsystemCommandingHelper {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
current_mode: UNKNOWN_MODE,
|
||||
state: Default::default(),
|
||||
children_mode_store: Default::default(),
|
||||
active_request_id: None,
|
||||
target_tables: Default::default(),
|
||||
sequence_tables: Default::default(),
|
||||
seq_exec_helper: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubsystemCommandingHelper {
|
||||
/// Create a new substem commanding helper with an intial [ModeTreeHelperState::Idle] state,
|
||||
/// an empty mode children store and empty target and sequence mode tables.
|
||||
pub fn new(
|
||||
children_mode_store: ModeStoreVec,
|
||||
target_tables: TargetModeTables,
|
||||
sequence_tables: SequenceModeTables,
|
||||
) -> Self {
|
||||
Self {
|
||||
current_mode: UNKNOWN_MODE,
|
||||
state: ModeTreeHelperState::Idle,
|
||||
children_mode_store,
|
||||
active_request_id: None,
|
||||
target_tables,
|
||||
sequence_tables,
|
||||
seq_exec_helper: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a mode child to the internal [Self::children_mode_store].
|
||||
pub fn add_mode_child(&mut self, child: ComponentId, mode: ModeAndSubmode) {
|
||||
self.children_mode_store.add_component(child, mode);
|
||||
}
|
||||
|
||||
/// Add a target mode table and an associated sequence mode table.
|
||||
pub fn add_target_and_sequence_table(
|
||||
&mut self,
|
||||
mode: Mode,
|
||||
target_table_val: TargetTablesMapValue,
|
||||
sequence_table_val: SequenceTablesMapValue,
|
||||
) {
|
||||
self.target_tables.0.insert(mode, target_table_val);
|
||||
self.sequence_tables.0.insert(mode, sequence_table_val);
|
||||
}
|
||||
|
||||
/// Starts a command sequence for a given [mode][Mode].
|
||||
pub fn start_command_sequence(
|
||||
&mut self,
|
||||
mode: Mode,
|
||||
request_id: RequestId,
|
||||
) -> Result<(), ModeDoesNotExistError> {
|
||||
self.seq_exec_helper
|
||||
.load(mode, request_id, &self.sequence_tables)?;
|
||||
self.state = ModeTreeHelperState::ModeCommanding;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_announce_mode_cmd_to_children(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
req_sender: &impl ModeRequestSender,
|
||||
recursive: bool,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
let mut request = ModeRequest::AnnounceMode;
|
||||
if recursive {
|
||||
request = ModeRequest::AnnounceModeRecursive;
|
||||
}
|
||||
for child in &self.children_mode_store.0 {
|
||||
req_sender.send_mode_request(request_id, child.id(), request)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn state_machine(
|
||||
&mut self,
|
||||
opt_reply: Option<GenericMessage<ModeReply>>,
|
||||
req_sender: &impl ModeRequestSender,
|
||||
) -> Result<SubsystemHelperResult, ModeTreeHelperError> {
|
||||
if let Some(reply) = opt_reply {
|
||||
self.handle_mode_reply(&reply);
|
||||
}
|
||||
match self.state {
|
||||
ModeTreeHelperState::Idle => Ok(SubsystemHelperResult::Idle),
|
||||
ModeTreeHelperState::TargetKeeping => {
|
||||
// We check whether the current mode is modelled by a target table first.
|
||||
if let Some(target_table) = self.target_tables.0.get(&self.current_mode.mode()) {
|
||||
return Ok(self.perform_target_keeping(target_table).into());
|
||||
}
|
||||
Ok(TargetKeepingResult::Ok.into())
|
||||
}
|
||||
ModeTreeHelperState::ModeCommanding => {
|
||||
let result = self.seq_exec_helper.run(
|
||||
&self.sequence_tables,
|
||||
req_sender,
|
||||
&mut self.children_mode_store,
|
||||
)?;
|
||||
// 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 =
|
||||
ModeAndSubmode::new(self.seq_exec_helper.target_mode().unwrap(), 0);
|
||||
}
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perform_target_keeping(
|
||||
&self,
|
||||
target_table: &TargetTablesMapValue,
|
||||
) -> TargetKeepingResult {
|
||||
for entry in &target_table.entries {
|
||||
if !entry.monitor_state {
|
||||
continue;
|
||||
}
|
||||
let mut target_mode_violated = false;
|
||||
self.children_mode_store.0.iter().for_each(|val| {
|
||||
if val.id() == entry.common.target_id {
|
||||
target_mode_violated =
|
||||
if let Some(allowed_submode_mask) = entry.allowed_submode_mask() {
|
||||
let fixed_bits = !allowed_submode_mask;
|
||||
(val.mode_and_submode().mode() != entry.common.mode_submode.mode())
|
||||
&& (val.mode_and_submode().submode() & fixed_bits
|
||||
!= entry.common.mode_submode.submode() & fixed_bits)
|
||||
} else {
|
||||
val.mode_and_submode() != entry.common.mode_submode
|
||||
};
|
||||
}
|
||||
});
|
||||
if target_mode_violated {
|
||||
// Target keeping violated. Report violation and fallback mode to user.
|
||||
return TargetKeepingResult::Violated {
|
||||
fallback_mode: target_table.fallback_mode,
|
||||
};
|
||||
}
|
||||
}
|
||||
TargetKeepingResult::Ok
|
||||
}
|
||||
|
||||
pub fn handle_mode_reply(&mut self, reply: &GenericMessage<ModeReply>) {
|
||||
if !self.children_mode_store.has_component(reply.sender_id()) {
|
||||
return;
|
||||
}
|
||||
let mut generic_mode_reply_handler =
|
||||
|sender_id, mode_and_submode: Option<ModeAndSubmode>| {
|
||||
// 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()
|
||||
{
|
||||
handle_awaition = true;
|
||||
}
|
||||
let still_awating_replies = self.children_mode_store.mode_reply_handler(
|
||||
sender_id,
|
||||
mode_and_submode,
|
||||
handle_awaition,
|
||||
);
|
||||
if self.state == ModeTreeHelperState::ModeCommanding
|
||||
&& !still_awating_replies.unwrap_or(false)
|
||||
{
|
||||
self.seq_exec_helper.confirm_sequence_done();
|
||||
}
|
||||
};
|
||||
match reply.message {
|
||||
ModeReply::ModeInfo(mode_and_submode) => {
|
||||
generic_mode_reply_handler(reply.sender_id(), Some(mode_and_submode));
|
||||
}
|
||||
ModeReply::ModeReply(mode_and_submode) => {
|
||||
generic_mode_reply_handler(reply.sender_id(), Some(mode_and_submode));
|
||||
}
|
||||
ModeReply::CantReachMode(_) => {
|
||||
generic_mode_reply_handler(reply.sender_id(), None);
|
||||
}
|
||||
ModeReply::WrongMode { reached, .. } => {
|
||||
generic_mode_reply_handler(reply.sender_id(), Some(reached));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn update_child_mode(
|
||||
&mut self,
|
||||
child: ComponentId,
|
||||
mode: ModeAndSubmode,
|
||||
) -> Result<(), TargetNotInModeStoreError> {
|
||||
let val_mut = self
|
||||
.children_mode_store
|
||||
.get_mut(child)
|
||||
.ok_or(TargetNotInModeStoreError(child))?;
|
||||
val_mut.mode_and_submode = mode;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use core::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::{
|
||||
mode::{Mode, ModeAndSubmode, ModeRequest, ModeRequestSender, UNKNOWN_MODE},
|
||||
mode_tree::{
|
||||
ModeStoreProvider, ModeStoreVec, SequenceModeTables, SequenceTableEntry,
|
||||
SequenceTableMapTable, SequenceTablesMapValue,
|
||||
},
|
||||
queue::GenericTargetedMessagingError,
|
||||
request::RequestId,
|
||||
subsystem::{ModeCommandingResult, SequenceExecutionHelperState},
|
||||
ComponentId,
|
||||
};
|
||||
|
||||
use super::SequenceExecutionHelper;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExampleTargetId {
|
||||
Target0 = 1,
|
||||
Target1 = 2,
|
||||
Target2 = 3,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExampleMode {
|
||||
Mode0 = 1,
|
||||
Mode1 = 2,
|
||||
Mode2 = 3,
|
||||
}
|
||||
|
||||
pub struct ModeReqWrapper {
|
||||
pub request_id: RequestId,
|
||||
pub target_id: ComponentId,
|
||||
pub request: ModeRequest,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ModeReqSenderMock {
|
||||
pub requests: RefCell<VecDeque<ModeReqWrapper>>,
|
||||
}
|
||||
|
||||
impl ModeRequestSender for ModeReqSenderMock {
|
||||
fn local_channel_id(&self) -> crate::ComponentId {
|
||||
0
|
||||
}
|
||||
|
||||
fn send_mode_request(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
target_id: ComponentId,
|
||||
request: ModeRequest,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.requests.borrow_mut().push_back(ModeReqWrapper {
|
||||
request_id,
|
||||
target_id,
|
||||
request,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SequenceExecutorTestbench {
|
||||
pub sender: ModeReqSenderMock,
|
||||
pub mode_store: ModeStoreVec,
|
||||
pub seq_table: SequenceModeTables,
|
||||
pub execution_helper: SequenceExecutionHelper,
|
||||
}
|
||||
|
||||
impl SequenceExecutorTestbench {
|
||||
pub fn new() -> Self {
|
||||
let mode_store = create_default_mode_store();
|
||||
let seq_table = create_simple_sample_seq_table(false, false);
|
||||
Self {
|
||||
sender: ModeReqSenderMock::default(),
|
||||
mode_store,
|
||||
seq_table,
|
||||
execution_helper: SequenceExecutionHelper::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mode_table(&mut self, mode: ExampleMode) -> &mut SequenceTablesMapValue {
|
||||
self.seq_table.0.get_mut(&(mode as Mode)).unwrap()
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<ModeCommandingResult, GenericTargetedMessagingError> {
|
||||
self.execution_helper
|
||||
.run(&self.seq_table, &self.sender, &mut self.mode_store)
|
||||
}
|
||||
|
||||
fn check_run_is_no_op(&mut self) {
|
||||
// Assure that no unexpected behaviour occurs.
|
||||
assert_eq!(
|
||||
self.execution_helper
|
||||
.run(&self.seq_table, &self.sender, &mut self.mode_store)
|
||||
.unwrap(),
|
||||
ModeCommandingResult::Done
|
||||
);
|
||||
assert_eq!(
|
||||
self.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Idle
|
||||
);
|
||||
assert!(self.sender.requests.borrow().is_empty());
|
||||
}
|
||||
|
||||
fn generic_checks_subsystem_md1_step0(&mut self, expected_req_id: RequestId) {
|
||||
assert_eq!(
|
||||
self.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode1 as Mode
|
||||
);
|
||||
assert_eq!(self.sender.requests.borrow().len(), 2);
|
||||
let req_0 = self.sender.requests.get_mut().pop_front().unwrap();
|
||||
assert_eq!(req_0.target_id, ExampleTargetId::Target0 as u64);
|
||||
assert_eq!(req_0.request_id, expected_req_id);
|
||||
assert_eq!(
|
||||
req_0.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: SUBSYSTEM_MD1_ST0_TGT0_MODE,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
let req_1 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req_1.target_id, ExampleTargetId::Target1 as u64);
|
||||
assert_eq!(
|
||||
req_1.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: SUBSYSTEM_MD1_ST0_TGT1_MODE,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
}
|
||||
fn generic_checks_subsystem_md1_step1(&mut self, expected_req_id: RequestId) {
|
||||
assert_eq!(
|
||||
self.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode1 as Mode
|
||||
);
|
||||
assert_eq!(self.sender.requests.borrow().len(), 1);
|
||||
let req_0 = self.sender.requests.get_mut().pop_front().unwrap();
|
||||
assert_eq!(req_0.target_id, ExampleTargetId::Target2 as u64);
|
||||
assert_eq!(req_0.request_id, expected_req_id);
|
||||
assert_eq!(
|
||||
req_0.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: SUBSYSTEM_MD1_ST1_TGT2_MODE,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn generic_checks_subsystem_md0(&mut self, expected_req_id: RequestId) {
|
||||
assert_eq!(
|
||||
self.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode0 as Mode
|
||||
);
|
||||
assert_eq!(self.execution_helper.current_sequence_index().unwrap(), 0);
|
||||
assert_eq!(self.sender.requests.borrow().len(), 2);
|
||||
let req_0 = self.sender.requests.get_mut().pop_front().unwrap();
|
||||
assert_eq!(req_0.target_id, ExampleTargetId::Target0 as u64);
|
||||
assert_eq!(req_0.request_id, expected_req_id);
|
||||
assert_eq!(
|
||||
req_0.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: SUBSYSTEM_MD0_TGT_0_MODE,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
let req_1 = self.sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req_1.target_id, ExampleTargetId::Target1 as u64);
|
||||
assert_eq!(
|
||||
req_1.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: SUBSYSTEM_MD0_TGT_1_MODE,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_default_mode_store() -> ModeStoreVec {
|
||||
let mut mode_store = ModeStoreVec::default();
|
||||
mode_store.add_component(ExampleTargetId::Target0 as u64, UNKNOWN_MODE);
|
||||
mode_store.add_component(ExampleTargetId::Target1 as u64, UNKNOWN_MODE);
|
||||
mode_store.add_component(ExampleTargetId::Target2 as u64, UNKNOWN_MODE);
|
||||
mode_store
|
||||
}
|
||||
|
||||
fn create_simple_sample_seq_table(
|
||||
success_check_tgt0: bool,
|
||||
success_check_tgt1: bool,
|
||||
) -> SequenceModeTables {
|
||||
let mut table = SequenceModeTables::default();
|
||||
// Mode 0 - One step command
|
||||
let mut table_val = SequenceTablesMapValue::new("MODE_0");
|
||||
let mut table_seq_0 = SequenceTableMapTable::new("MODE_0_SEQ_0");
|
||||
table_seq_0.add_entry(SequenceTableEntry::new(
|
||||
"TARGET_0",
|
||||
ExampleTargetId::Target0 as u64,
|
||||
SUBSYSTEM_MD0_TGT_0_MODE,
|
||||
success_check_tgt0,
|
||||
));
|
||||
table_seq_0.add_entry(SequenceTableEntry::new(
|
||||
"TARGET_1",
|
||||
ExampleTargetId::Target1 as u64,
|
||||
SUBSYSTEM_MD0_TGT_1_MODE,
|
||||
success_check_tgt1,
|
||||
));
|
||||
table_val.add_sequence_table(table_seq_0);
|
||||
table.0.insert(ExampleMode::Mode0 as u32, table_val);
|
||||
|
||||
// Mode 1 - Multi Step command
|
||||
let mut table_val = SequenceTablesMapValue::new("MODE_1");
|
||||
let mut table_seq_0 = SequenceTableMapTable::new("MODE_1_SEQ_0");
|
||||
table_seq_0.add_entry(SequenceTableEntry::new(
|
||||
"MD1_SEQ0_TGT0",
|
||||
ExampleTargetId::Target0 as u64,
|
||||
SUBSYSTEM_MD1_ST0_TGT0_MODE,
|
||||
false,
|
||||
));
|
||||
table_seq_0.add_entry(SequenceTableEntry::new(
|
||||
"MD1_SEQ0_TGT1",
|
||||
ExampleTargetId::Target1 as u64,
|
||||
SUBSYSTEM_MD1_ST0_TGT1_MODE,
|
||||
false,
|
||||
));
|
||||
table_val.add_sequence_table(table_seq_0);
|
||||
let mut table_seq_1 = SequenceTableMapTable::new("MODE_1_SEQ_1");
|
||||
table_seq_1.add_entry(SequenceTableEntry::new(
|
||||
"MD1_SEQ1_TGT2",
|
||||
ExampleTargetId::Target2 as u64,
|
||||
SUBSYSTEM_MD1_ST1_TGT2_MODE,
|
||||
false,
|
||||
));
|
||||
table_val.add_sequence_table(table_seq_1);
|
||||
table.0.insert(ExampleMode::Mode1 as u32, table_val);
|
||||
table
|
||||
}
|
||||
|
||||
const SUBSYSTEM_MD0_TGT_0_MODE: ModeAndSubmode =
|
||||
ModeAndSubmode::new(ExampleMode::Mode0 as u32, 0);
|
||||
const SUBSYSTEM_MD0_TGT_1_MODE: ModeAndSubmode =
|
||||
ModeAndSubmode::new(ExampleMode::Mode1 as u32, 0);
|
||||
|
||||
const SUBSYSTEM_MD1_ST0_TGT0_MODE: ModeAndSubmode =
|
||||
ModeAndSubmode::new(ExampleMode::Mode2 as u32, 0);
|
||||
const SUBSYSTEM_MD1_ST0_TGT1_MODE: ModeAndSubmode =
|
||||
ModeAndSubmode::new(ExampleMode::Mode0 as u32, 0);
|
||||
const SUBSYSTEM_MD1_ST1_TGT2_MODE: ModeAndSubmode =
|
||||
ModeAndSubmode::new(ExampleMode::Mode1 as u32, 0);
|
||||
|
||||
#[test]
|
||||
fn test_init_state() {
|
||||
let execution_helper = SequenceExecutionHelper::new();
|
||||
assert_eq!(execution_helper.state(), SequenceExecutionHelperState::Idle);
|
||||
assert!(!execution_helper.awaiting_success_check());
|
||||
assert!(execution_helper.target_mode().is_none());
|
||||
assert!(execution_helper.current_sequence_index().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_execution_helper_no_success_check() {
|
||||
let mut tb = SequenceExecutorTestbench::new();
|
||||
let expected_req_id = 1;
|
||||
tb.execution_helper
|
||||
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_table)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Busy
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
assert_eq!(
|
||||
tb.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode0 as Mode
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper
|
||||
.run(&tb.seq_table, &tb.sender, &mut tb.mode_store)
|
||||
.expect("sequence exeecution helper run failure"),
|
||||
ModeCommandingResult::Done
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Idle
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||
tb.check_run_is_no_op();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_execution_helper_with_success_check() {
|
||||
let mut tb = SequenceExecutorTestbench::new();
|
||||
let mode0_table = tb.get_mode_table(ExampleMode::Mode0);
|
||||
mode0_table.entries[0].entries[0].check_success = true;
|
||||
mode0_table.entries[0].entries[1].check_success = true;
|
||||
let expected_req_id = 1;
|
||||
tb.execution_helper
|
||||
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_table)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Busy
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
assert_eq!(
|
||||
tb.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode0 as Mode
|
||||
);
|
||||
assert_eq!(
|
||||
tb.run().expect("sequence exeecution helper run failure"),
|
||||
ModeCommandingResult::AwaitingSuccessCheck
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
);
|
||||
// These are not cleared, even if the execution helper is already IDLE. This is okay for
|
||||
// now.
|
||||
assert!(tb.execution_helper.awaiting_success_check());
|
||||
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||
tb.execution_helper.confirm_sequence_done();
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Idle
|
||||
);
|
||||
|
||||
tb.check_run_is_no_op();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_execution_helper_with_partial_check() {
|
||||
let mut tb = SequenceExecutorTestbench::new();
|
||||
let mode0_table = tb.get_mode_table(ExampleMode::Mode0);
|
||||
mode0_table.entries[0].entries[0].check_success = true;
|
||||
let expected_req_id = 1;
|
||||
tb.execution_helper
|
||||
.load(ExampleMode::Mode0 as u32, expected_req_id, &tb.seq_table)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Busy
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
assert_eq!(
|
||||
tb.run().expect("sequence execution helper run failure"),
|
||||
ModeCommandingResult::AwaitingSuccessCheck
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
);
|
||||
// These are not cleared, even if the execution helper is already IDLE. This is okay for
|
||||
// now.
|
||||
assert!(tb.execution_helper.awaiting_success_check());
|
||||
tb.generic_checks_subsystem_md0(expected_req_id);
|
||||
tb.execution_helper.confirm_sequence_done();
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Idle
|
||||
);
|
||||
tb.check_run_is_no_op();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_execution_helper_multi_step_no_success_check() {
|
||||
let mut tb = SequenceExecutorTestbench::new();
|
||||
let expected_req_id = 1;
|
||||
tb.execution_helper
|
||||
.load(ExampleMode::Mode1 as u32, expected_req_id, &tb.seq_table)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Busy
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
assert_eq!(
|
||||
tb.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode1 as Mode
|
||||
);
|
||||
assert_eq!(
|
||||
tb.run().expect("sequence execution helper run failure"),
|
||||
ModeCommandingResult::StepDone
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Busy
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
tb.generic_checks_subsystem_md1_step0(expected_req_id);
|
||||
assert_eq!(tb.execution_helper.current_sequence_index().unwrap(), 1);
|
||||
|
||||
assert_eq!(
|
||||
tb.run().expect("sequence execution helper run failure"),
|
||||
ModeCommandingResult::Done
|
||||
);
|
||||
tb.generic_checks_subsystem_md1_step1(expected_req_id);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Idle
|
||||
);
|
||||
tb.check_run_is_no_op();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sequence_execution_helper_multi_step_full_success_check() {
|
||||
let mut tb = SequenceExecutorTestbench::new();
|
||||
let expected_req_id = 1;
|
||||
tb.execution_helper
|
||||
.load(ExampleMode::Mode1 as u32, expected_req_id, &tb.seq_table)
|
||||
.unwrap();
|
||||
let mode1_table = tb.get_mode_table(ExampleMode::Mode1);
|
||||
mode1_table.entries[0].entries[0].check_success = true;
|
||||
mode1_table.entries[0].entries[1].check_success = true;
|
||||
mode1_table.entries[1].entries[0].check_success = true;
|
||||
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::Busy
|
||||
);
|
||||
assert!(!tb.execution_helper.awaiting_success_check());
|
||||
assert_eq!(
|
||||
tb.execution_helper.target_mode().unwrap(),
|
||||
ExampleMode::Mode1 as Mode
|
||||
);
|
||||
assert_eq!(
|
||||
tb.run().expect("sequence execution helper run failure"),
|
||||
ModeCommandingResult::AwaitingSuccessCheck
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
);
|
||||
assert!(tb.execution_helper.awaiting_success_check());
|
||||
tb.generic_checks_subsystem_md1_step0(expected_req_id);
|
||||
assert_eq!(tb.execution_helper.current_sequence_index().unwrap(), 0);
|
||||
tb.execution_helper.confirm_sequence_done();
|
||||
|
||||
assert_eq!(
|
||||
tb.run().expect("sequence execution helper run failure"),
|
||||
ModeCommandingResult::AwaitingSuccessCheck
|
||||
);
|
||||
assert_eq!(
|
||||
tb.execution_helper.state(),
|
||||
SequenceExecutionHelperState::AwaitingSuccessCheck
|
||||
);
|
||||
assert!(tb.execution_helper.awaiting_success_check());
|
||||
assert_eq!(tb.execution_helper.current_sequence_index().unwrap(), 1);
|
||||
tb.generic_checks_subsystem_md1_step1(expected_req_id);
|
||||
tb.execution_helper.confirm_sequence_done();
|
||||
tb.check_run_is_no_op();
|
||||
}
|
||||
|
||||
// TODO: Test subsystem commanding helper
|
||||
}
|
@ -17,37 +17,37 @@ impl PusTmWithCdsShortHelper {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub fn create_pus_tm_timestamp_now<'a>(
|
||||
&'a mut self,
|
||||
pub fn create_pus_tm_timestamp_now<'time, 'src_data>(
|
||||
&'time mut self,
|
||||
service: u8,
|
||||
subservice: u8,
|
||||
source_data: &'a [u8],
|
||||
source_data: &'src_data [u8],
|
||||
seq_count: u16,
|
||||
) -> PusTmCreator {
|
||||
) -> PusTmCreator<'time, 'src_data> {
|
||||
let time_stamp = CdsTime::now_with_u16_days().unwrap();
|
||||
time_stamp.write_to_bytes(&mut self.cds_short_buf).unwrap();
|
||||
self.create_pus_tm_common(service, subservice, source_data, seq_count)
|
||||
}
|
||||
|
||||
pub fn create_pus_tm_with_stamper<'a>(
|
||||
&'a mut self,
|
||||
pub fn create_pus_tm_with_stamper<'time, 'src_data>(
|
||||
&'time mut self,
|
||||
service: u8,
|
||||
subservice: u8,
|
||||
source_data: &'a [u8],
|
||||
source_data: &'src_data [u8],
|
||||
stamper: &CdsTime,
|
||||
seq_count: u16,
|
||||
) -> PusTmCreator {
|
||||
) -> PusTmCreator<'time, 'src_data> {
|
||||
stamper.write_to_bytes(&mut self.cds_short_buf).unwrap();
|
||||
self.create_pus_tm_common(service, subservice, source_data, seq_count)
|
||||
}
|
||||
|
||||
fn create_pus_tm_common<'a>(
|
||||
&'a self,
|
||||
fn create_pus_tm_common<'time, 'src_data>(
|
||||
&'time self,
|
||||
service: u8,
|
||||
subservice: u8,
|
||||
source_data: &'a [u8],
|
||||
source_data: &'src_data [u8],
|
||||
seq_count: u16,
|
||||
) -> PusTmCreator {
|
||||
) -> PusTmCreator<'time, 'src_data> {
|
||||
let reply_header = SpHeader::new_for_unseg_tm(self.apid, seq_count, 0);
|
||||
let tc_header = PusTmSecondaryHeader::new_simple(service, subservice, &self.cds_short_buf);
|
||||
PusTmCreator::new(reply_header, tc_header, source_data, true)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,6 @@ use satrs::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
|
||||
use satrs::params::U32Pair;
|
||||
use satrs::params::{Params, ParamsHeapless, WritableToBeBytes};
|
||||
use satrs::pus::event_man::{DefaultPusEventReportingMap, EventReporter, PusEventTmCreatorWithMap};
|
||||
use satrs::pus::test_util::TEST_COMPONENT_ID_0;
|
||||
use satrs::request::UniqueApidTargetId;
|
||||
use satrs::tmtc::PacketAsVec;
|
||||
use spacepackets::ecss::tm::PusTmReader;
|
||||
@ -100,10 +99,7 @@ fn test_threaded_usage() {
|
||||
// Event sender and TM checker thread
|
||||
let jh1 = thread::spawn(move || {
|
||||
event_tx
|
||||
.send(EventMessage::new(
|
||||
TEST_COMPONENT_ID_0.id(),
|
||||
INFO_EVENT.into(),
|
||||
))
|
||||
.send(EventMessage::new(TEST_ID.id(), INFO_EVENT.into()))
|
||||
.expect("Sending info event failed");
|
||||
loop {
|
||||
match event_packet_rx.try_recv() {
|
||||
@ -130,7 +126,7 @@ fn test_threaded_usage() {
|
||||
}
|
||||
event_tx
|
||||
.send(EventMessage::new_with_params(
|
||||
TEST_COMPONENT_ID_0.id(),
|
||||
TEST_ID.id(),
|
||||
LOW_SEV_EVENT,
|
||||
&Params::Heapless((2_u32, 3_u32).into()),
|
||||
))
|
||||
|
Loading…
x
Reference in New Issue
Block a user