Mode Tree Feature Update

This commit is contained in:
Robin Müller 2024-11-21 18:35:16 +01:00
parent 1a1d330814
commit 474afc37ca
21 changed files with 4776 additions and 543 deletions

3
docs.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
cargo +nightly doc --all-features --open

View File

@ -386,6 +386,7 @@ impl<
&mut self, &mut self,
requestor: MessageMetadata, requestor: MessageMetadata,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
_forced: bool,
) -> Result<(), satrs::mode::ModeError> { ) -> Result<(), satrs::mode::ModeError> {
log::info!( log::info!(
"{}: transitioning to mode {:?}", "{}: transitioning to mode {:?}",
@ -575,7 +576,10 @@ mod tests {
.mode_request_tx .mode_request_tx
.send(GenericMessage::new( .send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()), 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"); .expect("failed to send mode request");
testbench.handler.periodic_operation(); testbench.handler.periodic_operation();
@ -633,7 +637,10 @@ mod tests {
.mode_request_tx .mode_request_tx
.send(GenericMessage::new( .send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()), 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"); .expect("failed to send mode request");
testbench.handler.periodic_operation(); testbench.handler.periodic_operation();

View File

@ -412,6 +412,7 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeRequestHandler
&mut self, &mut self,
requestor: MessageMetadata, requestor: MessageMetadata,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
_forced: bool,
) -> Result<(), satrs::mode::ModeError> { ) -> Result<(), satrs::mode::ModeError> {
log::info!( log::info!(
"{}: transitioning to mode {:?}", "{}: transitioning to mode {:?}",
@ -660,7 +661,10 @@ mod tests {
.mode_request_tx .mode_request_tx
.send(GenericMessage::new( .send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()), 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"); .expect("failed to send mode request");
let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap(); let switch_map_shared = testbench.handler.shared_switch_map.lock().unwrap();
@ -692,7 +696,10 @@ mod tests {
.mode_request_tx .mode_request_tx
.send(GenericMessage::new( .send(GenericMessage::new(
MessageMetadata::new(0, PUS_MODE_SERVICE.id()), 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"); .expect("failed to send mode request");
testbench testbench

View File

@ -291,7 +291,10 @@ fn static_tmtc_pool_main() {
pcdu_handler_mode_tx pcdu_handler_mode_tx
.send(GenericMessage::new( .send(GenericMessage::new(
MessageMetadata::new(0, NO_SENDER), 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"); .expect("sending initial mode request failed");
@ -598,7 +601,10 @@ fn dyn_tmtc_pool_main() {
pcdu_handler_mode_tx pcdu_handler_mode_tx
.send(GenericMessage::new( .send(GenericMessage::new(
MessageMetadata::new(0, NO_SENDER), 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"); .expect("sending initial mode request failed");

View File

@ -110,6 +110,7 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
), ),
)?; )?;
} }
ModeReply::ModeInfo(_mode_and_submode) => (),
}; };
Ok(true) Ok(true)
} }
@ -190,7 +191,13 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
} }
let mode_and_submode = ModeAndSubmode::from_be_bytes(&tc.user_data()[4..]) let mode_and_submode = ModeAndSubmode::from_be_bytes(&tc.user_data()[4..])
.expect("mode and submode extraction failed"); .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::TcReadMode => Ok((active_request, ModeRequest::ReadMode)),
Subservice::TcAnnounceMode => Ok((active_request, ModeRequest::AnnounceMode)), Subservice::TcAnnounceMode => Ok((active_request, ModeRequest::AnnounceMode)),
@ -346,7 +353,13 @@ mod tests {
let (_active_req, req) = testbench let (_active_req, req) = testbench
.convert(token, &[], TEST_APID, TEST_UNIQUE_ID_0) .convert(token, &[], TEST_APID, TEST_UNIQUE_ID_0)
.expect("conversion has failed"); .expect("conversion has failed");
assert_eq!(req, ModeRequest::SetMode(mode_and_submode)); assert_eq!(
req,
ModeRequest::SetMode {
mode_and_submode,
forced: false
}
);
} }
#[test] #[test]

View File

@ -20,6 +20,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `StaticHeaplessMemoryPool` which can be grown with user-provided static buffers. - `StaticHeaplessMemoryPool` which can be grown with user-provided static buffers.
- Scheduling table for systems with a standard runtime - 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 # [v0.2.1] 2024-05-19

View File

@ -2,7 +2,7 @@
name = "satrs" name = "satrs"
version = "0.2.1" version = "0.2.1"
edition = "2021" edition = "2021"
rust-version = "1.71.1" rust-version = "1.82.0"
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"] authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
description = "A framework to build software for remote systems" description = "A framework to build software for remote systems"
homepage = "https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/" homepage = "https://absatsw.irs.uni-stuttgart.de/projects/sat-rs/"

448
satrs/src/dev_mgmt.rs Normal file
View 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
View 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);
}
}

View File

@ -22,14 +22,21 @@ extern crate downcast_rs;
#[cfg(any(feature = "std", test))] #[cfg(any(feature = "std", test))]
extern crate std; extern crate std;
pub mod action;
#[cfg(feature = "alloc")]
pub mod dev_mgmt;
pub mod encoding; pub mod encoding;
pub mod event_man; pub mod event_man;
pub mod events; pub mod events;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod executable; pub mod executable;
pub mod hal; pub mod hal;
pub mod health;
pub mod hk;
pub mod mode;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub mod mode_tree; pub mod mode_tree;
pub mod params;
pub mod pool; pub mod pool;
pub mod power; pub mod power;
pub mod pus; pub mod pus;
@ -38,14 +45,11 @@ pub mod request;
pub mod res_code; pub mod res_code;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod scheduling; pub mod scheduling;
#[cfg(feature = "alloc")]
pub mod subsystem;
pub mod time; pub mod time;
pub mod tmtc; pub mod tmtc;
pub mod action;
pub mod hk;
pub mod mode;
pub mod params;
pub use spacepackets; pub use spacepackets;
use spacepackets::PacketId; use spacepackets::PacketId;

View File

@ -12,7 +12,9 @@ pub use std_mod::*;
use crate::{ use crate::{
queue::GenericTargetedMessagingError, queue::GenericTargetedMessagingError,
request::{GenericMessage, MessageMetadata, MessageReceiver, MessageReceiverWithId, RequestId}, request::{
GenericMessage, MessageMetadata, MessageReceiverProvider, MessageReceiverWithId, RequestId,
},
ComponentId, ComponentId,
}; };
@ -26,6 +28,11 @@ pub struct ModeAndSubmode {
submode: Submode, 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 { impl ModeAndSubmode {
pub const RAW_LEN: usize = size_of::<Mode>() + size_of::<Submode>(); pub const RAW_LEN: usize = size_of::<Mode>() + size_of::<Submode>();
@ -111,7 +118,10 @@ impl TargetedModeCommand {
pub enum ModeRequest { pub enum ModeRequest {
/// Mode information. Can be used to notify other components of changed modes. /// Mode information. Can be used to notify other components of changed modes.
ModeInfo(ModeAndSubmode), ModeInfo(ModeAndSubmode),
SetMode(ModeAndSubmode), SetMode {
mode_and_submode: ModeAndSubmode,
forced: bool,
},
ReadMode, ReadMode,
AnnounceMode, AnnounceMode,
AnnounceModeRecursive, AnnounceModeRecursive,
@ -127,6 +137,8 @@ pub struct TargetedModeRequest {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum ModeReply { 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. /// Reply to a mode request to confirm the commanded mode was reached.
ModeReply(ModeAndSubmode), ModeReply(ModeAndSubmode),
// Can not reach the commanded mode. Contains a reason as a [ResultU16]. // Can not reach the commanded mode. Contains a reason as a [ResultU16].
@ -156,7 +168,7 @@ pub trait ModeRequestReceiver {
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError>; ) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError>;
} }
impl<R: MessageReceiver<ModeRequest>> ModeRequestReceiver impl<R: MessageReceiverProvider<ModeRequest>> ModeRequestReceiver
for MessageReceiverWithId<ModeRequest, R> for MessageReceiverWithId<ModeRequest, R>
{ {
fn try_recv_mode_request( 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 { pub enum ModeError {
Messaging(GenericTargetedMessagingError), #[error("Messaging error: {0}")]
} Messaging(#[from] GenericTargetedMessagingError),
#[error("busy with other mode request")]
impl From<GenericTargetedMessagingError> for ModeError { Busy,
fn from(value: GenericTargetedMessagingError) -> Self {
Self::Messaging(value)
}
} }
pub trait ModeProvider { pub trait ModeProvider {
@ -196,6 +205,7 @@ pub trait ModeRequestHandler: ModeProvider {
&mut self, &mut self,
requestor: MessageMetadata, requestor: MessageMetadata,
mode_and_submode: ModeAndSubmode, mode_and_submode: ModeAndSubmode,
forced: bool,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
fn announce_mode(&self, requestor_info: Option<MessageMetadata>, recursive: bool); fn announce_mode(&self, requestor_info: Option<MessageMetadata>, recursive: bool);
@ -222,9 +232,10 @@ pub trait ModeRequestHandler: ModeProvider {
request: GenericMessage<ModeRequest>, request: GenericMessage<ModeRequest>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
match request.message { match request.message {
ModeRequest::SetMode(mode_and_submode) => { ModeRequest::SetMode {
self.start_transition(request.requestor_info, mode_and_submode) mode_and_submode,
} forced,
} => self.start_transition(request.requestor_info, mode_and_submode, forced),
ModeRequest::ReadMode => self.send_mode_reply( ModeRequest::ReadMode => self.send_mode_reply(
request.requestor_info, request.requestor_info,
ModeReply::ModeReply(self.mode_and_submode()), ModeReply::ModeReply(self.mode_and_submode()),
@ -248,7 +259,9 @@ pub trait ModeReplyReceiver {
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError>; ) -> 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( fn try_recv_mode_reply(
&self, &self,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> {
@ -270,12 +283,13 @@ pub trait ModeReplySender {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod alloc_mod { pub mod alloc_mod {
use crate::request::{ use crate::request::{
MessageSender, MessageSenderAndReceiver, MessageSenderMap, RequestAndReplySenderAndReceiver, MessageSenderAndReceiver, MessageSenderMap, MessageSenderProvider,
MessageSenderStoreProvider, RequestAndReplySenderAndReceiver,
}; };
use super::*; use super::*;
impl<S: MessageSender<ModeReply>> MessageSenderMap<ModeReply, S> { impl<S: MessageSenderProvider<ModeReply>> MessageSenderMap<ModeReply, S> {
pub fn send_mode_reply( pub fn send_mode_reply(
&self, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
@ -290,8 +304,13 @@ pub mod alloc_mod {
} }
} }
impl<FROM, S: MessageSender<ModeReply>, R: MessageReceiver<FROM>> ModeReplySender impl<
for MessageSenderAndReceiver<ModeReply, FROM, S, R> 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 { fn local_channel_id(&self) -> ComponentId {
self.local_channel_id_generic() self.local_channel_id_generic()
@ -302,7 +321,7 @@ pub mod alloc_mod {
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
request: ModeReply, request: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> 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()), MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()),
requestor_info.sender_id(), requestor_info.sender_id(),
request, request,
@ -310,8 +329,13 @@ pub mod alloc_mod {
} }
} }
impl<TO, S: MessageSender<TO>, R: MessageReceiver<ModeReply>> ModeReplyReceiver impl<
for MessageSenderAndReceiver<TO, ModeReply, S, R> To,
Sender: MessageSenderProvider<To>,
Receiver: MessageReceiverProvider<ModeReply>,
SenderStore: MessageSenderStoreProvider<To, Sender>,
> ModeReplyReceiver
for MessageSenderAndReceiver<To, ModeReply, Sender, Receiver, SenderStore>
{ {
fn try_recv_mode_reply( fn try_recv_mode_reply(
&self, &self,
@ -321,26 +345,51 @@ pub mod alloc_mod {
} }
impl< impl<
REQUEST, Request,
S0: MessageSender<REQUEST>, ReqSender: MessageSenderProvider<Request>,
R0: MessageReceiver<ModeReply>, ReqReceiver: MessageReceiverProvider<Request>,
S1: MessageSender<ModeReply>, ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
R1: MessageReceiver<REQUEST>, Reply,
> RequestAndReplySenderAndReceiver<REQUEST, ModeReply, S0, R0, S1, R1> 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) { pub fn add_reply_target(&mut self, target_id: ComponentId, reply_sender: ReplySender) {
self.reply_sender_map self.reply_sender_store
.add_message_target(target_id, reply_sender) .add_message_target(target_id, reply_sender)
} }
} }
impl< impl<
REQUEST, Request,
S0: MessageSender<REQUEST>, ReqSender: MessageSenderProvider<Request>,
R0: MessageReceiver<ModeReply>, ReqReceiver: MessageReceiverProvider<Request>,
S1: MessageSender<ModeReply>, ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
R1: MessageReceiver<REQUEST>, ReplySender: MessageSenderProvider<ModeReply>,
> ModeReplySender for RequestAndReplySenderAndReceiver<REQUEST, ModeReply, S0, R0, S1, R1> ReplyReceiver: MessageReceiverProvider<ModeReply>,
ReplySenderStore: MessageSenderStoreProvider<ModeReply, ReplySender>,
> ModeReplySender
for RequestAndReplySenderAndReceiver<
Request,
ReqSender,
ReqReceiver,
ReqSenderStore,
ModeReply,
ReplySender,
ReplyReceiver,
ReplySenderStore,
>
{ {
fn local_channel_id(&self) -> ComponentId { fn local_channel_id(&self) -> ComponentId {
self.local_channel_id_generic() self.local_channel_id_generic()
@ -349,24 +398,35 @@ pub mod alloc_mod {
fn send_mode_reply( fn send_mode_reply(
&self, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
request: ModeReply, reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> 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()), MessageMetadata::new(requestor_info.request_id(), self.local_channel_id()),
requestor_info.sender_id(), requestor_info.sender_id(),
request, reply,
) )
} }
} }
impl< impl<
REQUEST, Request,
S0: MessageSender<REQUEST>, ReqSender: MessageSenderProvider<Request>,
R0: MessageReceiver<ModeReply>, ReqReceiver: MessageReceiverProvider<Request>,
S1: MessageSender<ModeReply>, ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
R1: MessageReceiver<REQUEST>, ReplySender: MessageSenderProvider<ModeReply>,
ReplyReceiver: MessageReceiverProvider<ModeReply>,
ReplySenderStore: MessageSenderStoreProvider<ModeReply, ReplySender>,
> ModeReplyReceiver > ModeReplyReceiver
for RequestAndReplySenderAndReceiver<REQUEST, ModeReply, S0, R0, S1, R1> for RequestAndReplySenderAndReceiver<
Request,
ReqSender,
ReqReceiver,
ReqSenderStore,
ModeReply,
ReplySender,
ReplyReceiver,
ReplySenderStore,
>
{ {
fn try_recv_mode_reply( fn try_recv_mode_reply(
&self, &self,
@ -376,11 +436,14 @@ pub mod alloc_mod {
} }
/// Helper type definition for a mode handler which can handle mode requests. /// Helper type definition for a mode handler which can handle mode requests.
pub type ModeRequestHandlerInterface<S, R> = pub type ModeRequestHandlerInterface<Sender, Receiver, ReplySenderStore> =
MessageSenderAndReceiver<ModeReply, ModeRequest, S, R>; MessageSenderAndReceiver<ModeReply, ModeRequest, Sender, Receiver, ReplySenderStore>;
impl<S: MessageSender<ModeReply>, R: MessageReceiver<ModeRequest>> impl<
ModeRequestHandlerInterface<S, R> Sender: MessageSenderProvider<ModeReply>,
Receiver: MessageReceiverProvider<ModeRequest>,
ReplySenderStore: MessageSenderStoreProvider<ModeReply, Sender>,
> ModeRequestHandlerInterface<Sender, Receiver, ReplySenderStore>
{ {
pub fn try_recv_mode_request( pub fn try_recv_mode_request(
&self, &self,
@ -403,9 +466,15 @@ pub mod alloc_mod {
/// Helper type defintion for a mode handler object which can send mode requests and receive /// Helper type defintion for a mode handler object which can send mode requests and receive
/// mode replies. /// 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( pub fn try_recv_mode_reply(
&self, &self,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> { ) -> 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 /// Helper type defintion for a mode handler object which can both send mode requests and
/// process mode requests. /// process mode requests.
pub type ModeInterface<S0, R0, S1, R1> = pub type ModeInterface<
RequestAndReplySenderAndReceiver<ModeRequest, ModeReply, S0, R0, S1, R1>; 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( pub fn send_mode_request(
&self, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
@ -442,25 +526,13 @@ pub mod alloc_mod {
} }
} }
/* impl<
impl<S: MessageSender<ModeRequest>> ModeRequestSender for MessageSenderMapWithId<ModeRequest, S> { To,
fn local_channel_id(&self) -> ComponentId { Sender: MessageSenderProvider<To>,
self.local_channel_id Receiver: MessageReceiverProvider<ModeRequest>,
} SenderStore: MessageSenderStoreProvider<To, Sender>,
> ModeRequestReceiver
fn send_mode_request( for MessageSenderAndReceiver<To, ModeRequest, Sender, Receiver, SenderStore>
&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>
{ {
fn try_recv_mode_request( fn try_recv_mode_request(
&self, &self,
@ -469,8 +541,13 @@ pub mod alloc_mod {
} }
} }
impl<FROM, S: MessageSender<ModeRequest>, R: MessageReceiver<FROM>> ModeRequestSender impl<
for MessageSenderAndReceiver<ModeRequest, FROM, S, R> 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 { fn local_channel_id(&self) -> ComponentId {
self.local_channel_id_generic() self.local_channel_id_generic()
@ -482,7 +559,7 @@ pub mod alloc_mod {
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_mode_request( self.message_sender_store.send_message(
MessageMetadata::new(request_id, self.local_channel_id()), MessageMetadata::new(request_id, self.local_channel_id()),
target_id, target_id,
request, request,
@ -491,27 +568,50 @@ pub mod alloc_mod {
} }
impl< impl<
REPLY, ReqSender: MessageSenderProvider<ModeRequest>,
S0: MessageSender<ModeRequest>, ReqReceiver: MessageReceiverProvider<ModeRequest>,
R0: MessageReceiver<REPLY>, ReqSenderStore: MessageSenderStoreProvider<ModeRequest, ReqSender>,
S1: MessageSender<REPLY>, Reply,
R1: MessageReceiver<ModeRequest>, ReplySender: MessageSenderProvider<Reply>,
> RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1> 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) { pub fn add_request_target(&mut self, target_id: ComponentId, request_sender: ReqSender) {
self.request_sender_map self.request_sender_store
.add_message_target(target_id, request_sender) .add_message_target(target_id, request_sender)
} }
} }
impl< impl<
REPLY, ReqSender: MessageSenderProvider<ModeRequest>,
S0: MessageSender<ModeRequest>, ReqReceiver: MessageReceiverProvider<ModeRequest>,
R0: MessageReceiver<REPLY>, ReqSenderStore: MessageSenderStoreProvider<ModeRequest, ReqSender>,
S1: MessageSender<REPLY>, Reply,
R1: MessageReceiver<ModeRequest>, ReplySender: MessageSenderProvider<Reply>,
ReplyReceiver: MessageReceiverProvider<Reply>,
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
> ModeRequestSender > 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 { fn local_channel_id(&self) -> ComponentId {
self.local_channel_id_generic() self.local_channel_id_generic()
@ -523,7 +623,7 @@ pub mod alloc_mod {
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.request_sender_map.send_mode_request( self.request_sender_store.send_message(
MessageMetadata::new(request_id, self.local_channel_id()), MessageMetadata::new(request_id, self.local_channel_id()),
target_id, target_id,
request, request,
@ -532,13 +632,24 @@ pub mod alloc_mod {
} }
impl< impl<
REPLY, ReqSender: MessageSenderProvider<ModeRequest>,
S0: MessageSender<ModeRequest>, ReqReceiver: MessageReceiverProvider<ModeRequest>,
R0: MessageReceiver<REPLY>, ReqSenderStore: MessageSenderStoreProvider<ModeRequest, ReqSender>,
S1: MessageSender<REPLY>, Reply,
R1: MessageReceiver<ModeRequest>, ReplySender: MessageSenderProvider<Reply>,
ReplyReceiver: MessageReceiverProvider<Reply>,
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
> ModeRequestReceiver > ModeRequestReceiver
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1> for RequestAndReplySenderAndReceiver<
ModeRequest,
ReqSender,
ReqReceiver,
ReqSenderStore,
Reply,
ReplySender,
ReplyReceiver,
ReplySenderStore,
>
{ {
fn try_recv_mode_request( fn try_recv_mode_request(
&self, &self,
@ -552,39 +663,97 @@ pub mod alloc_mod {
pub mod std_mod { pub mod std_mod {
use std::sync::mpsc; use std::sync::mpsc;
use crate::request::{MessageSenderList, OneMessageSender};
use super::*; use super::*;
pub type ModeRequestHandlerMpsc = ModeRequestHandlerInterface< pub type ModeRequestHandlerMpsc = ModeRequestHandlerInterface<
mpsc::Sender<GenericMessage<ModeReply>>, mpsc::Sender<GenericMessage<ModeReply>>,
mpsc::Receiver<GenericMessage<ModeRequest>>, mpsc::Receiver<GenericMessage<ModeRequest>>,
MessageSenderList<ModeReply, mpsc::Sender<GenericMessage<ModeReply>>>,
>; >;
pub type ModeRequestHandlerMpscBounded = ModeRequestHandlerInterface< pub type ModeRequestHandlerMpscBounded = ModeRequestHandlerInterface<
mpsc::SyncSender<GenericMessage<ModeReply>>, mpsc::SyncSender<GenericMessage<ModeReply>>,
mpsc::Receiver<GenericMessage<ModeRequest>>, mpsc::Receiver<GenericMessage<ModeRequest>>,
MessageSenderList<ModeReply, mpsc::SyncSender<GenericMessage<ModeReply>>>,
>; >;
pub type ModeRequestorMpsc = ModeRequestorInterface< pub type ModeRequestorOneChildMpsc = ModeRequestorInterface<
mpsc::Sender<GenericMessage<ModeRequest>>, mpsc::Sender<GenericMessage<ModeRequest>>,
mpsc::Receiver<GenericMessage<ModeReply>>, mpsc::Receiver<GenericMessage<ModeReply>>,
OneMessageSender<ModeRequest, mpsc::Sender<GenericMessage<ModeRequest>>>,
>; >;
pub type ModeRequestorBoundedMpsc = ModeRequestorInterface< pub type ModeRequestorOneChildBoundedMpsc = ModeRequestorInterface<
mpsc::SyncSender<GenericMessage<ModeRequest>>, mpsc::SyncSender<GenericMessage<ModeRequest>>,
mpsc::Receiver<GenericMessage<ModeReply>>, 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< pub type ModeRequestorAndHandlerMpsc = ModeInterface<
mpsc::Sender<GenericMessage<ModeRequest>>, mpsc::Sender<GenericMessage<ModeRequest>>,
mpsc::Receiver<GenericMessage<ModeReply>>,
mpsc::Sender<GenericMessage<ModeReply>>,
mpsc::Receiver<GenericMessage<ModeRequest>>, 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< pub type ModeRequestorAndHandlerMpscBounded = ModeInterface<
mpsc::SyncSender<GenericMessage<ModeRequest>>, mpsc::SyncSender<GenericMessage<ModeRequest>>,
mpsc::Receiver<GenericMessage<ModeReply>>,
mpsc::SyncSender<GenericMessage<ModeReply>>,
mpsc::Receiver<GenericMessage<ModeRequest>>, 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)] #[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(())
}
}
}

View File

@ -2,10 +2,57 @@ use alloc::vec::Vec;
use hashbrown::HashMap; use hashbrown::HashMap;
use crate::{ use crate::{
mode::{Mode, ModeAndSubmode, Submode}, mode::{Mode, ModeAndSubmode, ModeReply, ModeRequest, Submode},
request::MessageSenderProvider,
ComponentId, 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)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TableEntryType { pub enum TableEntryType {
/// Target table containing information of the expected children modes for given mode. /// Target table containing information of the expected children modes for given mode.
@ -15,23 +62,553 @@ pub enum TableEntryType {
Sequence, 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. /// Name of respective table entry.
pub name: &'static str, pub name: &'static str,
/// Target channel ID. /// Target component ID.
pub channel_id: ComponentId, 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, pub mode_submode: ModeAndSubmode,
/// This mask allows to specify multiple allowed submodes for a given mode.
pub allowed_submode_mask: Option<Submode>, 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 check_success: bool,
} }
pub struct ModeTableMapValue { impl SequenceTableEntry {
/// Name for a given mode table entry. pub fn new(
pub name: &'static str, name: &'static str,
pub entries: Vec<ModeTableEntry>, target_id: ComponentId,
mode_submode: ModeAndSubmode,
check_success: bool,
) -> Self {
Self {
common: ModeTableEntryCommon {
name,
target_id,
mode_submode,
allowed_submode_mask: None,
},
check_success,
}
}
delegate::delegate! {
to self.common {
pub fn set_allowed_submode_mask(&mut self, mask: Submode);
pub fn allowed_submode_mask(&self) -> Option<Submode>;
}
}
} }
pub type ModeTable = HashMap<Mode, ModeTableMapValue>; #[derive(Debug, thiserror::Error)]
#[error("target {0} not in mode store")]
pub struct TargetNotInModeStoreError(pub ComponentId);
/// Mode store value type.
#[derive(Debug, Copy, Clone)]
pub struct ModeStoreValue {
/// ID of the mode component.
id: ComponentId,
/// Current mode and submode of the component.
pub mode_and_submode: ModeAndSubmode,
/// State information to track whether a reply should be awaited for the mode component.
pub awaiting_reply: bool,
}
impl ModeStoreValue {
pub fn new(id: ComponentId, mode_and_submode: ModeAndSubmode) -> Self {
Self {
id,
mode_and_submode,
awaiting_reply: false,
}
}
pub fn id(&self) -> ComponentId {
self.id
}
pub fn mode_and_submode(&self) -> ModeAndSubmode {
self.mode_and_submode
}
}
pub trait ModeStoreProvider {
fn add_component(&mut self, target_id: ComponentId, mode: ModeAndSubmode);
fn has_component(&self, target_id: ComponentId) -> bool;
fn get(&self, target_id: ComponentId) -> Option<&ModeStoreValue>;
fn get_mut(&mut self, target_id: ComponentId) -> Option<&mut ModeStoreValue>;
/// Generic handler for mode replies received from child components.
///
/// Implementation should clear the awaition flag if the `handle_reply_awaition` argument is
/// true and returns whether any children are still awaiting replies. If the flag is not set
fn mode_reply_handler_with_reply_awaition(
&mut self,
sender_id: ComponentId,
reported_mode_and_submode: Option<ModeAndSubmode>,
) -> bool {
self.mode_reply_handler(sender_id, reported_mode_and_submode, true)
.unwrap_or(false)
}
fn mode_reply_handler_without_reply_awaition(
&mut self,
sender_id: ComponentId,
reported_mode_and_submode: Option<ModeAndSubmode>,
) {
self.mode_reply_handler(sender_id, reported_mode_and_submode, false);
}
fn mode_reply_handler(
&mut self,
sender_id: ComponentId,
reported_mode_and_submode: Option<ModeAndSubmode>,
with_reply_awaition: bool,
) -> Option<bool>;
}
#[cfg(feature = "alloc")]
pub mod alloc_mod {
use super::*;
#[derive(Debug)]
pub struct TargetTablesMapValue {
/// Name for a given mode table entry.
pub name: &'static str,
/// Optional fallback mode if the target mode can not be kept.
pub fallback_mode: Option<Mode>,
/// These are the rows of the a target table.
pub entries: Vec<TargetTableEntry>,
}
impl TargetTablesMapValue {
pub fn new(name: &'static str, fallback_mode: Option<Mode>) -> Self {
Self {
name,
fallback_mode,
entries: Default::default(),
}
}
pub fn add_entry(&mut self, entry: TargetTableEntry) {
self.entries.push(entry);
}
}
/// One sequence of a [SequenceTablesMapValue] in a [SequenceModeTables].
///
/// It contains all mode requests which need to be executed for a sequence step and it also
/// associates a [Self::name] with the sequence.
#[derive(Debug)]
pub struct SequenceTableMapTable {
/// Name for a given mode sequence.
pub name: &'static str,
/// These are the rows of the a sequence table.
pub entries: Vec<SequenceTableEntry>,
}
impl SequenceTableMapTable {
pub fn new(name: &'static str) -> Self {
Self {
name,
entries: Default::default(),
}
}
pub fn add_entry(&mut self, entry: SequenceTableEntry) {
self.entries.push(entry);
}
}
/// A sequence table entry.
///
/// This is simply a list of [SequenceTableMapTable]s which also associates a [Self::name]
/// with the sequence. The order of sub-tables in the list also specifies the execution order
/// in the mode sequence.
#[derive(Debug)]
pub struct SequenceTablesMapValue {
/// Name for a given mode sequence.
pub name: &'static str,
/// Each sequence can consists of multiple sequences that are executed consecutively.
pub entries: Vec<SequenceTableMapTable>,
}
impl SequenceTablesMapValue {
pub fn new(name: &'static str) -> Self {
Self {
name,
entries: Default::default(),
}
}
pub fn add_sequence_table(&mut self, entry: SequenceTableMapTable) {
self.entries.push(entry);
}
}
#[derive(Debug, Default)]
pub struct TargetModeTables(pub HashMap<Mode, TargetTablesMapValue>);
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)] #[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);
}
}

View File

@ -68,7 +68,8 @@ pub mod alloc_mod {
action::ActionRequest, action::ActionRequest,
queue::GenericTargetedMessagingError, queue::GenericTargetedMessagingError,
request::{ request::{
GenericMessage, MessageReceiver, MessageSender, MessageSenderAndReceiver, RequestId, GenericMessage, MessageReceiverProvider, MessageSenderAndReceiver,
MessageSenderProvider, MessageSenderStoreProvider, RequestId,
}, },
ComponentId, ComponentId,
}; };
@ -76,11 +77,14 @@ pub mod alloc_mod {
use super::ActionReplyPus; use super::ActionReplyPus;
/// Helper type definition for a mode handler which can handle mode requests. /// Helper type definition for a mode handler which can handle mode requests.
pub type ActionRequestHandlerInterface<S, R> = pub type ActionRequestHandlerInterface<Sender, Receiver, ReplySenderStore> =
MessageSenderAndReceiver<ActionReplyPus, ActionRequest, S, R>; MessageSenderAndReceiver<ActionReplyPus, ActionRequest, Sender, Receiver, ReplySenderStore>;
impl<S: MessageSender<ActionReplyPus>, R: MessageReceiver<ActionRequest>> impl<
ActionRequestHandlerInterface<S, R> Sender: MessageSenderProvider<ActionReplyPus>,
Receiver: MessageReceiverProvider<ActionRequest>,
ReplySender: MessageSenderStoreProvider<ActionReplyPus, Sender>,
> ActionRequestHandlerInterface<Sender, Receiver, ReplySender>
{ {
pub fn try_recv_action_request( pub fn try_recv_action_request(
&self, &self,
@ -100,11 +104,20 @@ pub mod alloc_mod {
/// Helper type defintion for a mode handler object which can send mode requests and receive /// Helper type defintion for a mode handler object which can send mode requests and receive
/// mode replies. /// mode replies.
pub type ActionRequestorInterface<S, R> = pub type ActionRequestorInterface<Sender, Receiver, RequestSenderStore> =
MessageSenderAndReceiver<ActionRequest, ActionReplyPus, S, R>; MessageSenderAndReceiver<
ActionRequest,
ActionReplyPus,
Sender,
Receiver,
RequestSenderStore,
>;
impl<S: MessageSender<ActionRequest>, R: MessageReceiver<ActionReplyPus>> impl<
ActionRequestorInterface<S, R> Sender: MessageSenderProvider<ActionRequest>,
Receiver: MessageReceiverProvider<ActionReplyPus>,
RequestSenderStore: MessageSenderStoreProvider<ActionRequest, Sender>,
> ActionRequestorInterface<Sender, Receiver, RequestSenderStore>
{ {
pub fn try_recv_action_reply( pub fn try_recv_action_reply(
&self, &self,
@ -132,6 +145,7 @@ pub mod std_mod {
verification::{self, TcStateToken}, verification::{self, TcStateToken},
ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap, ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap,
}, },
request::{MessageSenderMap, OneMessageSender},
ComponentId, ComponentId,
}; };
@ -174,22 +188,38 @@ pub mod std_mod {
} }
pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap<ActivePusActionRequestStd>; pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap<ActivePusActionRequestStd>;
pub type ActionRequestHandlerMpsc = ActionRequestHandlerInterface< pub type ActionRequestHandlerOneSenderMpsc = ActionRequestHandlerInterface<
mpsc::Sender<GenericMessage<ActionReplyPus>>, mpsc::Sender<GenericMessage<ActionReplyPus>>,
mpsc::Receiver<GenericMessage<ActionRequest>>, mpsc::Receiver<GenericMessage<ActionRequest>>,
OneMessageSender<
GenericMessage<ActionReplyPus>,
mpsc::Sender<GenericMessage<ActionReplyPus>>,
>,
>; >;
pub type ActionRequestHandlerMpscBounded = ActionRequestHandlerInterface< pub type ActionRequestHandlerOneSenderMpscBounded = ActionRequestHandlerInterface<
mpsc::SyncSender<GenericMessage<ActionReplyPus>>, mpsc::SyncSender<GenericMessage<ActionReplyPus>>,
mpsc::Receiver<GenericMessage<ActionRequest>>, mpsc::Receiver<GenericMessage<ActionRequest>>,
OneMessageSender<
GenericMessage<ActionReplyPus>,
mpsc::SyncSender<GenericMessage<ActionReplyPus>>,
>,
>; >;
pub type ActionRequestorMpsc = ActionRequestorInterface< pub type ActionRequestorWithSenderMapMpsc = ActionRequestorInterface<
mpsc::Sender<GenericMessage<ActionRequest>>, mpsc::Sender<GenericMessage<ActionRequest>>,
mpsc::Receiver<GenericMessage<ActionReplyPus>>, mpsc::Receiver<GenericMessage<ActionReplyPus>>,
MessageSenderMap<
GenericMessage<ActionRequest>,
mpsc::Sender<GenericMessage<ActionRequest>>,
>,
>; >;
pub type ActionRequestorBoundedMpsc = ActionRequestorInterface< pub type ActionRequestorWithSenderMapBoundedMpsc = ActionRequestorInterface<
mpsc::SyncSender<GenericMessage<ActionRequest>>, mpsc::SyncSender<GenericMessage<ActionRequest>>,
mpsc::Receiver<GenericMessage<ActionReplyPus>>, mpsc::Receiver<GenericMessage<ActionReplyPus>>,
MessageSenderMap<
GenericMessage<ActionRequest>,
mpsc::SyncSender<GenericMessage<ActionRequest>>,
>,
>; >;
} }

View File

@ -1221,9 +1221,10 @@ pub(crate) fn source_buffer_large_enough(
#[cfg(any(feature = "test_util", test))] #[cfg(any(feature = "test_util", test))]
pub mod test_util { pub mod test_util {
use crate::request::UniqueApidTargetId;
use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader}; use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader};
use crate::request::UniqueApidTargetId;
use super::{ use super::{
verification::{self, TcStateAccepted, VerificationToken}, verification::{self, TcStateAccepted, VerificationToken},
DirectPusPacketHandlerResult, PusPacketHandlingError, DirectPusPacketHandlerResult, PusPacketHandlingError,
@ -1232,6 +1233,7 @@ pub mod test_util {
pub const TEST_APID: u16 = 0x101; pub const TEST_APID: u16 = 0x101;
pub const TEST_UNIQUE_ID_0: u32 = 0x05; pub const TEST_UNIQUE_ID_0: u32 = 0x05;
pub const TEST_UNIQUE_ID_1: u32 = 0x06; pub const TEST_UNIQUE_ID_1: u32 = 0x06;
pub const TEST_COMPONENT_ID_0: UniqueApidTargetId = pub const TEST_COMPONENT_ID_0: UniqueApidTargetId =
UniqueApidTargetId::new(TEST_APID, TEST_UNIQUE_ID_0); UniqueApidTargetId::new(TEST_APID, TEST_UNIQUE_ID_0);
pub const TEST_COMPONENT_ID_1: UniqueApidTargetId = pub const TEST_COMPONENT_ID_1: UniqueApidTargetId =
@ -1268,14 +1270,13 @@ pub mod tests {
use spacepackets::ecss::tm::{GenericPusTmSecondaryHeader, PusTmCreator, PusTmReader}; use spacepackets::ecss::tm::{GenericPusTmSecondaryHeader, PusTmCreator, PusTmReader};
use spacepackets::ecss::{PusPacket, WritablePusPacket}; use spacepackets::ecss::{PusPacket, WritablePusPacket};
use spacepackets::CcsdsPacket; use spacepackets::CcsdsPacket;
use test_util::{TEST_APID, TEST_COMPONENT_ID_0};
use crate::pool::{PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig}; use crate::pool::{PoolProvider, SharedStaticMemoryPool, StaticMemoryPool, StaticPoolConfig};
use crate::pus::verification::{RequestId, VerificationReporter}; use crate::pus::verification::{RequestId, VerificationReporter};
use crate::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool, SharedPacketPool}; use crate::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool, SharedPacketPool};
use crate::ComponentId; use crate::ComponentId;
use super::test_util::{TEST_APID, TEST_COMPONENT_ID_0};
use super::verification::test_util::TestVerificationReporter; use super::verification::test_util::TestVerificationReporter;
use super::verification::{ use super::verification::{
TcStateAccepted, VerificationReporterCfg, VerificationReportingProvider, VerificationToken, TcStateAccepted, VerificationReporterCfg, VerificationReportingProvider, VerificationToken,

View File

@ -39,7 +39,7 @@ mod tests {
use crate::{ use crate::{
mode::{ mode::{
ModeAndSubmode, ModeReply, ModeReplySender, ModeRequest, ModeRequestSender, ModeAndSubmode, ModeReply, ModeReplySender, ModeRequest, ModeRequestSender,
ModeRequestorAndHandlerMpsc, ModeRequestorMpsc, ModeRequestorAndHandlerMpsc, ModeRequestorOneChildMpsc,
}, },
request::{GenericMessage, MessageMetadata}, request::{GenericMessage, MessageMetadata},
}; };
@ -52,7 +52,8 @@ mod tests {
fn test_simple_mode_requestor() { fn test_simple_mode_requestor() {
let (reply_sender, reply_receiver) = mpsc::channel(); let (reply_sender, reply_receiver) = mpsc::channel();
let (request_sender, request_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); mode_requestor.add_message_target(TEST_COMPONENT_ID_1, request_sender);
// Send a request and verify it arrives at the receiver. // Send a request and verify it arrives at the receiver.

View File

@ -1,6 +1,3 @@
use core::fmt::{Display, Formatter};
#[cfg(feature = "std")]
use std::error::Error;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::sync::mpsc; use std::sync::mpsc;
@ -10,89 +7,31 @@ use crate::ComponentId;
pub type ChannelId = u32; pub type ChannelId = u32;
/// Generic error type for sending something via a message queue. /// 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 { pub enum GenericSendError {
#[error("rx side has disconnected")]
RxDisconnected, RxDisconnected,
#[error("queue with max capacity of {0:?} is full")]
QueueFull(Option<u32>), QueueFull(Option<u32>),
#[error("target queue with ID {0} does not exist")]
TargetDoesNotExist(ComponentId), 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. /// 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 { pub enum GenericReceiveError {
#[error("nothing to receive")]
Empty, Empty,
#[error("tx side with id {0:?} has disconnected")]
TxDisconnected(Option<ComponentId>), TxDisconnected(Option<ComponentId>),
} }
impl Display for GenericReceiveError { #[derive(Debug, Clone, thiserror::Error)]
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)]
pub enum GenericTargetedMessagingError { pub enum GenericTargetedMessagingError {
Send(GenericSendError), #[error("generic targeted messaging send error: {0}")]
Receive(GenericReceiveError), Send(#[from] GenericSendError),
} #[error("generic targeted messaging receive error: {0}")]
impl From<GenericSendError> for GenericTargetedMessagingError { Receive(#[from] GenericReceiveError),
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),
}
}
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -140,24 +140,27 @@ impl<Message> GenericMessage<Message> {
} }
/// Generic trait for objects which can send targeted messages. /// 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>; fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError>;
} }
// Generic trait for objects which can receive targeted messages. // 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>; 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 { fn from(receiver: R) -> Self {
MessageWithSenderIdReceiver(receiver, PhantomData) MessageWithSenderIdReceiver(receiver, PhantomData)
} }
} }
impl<MSG, R: MessageReceiver<MSG>> MessageWithSenderIdReceiver<MSG, R> { impl<MSG, R: MessageReceiverProvider<MSG>> MessageWithSenderIdReceiver<MSG, R> {
pub fn try_recv_message( pub fn try_recv_message(
&self, &self,
) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> { ) -> 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, local_channel_id: ComponentId,
reply_receiver: MessageWithSenderIdReceiver<MSG, R>, 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 { pub fn new(local_channel_id: ComponentId, reply_receiver: R) -> Self {
Self { Self {
local_channel_id, 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( pub fn try_recv_message(
&self, &self,
) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> { ) -> 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")] #[cfg(feature = "alloc")]
pub mod alloc_mod { pub mod alloc_mod {
use crate::queue::GenericSendError; use crate::queue::GenericSendError;
use std::convert::From;
use super::*; use super::*;
use hashbrown::HashMap; use hashbrown::HashMap;
pub struct MessageSenderMap<MSG, S: MessageSender<MSG>>( pub struct OneMessageSender<Msg, S: MessageSenderProvider<Msg>> {
pub HashMap<ComponentId, S>, 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>, 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 { fn default() -> Self {
Self(Default::default(), PhantomData) Self(Default::default(), PhantomData)
} }
} }
impl<MSG, S: MessageSender<MSG>> MessageSenderMap<MSG, S> { impl<Msg, Sender: MessageSenderProvider<Msg>> MessageSenderStoreProvider<Msg, Sender>
pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) { for MessageSenderList<Msg, Sender>
self.0.insert(target_id, message_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, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
target_channel_id: ComponentId, 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> { ) -> Result<(), GenericTargetedMessagingError> {
if self.0.contains_key(&target_channel_id) { if self.0.contains_key(&target_channel_id) {
return self 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 local_channel_id: ComponentId,
pub message_sender_map: MessageSenderMap<TO, S>, pub message_sender_store: SenderStore,
pub message_receiver: MessageWithSenderIdReceiver<FROM, R>, pub message_receiver: MessageWithSenderIdReceiver<From, Receiver>,
pub(crate) phantom: PhantomData<(To, Sender)>,
} }
impl<TO, FROM, S: MessageSender<TO>, R: MessageReceiver<FROM>> impl<
MessageSenderAndReceiver<TO, FROM, S, R> 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 { Self {
local_channel_id, local_channel_id,
message_sender_map: Default::default(), message_sender_store: Default::default(),
message_receiver: MessageWithSenderIdReceiver::from(message_receiver), message_receiver: MessageWithSenderIdReceiver::from(message_receiver),
phantom: PhantomData,
} }
} }
pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: S) { pub fn add_message_target(&mut self, target_id: ComponentId, message_sender: Sender) {
self.message_sender_map self.message_sender_store
.add_message_target(target_id, message_sender) .add_message_target(target_id, message_sender)
} }
@ -262,9 +366,9 @@ pub mod alloc_mod {
&self, &self,
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
message: TO, message: To,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_message( self.message_sender_store.send_message(
MessageMetadata::new(request_id, self.local_channel_id_generic()), MessageMetadata::new(request_id, self.local_channel_id_generic()),
target_id, target_id,
message, 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. /// Try to receive a message, which can be a reply or a request, depending on the generics.
pub fn try_recv_message( pub fn try_recv_message(
&self, &self,
) -> Result<Option<GenericMessage<FROM>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<From>>, GenericTargetedMessagingError> {
self.message_receiver.try_recv_message() self.message_receiver.try_recv_message()
} }
} }
pub struct RequestAndReplySenderAndReceiver< pub struct RequestAndReplySenderAndReceiver<
REQUEST, Request,
REPLY, ReqSender: MessageSenderProvider<Request>,
S0: MessageSender<REQUEST>, ReqReceiver: MessageReceiverProvider<Request>,
R0: MessageReceiver<REPLY>, ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
S1: MessageSender<REPLY>, Reply,
R1: MessageReceiver<REQUEST>, ReplySender: MessageSenderProvider<Reply>,
ReplyReceiver: MessageReceiverProvider<Reply>,
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
> { > {
pub local_channel_id: ComponentId, pub local_channel_id: ComponentId,
// These 2 are a functional group. // These 2 are a functional group.
pub request_sender_map: MessageSenderMap<REQUEST, S0>, pub request_sender_store: ReqSenderStore,
pub reply_receiver: MessageWithSenderIdReceiver<REPLY, R0>, pub reply_receiver: MessageWithSenderIdReceiver<Reply, ReplyReceiver>,
// These 2 are a functional group. // These 2 are a functional group.
pub request_receiver: MessageWithSenderIdReceiver<REQUEST, R1>, pub request_receiver: MessageWithSenderIdReceiver<Request, ReqReceiver>,
pub reply_sender_map: MessageSenderMap<REPLY, S1>, pub reply_sender_store: ReplySenderStore,
phantom: PhantomData<(ReqSender, ReplySender)>,
} }
impl< impl<
REQUEST, Request,
REPLY, ReqSender: MessageSenderProvider<Request>,
S0: MessageSender<REQUEST>, ReqReceiver: MessageReceiverProvider<Request>,
R0: MessageReceiver<REPLY>, ReqSenderStore: MessageSenderStoreProvider<Request, ReqSender>,
S1: MessageSender<REPLY>, Reply,
R1: MessageReceiver<REQUEST>, ReplySender: MessageSenderProvider<Reply>,
> RequestAndReplySenderAndReceiver<REQUEST, REPLY, S0, R0, S1, R1> ReplyReceiver: MessageReceiverProvider<Reply>,
ReplySenderStore: MessageSenderStoreProvider<Reply, ReplySender>,
>
RequestAndReplySenderAndReceiver<
Request,
ReqSender,
ReqReceiver,
ReqSenderStore,
Reply,
ReplySender,
ReplyReceiver,
ReplySenderStore,
>
{ {
pub fn new( pub fn new(
local_channel_id: ComponentId, local_channel_id: ComponentId,
request_receiver: R1, request_receiver: ReqReceiver,
reply_receiver: R0, reply_receiver: ReplyReceiver,
) -> Self { ) -> Self {
Self { Self {
local_channel_id, local_channel_id,
request_receiver: request_receiver.into(), request_receiver: request_receiver.into(),
reply_receiver: reply_receiver.into(), reply_receiver: reply_receiver.into(),
request_sender_map: Default::default(), request_sender_store: Default::default(),
reply_sender_map: Default::default(), reply_sender_store: Default::default(),
phantom: PhantomData,
} }
} }
@ -333,14 +453,14 @@ pub mod std_mod {
use crate::queue::{GenericReceiveError, GenericSendError}; 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> { fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError> {
self.send(message) self.send(message)
.map_err(|_| GenericSendError::RxDisconnected)?; .map_err(|_| GenericSendError::RxDisconnected)?;
Ok(()) 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> { fn send(&self, message: GenericMessage<MSG>) -> Result<(), GenericTargetedMessagingError> {
if let Err(e) = self.try_send(message) { if let Err(e) = self.try_send(message) {
return match e { return match e {
@ -357,7 +477,7 @@ pub mod std_mod {
pub type MessageSenderMapMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::Sender<MSG>>; pub type MessageSenderMapMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::Sender<MSG>>;
pub type MessageSenderMapBoundedMpsc<MSG> = MessageReceiverWithId<MSG, mpsc::SyncSender<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> { fn try_recv(&self) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
match self.try_recv() { match self.try_recv() {
Ok(msg) => Ok(Some(msg)), Ok(msg) => Ok(Some(msg)),
@ -386,7 +506,7 @@ mod tests {
use crate::{ use crate::{
queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError}, queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError},
request::{MessageMetadata, MessageSenderMap}, request::{MessageMetadata, MessageSenderMap, MessageSenderStoreProvider},
}; };
use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId}; use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId};

View File

@ -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 /// 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) { pub fn init_start_of_slot(&mut self) {
self.start_of_slot = Instant::now(); self.start_of_slot = Instant::now();
} }

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

View File

@ -6,7 +6,6 @@ use satrs::events::{EventU32, EventU32TypedSev, Severity, SeverityInfo};
use satrs::params::U32Pair; use satrs::params::U32Pair;
use satrs::params::{Params, ParamsHeapless, WritableToBeBytes}; use satrs::params::{Params, ParamsHeapless, WritableToBeBytes};
use satrs::pus::event_man::{DefaultPusEventReportingMap, EventReporter, PusEventTmCreatorWithMap}; use satrs::pus::event_man::{DefaultPusEventReportingMap, EventReporter, PusEventTmCreatorWithMap};
use satrs::pus::test_util::TEST_COMPONENT_ID_0;
use satrs::request::UniqueApidTargetId; use satrs::request::UniqueApidTargetId;
use satrs::tmtc::PacketAsVec; use satrs::tmtc::PacketAsVec;
use spacepackets::ecss::tm::PusTmReader; use spacepackets::ecss::tm::PusTmReader;
@ -100,10 +99,7 @@ fn test_threaded_usage() {
// Event sender and TM checker thread // Event sender and TM checker thread
let jh1 = thread::spawn(move || { let jh1 = thread::spawn(move || {
event_tx event_tx
.send(EventMessage::new( .send(EventMessage::new(TEST_ID.id(), INFO_EVENT.into()))
TEST_COMPONENT_ID_0.id(),
INFO_EVENT.into(),
))
.expect("Sending info event failed"); .expect("Sending info event failed");
loop { loop {
match event_packet_rx.try_recv() { match event_packet_rx.try_recv() {
@ -130,7 +126,7 @@ fn test_threaded_usage() {
} }
event_tx event_tx
.send(EventMessage::new_with_params( .send(EventMessage::new_with_params(
TEST_COMPONENT_ID_0.id(), TEST_ID.id(),
LOW_SEV_EVENT, LOW_SEV_EVENT,
&Params::Heapless((2_u32, 3_u32).into()), &Params::Heapless((2_u32, 3_u32).into()),
)) ))