Mode Tree Feature Update
This commit is contained in:
parent
1a1d330814
commit
474afc37ca
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]
|
||||
|
@ -20,6 +20,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
- `StaticHeaplessMemoryPool` which can be grown with user-provided static buffers.
|
||||
- Scheduling table for systems with a standard runtime
|
||||
- Mode Tree Feature which allows building a network of mode components which can send mode
|
||||
messages to each other.
|
||||
- Added first helper features like the `SubsystemExecutionHelper` and the
|
||||
`SubsystemCommandingHelper` which allows to build subsystem components. Subsystem components
|
||||
are able to execute mode sequences and perform target keeping based on a declarative table
|
||||
format.
|
||||
- Added `DevManagerCommandingHelper` which performs some of the boilerplate logik required
|
||||
by Assembly and Device Management components. This includes forwarding mode requests and
|
||||
handling mode replies.
|
||||
- First basic health module with `HealthState`s and the `HealthTableProvider` trait. These
|
||||
components are important for any FDIR components which get added in the future.
|
||||
|
||||
# [v0.2.1] 2024-05-19
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
name = "satrs"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
rust-version = "1.71.1"
|
||||
rust-version = "1.82.0"
|
||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||
description = "A framework to build software for remote systems"
|
||||
homepage = "https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/"
|
||||
|
448
satrs/src/dev_mgmt.rs
Normal file
448
satrs/src/dev_mgmt.rs
Normal file
@ -0,0 +1,448 @@
|
||||
use crate::{
|
||||
mode::{ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender},
|
||||
mode_tree::{ModeStoreProvider, ModeStoreVec},
|
||||
queue::{GenericSendError, GenericTargetedMessagingError},
|
||||
request::{GenericMessage, RequestId},
|
||||
ComponentId,
|
||||
};
|
||||
use core::fmt::Debug;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ActiveModeCommandContext {
|
||||
pub target_mode: ModeAndSubmode,
|
||||
pub active_request_id: RequestId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub enum DevManagerHelperResult {
|
||||
#[default]
|
||||
Idle,
|
||||
Busy,
|
||||
ModeCommandingDone(ActiveModeCommandContext),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DevManagerHelperError {
|
||||
ChildNotInStore,
|
||||
}
|
||||
|
||||
pub trait DevManagerUserHook: Debug {
|
||||
fn send_mode_cmd_to_child(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
target_id: ComponentId,
|
||||
mode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
children_mode_store: &mut ModeStoreVec,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
) -> Result<(), GenericTargetedMessagingError>;
|
||||
|
||||
fn send_mode_cmds_to_children(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
commanded_parent_mode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
children_mode_store: &mut ModeStoreVec,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
) -> Result<(), GenericTargetedMessagingError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TransparentDevManagerHook {}
|
||||
|
||||
impl DevManagerUserHook for TransparentDevManagerHook {
|
||||
fn send_mode_cmds_to_children(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
commanded_parent_mode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
children_mode_store: &mut ModeStoreVec,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
for child in children_mode_store {
|
||||
mode_req_sender.send_mode_request(
|
||||
request_id,
|
||||
child.id(),
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: commanded_parent_mode,
|
||||
forced,
|
||||
},
|
||||
)?;
|
||||
child.awaiting_reply = true;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_mode_cmd_to_child(
|
||||
&self,
|
||||
request_id: RequestId,
|
||||
target_id: ComponentId,
|
||||
mode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
children_mode_store: &mut ModeStoreVec,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
let mut_val = children_mode_store
|
||||
.get_mut(target_id)
|
||||
.ok_or(GenericSendError::TargetDoesNotExist(target_id))?;
|
||||
mut_val.awaiting_reply = true;
|
||||
mode_req_sender.send_mode_request(
|
||||
request_id,
|
||||
target_id,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: mode,
|
||||
forced,
|
||||
},
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DevManagerCommandingState {
|
||||
#[default]
|
||||
Idle,
|
||||
AwaitingReplies(ActiveModeCommandContext),
|
||||
}
|
||||
|
||||
impl DevManagerCommandingState {
|
||||
fn new_active_cmd(mode_and_submode: ModeAndSubmode, active_request_id: RequestId) -> Self {
|
||||
DevManagerCommandingState::AwaitingReplies(ActiveModeCommandContext {
|
||||
target_mode: mode_and_submode,
|
||||
active_request_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic helper for manager components which manage child components in a mode tree.
|
||||
///
|
||||
/// 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 DevManagerCommandingHelper<UserHook: DevManagerUserHook> {
|
||||
/// The IDs, modes and reply awaition status of all children are tracked in this data
|
||||
/// structure.
|
||||
pub children_mode_store: ModeStoreVec,
|
||||
pub user_hook: UserHook,
|
||||
pub state: DevManagerCommandingState,
|
||||
}
|
||||
|
||||
impl<UserHook: DevManagerUserHook> DevManagerCommandingHelper<UserHook> {
|
||||
pub fn new(user_hook: UserHook) -> Self {
|
||||
Self {
|
||||
children_mode_store: Default::default(),
|
||||
user_hook,
|
||||
state: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_mode_cmd_to_one_child(
|
||||
&mut self,
|
||||
request_id: RequestId,
|
||||
target_id: ComponentId,
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.state = DevManagerCommandingState::new_active_cmd(mode_and_submode, request_id);
|
||||
self.user_hook.send_mode_cmd_to_child(
|
||||
request_id,
|
||||
target_id,
|
||||
mode_and_submode,
|
||||
forced,
|
||||
&mut self.children_mode_store,
|
||||
mode_req_sender,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_mode_cmd_to_all_children(
|
||||
&mut self,
|
||||
request_id: RequestId,
|
||||
mode_and_submode: ModeAndSubmode,
|
||||
forced: bool,
|
||||
mode_req_sender: &impl ModeRequestSender,
|
||||
) -> Result<(), GenericTargetedMessagingError> {
|
||||
self.state = DevManagerCommandingState::new_active_cmd(mode_and_submode, request_id);
|
||||
self.user_hook.send_mode_cmds_to_children(
|
||||
request_id,
|
||||
mode_and_submode,
|
||||
forced,
|
||||
&mut self.children_mode_store,
|
||||
mode_req_sender,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn target_mode(&self) -> Option<ModeAndSubmode> {
|
||||
match self.state {
|
||||
DevManagerCommandingState::Idle => None,
|
||||
DevManagerCommandingState::AwaitingReplies(context) => Some(context.target_mode),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state(&self) -> DevManagerCommandingState {
|
||||
self.state
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/// Helper method which counts the number of children which have a certain mode.
|
||||
pub fn count_number_of_children_with_mode(&self, mode_and_submode: ModeAndSubmode) -> usize {
|
||||
let mut children_in_target_mode = 0;
|
||||
for child in &self.children_mode_store {
|
||||
if child.mode_and_submode() == mode_and_submode {
|
||||
children_in_target_mode += 1;
|
||||
}
|
||||
}
|
||||
children_in_target_mode
|
||||
}
|
||||
|
||||
pub fn handle_mode_reply(
|
||||
&mut self,
|
||||
mode_reply: &GenericMessage<ModeReply>,
|
||||
) -> Result<DevManagerHelperResult, DevManagerHelperError> {
|
||||
let context = match self.state {
|
||||
DevManagerCommandingState::Idle => return Ok(DevManagerHelperResult::Idle),
|
||||
DevManagerCommandingState::AwaitingReplies(active_mode_command_context) => {
|
||||
Some(active_mode_command_context)
|
||||
}
|
||||
};
|
||||
if !self
|
||||
.children_mode_store
|
||||
.has_component(mode_reply.sender_id())
|
||||
{
|
||||
return Err(DevManagerHelperError::ChildNotInStore);
|
||||
}
|
||||
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 let DevManagerCommandingState::AwaitingReplies { .. } = self.state {
|
||||
handle_awaition = true;
|
||||
}
|
||||
let still_awating_replies = self.children_mode_store.mode_reply_handler(
|
||||
mode_reply.sender_id(),
|
||||
mode_and_submode,
|
||||
handle_awaition,
|
||||
);
|
||||
// It is okay to unwrap: If awaition should be handled, the returned value should
|
||||
// always be some valid value.
|
||||
if handle_awaition && !still_awating_replies.unwrap() {
|
||||
self.state = DevManagerCommandingState::Idle;
|
||||
return Ok(DevManagerHelperResult::ModeCommandingDone(context.unwrap()));
|
||||
}
|
||||
Ok(DevManagerHelperResult::Busy)
|
||||
};
|
||||
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 {
|
||||
use crate::{
|
||||
mode::{tests::ModeReqSenderMock, UNKNOWN_MODE},
|
||||
request::MessageMetadata,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub enum ExampleId {
|
||||
Id1 = 1,
|
||||
Id2 = 2,
|
||||
}
|
||||
|
||||
pub enum ExampleMode {
|
||||
Mode1 = 1,
|
||||
Mode2 = 2,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basic() {
|
||||
let assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default());
|
||||
assert_eq!(assy_helper.state(), DevManagerCommandingState::Idle);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mode_announce() {
|
||||
let mut assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default());
|
||||
let mode_req_sender = ModeReqSenderMock::default();
|
||||
assy_helper.add_mode_child(ExampleId::Id1 as u64, UNKNOWN_MODE);
|
||||
assy_helper.add_mode_child(ExampleId::Id2 as u64, UNKNOWN_MODE);
|
||||
assy_helper
|
||||
.send_announce_mode_cmd_to_children(1, &mode_req_sender, false)
|
||||
.unwrap();
|
||||
assert_eq!(mode_req_sender.requests.borrow().len(), 2);
|
||||
let mut req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id1 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(req.request, ModeRequest::AnnounceMode);
|
||||
req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id2 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(req.request, ModeRequest::AnnounceMode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mode_announce_recursive() {
|
||||
let mut assy_helper = DevManagerCommandingHelper::new(TransparentDevManagerHook::default());
|
||||
let mode_req_sender = ModeReqSenderMock::default();
|
||||
assy_helper.add_mode_child(ExampleId::Id1 as u64, UNKNOWN_MODE);
|
||||
assy_helper.add_mode_child(ExampleId::Id2 as u64, UNKNOWN_MODE);
|
||||
assy_helper
|
||||
.send_announce_mode_cmd_to_children(1, &mode_req_sender, true)
|
||||
.unwrap();
|
||||
assert_eq!(mode_req_sender.requests.borrow().len(), 2);
|
||||
let mut req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id1 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(req.request, ModeRequest::AnnounceModeRecursive);
|
||||
req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id2 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(req.request, ModeRequest::AnnounceModeRecursive);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mode_commanding_one_child() {
|
||||
let mut dev_mgmt_helper =
|
||||
DevManagerCommandingHelper::new(TransparentDevManagerHook::default());
|
||||
let mode_req_sender = ModeReqSenderMock::default();
|
||||
dev_mgmt_helper.add_mode_child(ExampleId::Id1 as u64, UNKNOWN_MODE);
|
||||
let expected_mode = ModeAndSubmode::new(ExampleMode::Mode1 as u32, 0);
|
||||
dev_mgmt_helper
|
||||
.send_mode_cmd_to_one_child(
|
||||
1,
|
||||
ExampleId::Id1 as u64,
|
||||
expected_mode,
|
||||
false,
|
||||
&mode_req_sender,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(mode_req_sender.requests.borrow().len(), 1);
|
||||
let req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id1 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(
|
||||
req.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: expected_mode,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
matches!(
|
||||
dev_mgmt_helper.state(),
|
||||
DevManagerCommandingState::AwaitingReplies { .. }
|
||||
);
|
||||
if let DevManagerCommandingState::AwaitingReplies(ctx) = dev_mgmt_helper.state() {
|
||||
assert_eq!(ctx.target_mode, expected_mode);
|
||||
assert_eq!(ctx.active_request_id, 1);
|
||||
}
|
||||
let reply = GenericMessage::new(
|
||||
MessageMetadata::new(1, ExampleId::Id1 as u64),
|
||||
ModeReply::ModeReply(expected_mode),
|
||||
);
|
||||
if let DevManagerHelperResult::ModeCommandingDone(ActiveModeCommandContext {
|
||||
target_mode,
|
||||
active_request_id,
|
||||
}) = dev_mgmt_helper.handle_mode_reply(&reply).unwrap()
|
||||
{
|
||||
assert_eq!(target_mode, expected_mode);
|
||||
assert_eq!(active_request_id, 1);
|
||||
}
|
||||
matches!(dev_mgmt_helper.state(), DevManagerCommandingState::Idle);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mode_commanding_multi_child() {
|
||||
let mut dev_mgmt_helper =
|
||||
DevManagerCommandingHelper::new(TransparentDevManagerHook::default());
|
||||
let mode_req_sender = ModeReqSenderMock::default();
|
||||
dev_mgmt_helper.add_mode_child(ExampleId::Id1 as u64, UNKNOWN_MODE);
|
||||
dev_mgmt_helper.add_mode_child(ExampleId::Id2 as u64, UNKNOWN_MODE);
|
||||
let expected_mode = ModeAndSubmode::new(ExampleMode::Mode2 as u32, 0);
|
||||
dev_mgmt_helper
|
||||
.send_mode_cmd_to_all_children(1, expected_mode, false, &mode_req_sender)
|
||||
.unwrap();
|
||||
assert_eq!(mode_req_sender.requests.borrow().len(), 2);
|
||||
let req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id1 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(
|
||||
req.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: expected_mode,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
let req = mode_req_sender.requests.borrow_mut().pop_front().unwrap();
|
||||
assert_eq!(req.target_id, ExampleId::Id2 as u64);
|
||||
assert_eq!(req.request_id, 1);
|
||||
assert_eq!(
|
||||
req.request,
|
||||
ModeRequest::SetMode {
|
||||
mode_and_submode: expected_mode,
|
||||
forced: false
|
||||
}
|
||||
);
|
||||
matches!(
|
||||
dev_mgmt_helper.state(),
|
||||
DevManagerCommandingState::AwaitingReplies { .. }
|
||||
);
|
||||
if let DevManagerCommandingState::AwaitingReplies(ctx) = dev_mgmt_helper.state() {
|
||||
assert_eq!(ctx.target_mode, expected_mode);
|
||||
assert_eq!(ctx.active_request_id, 1);
|
||||
}
|
||||
|
||||
let reply = GenericMessage::new(
|
||||
MessageMetadata::new(1, ExampleId::Id1 as u64),
|
||||
ModeReply::ModeReply(expected_mode),
|
||||
);
|
||||
assert_eq!(
|
||||
dev_mgmt_helper.handle_mode_reply(&reply).unwrap(),
|
||||
DevManagerHelperResult::Busy
|
||||
);
|
||||
let reply = GenericMessage::new(
|
||||
MessageMetadata::new(1, ExampleId::Id2 as u64),
|
||||
ModeReply::ModeReply(expected_mode),
|
||||
);
|
||||
if let DevManagerHelperResult::ModeCommandingDone(ActiveModeCommandContext {
|
||||
target_mode,
|
||||
active_request_id,
|
||||
}) = dev_mgmt_helper.handle_mode_reply(&reply).unwrap()
|
||||
{
|
||||
assert_eq!(target_mode, expected_mode);
|
||||
assert_eq!(active_request_id, 1);
|
||||
}
|
||||
matches!(dev_mgmt_helper.state(), DevManagerCommandingState::Idle);
|
||||
}
|
||||
}
|
39
satrs/src/health.rs
Normal file
39
satrs/src/health.rs
Normal file
@ -0,0 +1,39 @@
|
||||
use crate::ComponentId;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum HealthState {
|
||||
Healthy = 1,
|
||||
Faulty = 2,
|
||||
PermanentFaulty = 3,
|
||||
ExternalControl = 4,
|
||||
NeedsRecovery = 5,
|
||||
}
|
||||
|
||||
pub trait HealthTableProvider {
|
||||
fn health(&self, id: ComponentId) -> Option<HealthState>;
|
||||
fn set_health(&mut self, id: ComponentId, health: HealthState);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HealthTableMapSync(
|
||||
std::sync::Arc<std::sync::Mutex<hashbrown::HashMap<ComponentId, HealthState>>>,
|
||||
);
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl HealthTableMapSync {
|
||||
pub fn new(health_table: hashbrown::HashMap<ComponentId, HealthState>) -> Self {
|
||||
Self(std::sync::Arc::new(std::sync::Mutex::new(health_table)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl HealthTableProvider for HealthTableMapSync {
|
||||
fn health(&self, id: ComponentId) -> Option<HealthState> {
|
||||
self.0.lock().unwrap().get(&id).copied()
|
||||
}
|
||||
|
||||
fn set_health(&mut self, id: ComponentId, health: HealthState) {
|
||||
self.0.lock().unwrap().insert(id, health);
|
||||
}
|
||||
}
|
@ -22,14 +22,21 @@ 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 health;
|
||||
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;
|
||||
@ -38,14 +45,11 @@ pub mod request;
|
||||
pub mod res_code;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod scheduling;
|
||||
#[cfg(feature = "alloc")]
|
||||
pub mod subsystem;
|
||||
pub mod time;
|
||||
pub mod tmtc;
|
||||
|
||||
pub mod action;
|
||||
pub mod hk;
|
||||
pub mod mode;
|
||||
pub mod params;
|
||||
|
||||
pub use spacepackets;
|
||||
|
||||
use spacepackets::PacketId;
|
||||
|
@ -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,11 @@ pub struct ModeAndSubmode {
|
||||
submode: Submode,
|
||||
}
|
||||
|
||||
pub const INVALID_MODE_VAL: Mode = Mode::MAX;
|
||||
pub const UNKNOWN_MODE_VAL: Mode = Mode::MAX - 1;
|
||||
pub const INVALID_MODE: ModeAndSubmode = ModeAndSubmode::new(INVALID_MODE_VAL, 0);
|
||||
pub const UNKNOWN_MODE: ModeAndSubmode = ModeAndSubmode::new(UNKNOWN_MODE_VAL, 0);
|
||||
|
||||
impl ModeAndSubmode {
|
||||
pub const RAW_LEN: usize = size_of::<Mode>() + size_of::<Submode>();
|
||||
|
||||
@ -111,7 +118,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 +137,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 +168,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 +178,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 +205,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 +232,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 +259,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 +283,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 +304,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 +321,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 +329,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 +345,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 +398,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 +436,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 +466,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 +493,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 +526,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 +541,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 +559,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 +568,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 +623,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 +632,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,39 +663,97 @@ 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>>>,
|
||||
>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {}
|
||||
pub(crate) mod tests {
|
||||
use core::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::{request::RequestId, ComponentId};
|
||||
|
||||
use super::*;
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,553 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
pub type ModeTable = HashMap<Mode, ModeTableMapValue>;
|
||||
delegate::delegate! {
|
||||
to self.common {
|
||||
pub fn set_allowed_submode_mask(&mut self, mask: Submode);
|
||||
pub fn allowed_submode_mask(&self) -> Option<Submode>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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>);
|
||||
|
||||
impl TargetModeTables {
|
||||
pub fn name(&self, mode: Mode) -> Option<&'static str> {
|
||||
self.0.get(&mode).map(|value| value.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl SequenceModeTables {
|
||||
pub fn name(&self, mode: Mode) -> Option<&'static str> {
|
||||
self.0.get(&mode).map(|value| value.name)
|
||||
}
|
||||
|
||||
pub fn name_of_sequence(&self, mode: Mode, seq_idx: usize) -> Option<&'static str> {
|
||||
self.0
|
||||
.get(&mode)
|
||||
.map(|value| value.entries.get(seq_idx).map(|v| v.name))?
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>);
|
||||
|
||||
impl<'a> IntoIterator for &'a ModeStoreVec {
|
||||
type Item = &'a ModeStoreValue;
|
||||
type IntoIter = std::slice::Iter<'a, ModeStoreValue>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a mut ModeStoreVec {
|
||||
type Item = &'a mut ModeStoreValue;
|
||||
type IntoIter = std::slice::IterMut<'a, ModeStoreValue>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// Mode store which tracks the mode information inside a [hashbrown::HashMap]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ModeStoreMap(pub hashbrown::HashMap<ComponentId, ModeStoreValue>);
|
||||
|
||||
impl<'a> IntoIterator for &'a ModeStoreMap {
|
||||
type Item = (&'a ComponentId, &'a ModeStoreValue);
|
||||
type IntoIter = hashbrown::hash_map::Iter<'a, ComponentId, ModeStoreValue>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.0.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl ModeStoreProvider for ModeStoreVec {
|
||||
fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode) {
|
||||
self.0.push(ModeStoreValue::new(target_id, mode));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
1610
satrs/src/subsystem.rs
Normal file
1610
satrs/src/subsystem.rs
Normal file
File diff suppressed because it is too large
Load Diff
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