Mode Tree Feature Update

This commit is contained in:
Robin Müller 2024-11-21 18:35:16 +01:00
parent 1a1d330814
commit e238b5d377
44 changed files with 5636 additions and 1562 deletions

View File

@ -11,7 +11,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
- run: cargo check --release - run: cargo check
# Check example with static pool configuration
- run: cargo check -p satrs-example --no-default-features
test: test:
name: Run Tests name: Run Tests
@ -37,7 +39,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable - uses: dtolnay/rust-toolchain@stable
with: with:
targets: "armv7-unknown-linux-gnueabihf, thumbv7em-none-eabihf" targets: "armv7-unknown-linux-gnueabihf, thumbv7em-none-eabihf"
- run: cargo check -p satrs --release --target=${{matrix.target}} --no-default-features - run: cargo check -p satrs --target=${{matrix.target}} --no-default-features
fmt: fmt:
name: Check formatting name: Check formatting

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

@ -20,6 +20,7 @@ thiserror = "2"
lazy_static = "1" lazy_static = "1"
strum = { version = "0.26", features = ["derive"] } strum = { version = "0.26", features = ["derive"] }
derive-new = "0.7" derive-new = "0.7"
cfg-if = "1"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
@ -35,8 +36,8 @@ version = "0.1.1"
path = "../satrs-mib" path = "../satrs-mib"
[features] [features]
dyn_tmtc = [] heap_tmtc = []
default = ["dyn_tmtc"] default = ["heap_tmtc"]
[dev-dependencies] [dev-dependencies]
env_logger = "0.11" env_logger = "0.11"

View File

@ -14,7 +14,7 @@ You can run the application using `cargo run`.
# Features # Features
The example has the `dyn_tmtc` feature which is enabled by default. With this feature enabled, The example has the `heap_tmtc` feature which is enabled by default. With this feature enabled,
TMTC packets are exchanged using the heap as the backing memory instead of pre-allocated static TMTC packets are exchanged using the heap as the backing memory instead of pre-allocated static
stores. stores.

View File

@ -1,7 +1,7 @@
use derive_new::new; use derive_new::new;
use satrs::hk::{HkRequest, HkRequestVariant}; use satrs::hk::{HkRequest, HkRequestVariant};
use satrs::mode_tree::{ModeChild, ModeNode};
use satrs::power::{PowerSwitchInfo, PowerSwitcherCommandSender}; use satrs::power::{PowerSwitchInfo, PowerSwitcherCommandSender};
use satrs::queue::{GenericSendError, GenericTargetedMessagingError};
use satrs_example::{DeviceMode, TimestampHelper}; use satrs_example::{DeviceMode, TimestampHelper};
use satrs_minisim::acs::lis3mdl::{ use satrs_minisim::acs::lis3mdl::{
MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR, MgmLis3MdlReply, MgmLis3RawValues, FIELD_LSB_PER_GAUSS_4_SENS, GAUSS_TO_MICROTESLA_FACTOR,
@ -15,7 +15,8 @@ use std::sync::{Arc, Mutex};
use std::time::Duration; use std::time::Duration;
use satrs::mode::{ use satrs::mode::{
ModeAndSubmode, ModeError, ModeProvider, ModeReply, ModeRequest, ModeRequestHandler, ModeAndSubmode, ModeError, ModeProvider, ModeReply, ModeRequestHandler,
ModeRequestHandlerMpscBounded,
}; };
use satrs::pus::{EcssTmSender, PusTmVariant}; use satrs::pus::{EcssTmSender, PusTmVariant};
use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId}; use satrs::request::{GenericMessage, MessageMetadata, UniqueApidTargetId};
@ -24,6 +25,8 @@ use satrs_example::config::components::{NO_SENDER, PUS_MODE_SERVICE};
use crate::hk::PusHkHelper; use crate::hk::PusHkHelper;
use crate::pus::hk::{HkReply, HkReplyVariant}; use crate::pus::hk::{HkReply, HkReplyVariant};
use crate::requests::CompositeRequest; use crate::requests::CompositeRequest;
use crate::spi::SpiInterface;
use crate::tmtc::sender::TmTcSender;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -48,11 +51,6 @@ pub enum TransitionState {
Done, Done,
} }
pub trait SpiInterface {
type Error: Debug;
fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error>;
}
#[derive(Default)] #[derive(Default)]
pub struct SpiDummyInterface { pub struct SpiDummyInterface {
pub dummy_values: MgmLis3RawValues, pub dummy_values: MgmLis3RawValues,
@ -129,13 +127,6 @@ pub struct MgmData {
pub z: f32, pub z: f32,
} }
pub struct MpscModeLeafInterface {
pub request_rx: mpsc::Receiver<GenericMessage<ModeRequest>>,
pub reply_to_pus_tx: mpsc::Sender<GenericMessage<ModeReply>>,
#[allow(dead_code)]
pub reply_to_parent_tx: mpsc::SyncSender<GenericMessage<ModeReply>>,
}
#[derive(Default)] #[derive(Default)]
pub struct BufWrapper { pub struct BufWrapper {
tx_buf: [u8; 32], tx_buf: [u8; 32],
@ -166,16 +157,15 @@ impl Default for ModeHelpers {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub struct MgmHandlerLis3Mdl< pub struct MgmHandlerLis3Mdl<
ComInterface: SpiInterface, ComInterface: SpiInterface,
TmSender: EcssTmSender,
SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>, SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>,
> { > {
id: UniqueApidTargetId, id: UniqueApidTargetId,
dev_str: &'static str, dev_str: &'static str,
mode_interface: MpscModeLeafInterface, mode_node: ModeRequestHandlerMpscBounded,
composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>, composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>,
hk_reply_tx: mpsc::Sender<GenericMessage<HkReply>>, hk_reply_tx: mpsc::SyncSender<GenericMessage<HkReply>>,
switch_helper: SwitchHelper, switch_helper: SwitchHelper,
tm_sender: TmSender, tm_sender: TmTcSender,
pub com_interface: ComInterface, pub com_interface: ComInterface,
shared_mgm_set: Arc<Mutex<MgmData>>, shared_mgm_set: Arc<Mutex<MgmData>>,
#[new(value = "PusHkHelper::new(id)")] #[new(value = "PusHkHelper::new(id)")]
@ -190,9 +180,8 @@ pub struct MgmHandlerLis3Mdl<
impl< impl<
ComInterface: SpiInterface, ComInterface: SpiInterface,
TmSender: EcssTmSender,
SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>, SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>,
> MgmHandlerLis3Mdl<ComInterface, TmSender, SwitchHelper> > MgmHandlerLis3Mdl<ComInterface, SwitchHelper>
{ {
pub fn periodic_operation(&mut self) { pub fn periodic_operation(&mut self) {
self.stamp_helper.update_from_now(); self.stamp_helper.update_from_now();
@ -275,8 +264,9 @@ impl<
pub fn handle_mode_requests(&mut self) { pub fn handle_mode_requests(&mut self) {
loop { loop {
// TODO: Only allow one set mode request per cycle? // TODO: Only allow one set mode request per cycle?
match self.mode_interface.request_rx.try_recv() { match self.mode_node.try_recv_mode_request() {
Ok(msg) => { Ok(opt_msg) => {
if let Some(msg) = opt_msg {
let result = self.handle_mode_request(msg); let result = self.handle_mode_request(msg);
// TODO: Trigger event? // TODO: Trigger event?
if result.is_err() { if result.is_err() {
@ -286,14 +276,16 @@ impl<
result.err().unwrap() result.err().unwrap()
); );
} }
}
Err(e) => {
if e != mpsc::TryRecvError::Empty {
log::warn!("{}: failed to receive mode request: {:?}", self.dev_str, e);
} else { } else {
break; break;
} }
} }
Err(e) => match e {
satrs::queue::GenericReceiveError::Empty => break,
satrs::queue::GenericReceiveError::TxDisconnected(e) => {
log::warn!("{}: failed to receive mode request: {:?}", self.dev_str, e);
}
},
} }
} }
} }
@ -365,9 +357,8 @@ impl<
impl< impl<
ComInterface: SpiInterface, ComInterface: SpiInterface,
TmSender: EcssTmSender,
SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>, SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>,
> ModeProvider for MgmHandlerLis3Mdl<ComInterface, TmSender, SwitchHelper> > ModeProvider for MgmHandlerLis3Mdl<ComInterface, SwitchHelper>
{ {
fn mode_and_submode(&self) -> ModeAndSubmode { fn mode_and_submode(&self) -> ModeAndSubmode {
self.mode_helpers.current self.mode_helpers.current
@ -376,9 +367,8 @@ impl<
impl< impl<
ComInterface: SpiInterface, ComInterface: SpiInterface,
TmSender: EcssTmSender,
SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>, SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>,
> ModeRequestHandler for MgmHandlerLis3Mdl<ComInterface, TmSender, SwitchHelper> > ModeRequestHandler for MgmHandlerLis3Mdl<ComInterface, SwitchHelper>
{ {
type Error = ModeError; type Error = ModeError;
@ -386,6 +376,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 {:?}",
@ -448,10 +439,9 @@ impl<
requestor.sender_id() requestor.sender_id()
); );
} }
self.mode_interface self.mode_node
.reply_to_pus_tx .send_mode_reply(requestor, reply)
.send(GenericMessage::new(requestor, reply)) .map_err(ModeError::Send)?;
.map_err(|_| GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected))?;
Ok(()) Ok(())
} }
@ -464,17 +454,44 @@ impl<
} }
} }
impl<
ComInterface: SpiInterface,
SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>,
> ModeNode for MgmHandlerLis3Mdl<ComInterface, SwitchHelper>
{
fn id(&self) -> satrs::ComponentId {
self.id.into()
}
}
impl<
ComInterface: SpiInterface,
SwitchHelper: PowerSwitchInfo<PcduSwitch> + PowerSwitcherCommandSender<PcduSwitch>,
> ModeChild for MgmHandlerLis3Mdl<ComInterface, SwitchHelper>
{
type Sender = mpsc::SyncSender<GenericMessage<ModeReply>>;
fn add_mode_parent(&mut self, id: satrs::ComponentId, reply_sender: Self::Sender) {
self.mode_node.add_message_target(id, reply_sender);
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::{mpsc, Arc}; use std::{
collections::HashMap,
sync::{mpsc, Arc},
};
use satrs::{ use satrs::{
mode::{ModeReply, ModeRequest}, mode::{ModeReply, ModeRequest},
mode_tree::ModeParent,
power::SwitchStateBinary, power::SwitchStateBinary,
request::{GenericMessage, UniqueApidTargetId}, request::{GenericMessage, UniqueApidTargetId},
tmtc::PacketAsVec, tmtc::PacketAsVec,
ComponentId,
}; };
use satrs_example::config::components::Apid; use satrs_example::config::components::{Apid, MGM_ASSEMBLY};
use satrs_minisim::acs::lis3mdl::MgmLis3RawValues; use satrs_minisim::acs::lis3mdl::MgmLis3RawValues;
use crate::{eps::TestSwitchHelper, pus::hk::HkReply, requests::CompositeRequest}; use crate::{eps::TestSwitchHelper, pus::hk::HkReply, requests::CompositeRequest};
@ -502,49 +519,88 @@ mod tests {
} }
} }
#[allow(dead_code)]
pub struct MgmTestbench { pub struct MgmTestbench {
pub mode_request_tx: mpsc::Sender<GenericMessage<ModeRequest>>, pub mode_request_tx: mpsc::SyncSender<GenericMessage<ModeRequest>>,
pub mode_reply_rx_to_pus: mpsc::Receiver<GenericMessage<ModeReply>>, pub mode_reply_rx_to_pus: mpsc::Receiver<GenericMessage<ModeReply>>,
pub mode_reply_rx_to_parent: mpsc::Receiver<GenericMessage<ModeReply>>, pub mode_reply_rx_to_parent: mpsc::Receiver<GenericMessage<ModeReply>>,
pub composite_request_tx: mpsc::Sender<GenericMessage<CompositeRequest>>, pub composite_request_tx: mpsc::Sender<GenericMessage<CompositeRequest>>,
pub hk_reply_rx: mpsc::Receiver<GenericMessage<HkReply>>, pub hk_reply_rx: mpsc::Receiver<GenericMessage<HkReply>>,
pub tm_rx: mpsc::Receiver<PacketAsVec>, pub tm_rx: mpsc::Receiver<PacketAsVec>,
pub handler: pub handler: MgmHandlerLis3Mdl<TestSpiInterface, TestSwitchHelper>,
MgmHandlerLis3Mdl<TestSpiInterface, mpsc::Sender<PacketAsVec>, TestSwitchHelper>, }
#[derive(Default)]
pub struct MgmAssemblyMock(
pub HashMap<ComponentId, mpsc::SyncSender<GenericMessage<ModeRequest>>>,
);
impl ModeNode for MgmAssemblyMock {
fn id(&self) -> satrs::ComponentId {
PUS_MODE_SERVICE.into()
}
}
impl ModeParent for MgmAssemblyMock {
type Sender = mpsc::SyncSender<GenericMessage<ModeRequest>>;
fn add_mode_child(&mut self, id: satrs::ComponentId, request_sender: Self::Sender) {
self.0.insert(id, request_sender);
}
}
#[derive(Default)]
pub struct PusMock {
pub request_sender_map: HashMap<ComponentId, mpsc::SyncSender<GenericMessage<ModeRequest>>>,
}
impl ModeNode for PusMock {
fn id(&self) -> satrs::ComponentId {
PUS_MODE_SERVICE.into()
}
}
impl ModeParent for PusMock {
type Sender = mpsc::SyncSender<GenericMessage<ModeRequest>>;
fn add_mode_child(&mut self, id: satrs::ComponentId, request_sender: Self::Sender) {
self.request_sender_map.insert(id, request_sender);
}
} }
impl MgmTestbench { impl MgmTestbench {
pub fn new() -> Self { pub fn new() -> Self {
let (request_tx, request_rx) = mpsc::channel(); let (request_tx, request_rx) = mpsc::sync_channel(5);
let (reply_tx_to_pus, reply_rx_to_pus) = mpsc::channel(); let (reply_tx_to_pus, reply_rx_to_pus) = mpsc::sync_channel(5);
let (reply_tx_to_parent, reply_rx_to_parent) = mpsc::sync_channel(5); let (reply_tx_to_parent, reply_rx_to_parent) = mpsc::sync_channel(5);
let mode_interface = MpscModeLeafInterface { let id = UniqueApidTargetId::new(Apid::Acs as u16, 1);
request_rx, let mode_node = ModeRequestHandlerMpscBounded::new(id.into(), request_rx);
reply_to_pus_tx: reply_tx_to_pus,
reply_to_parent_tx: reply_tx_to_parent,
};
let (composite_request_tx, composite_request_rx) = mpsc::channel(); let (composite_request_tx, composite_request_rx) = mpsc::channel();
let (hk_reply_tx, hk_reply_rx) = mpsc::channel(); let (hk_reply_tx, hk_reply_rx) = mpsc::sync_channel(10);
let (tm_tx, tm_rx) = mpsc::channel::<PacketAsVec>(); let (tm_tx, tm_rx) = mpsc::sync_channel(10);
let tm_sender = TmTcSender::Heap(tm_tx);
let shared_mgm_set = Arc::default(); let shared_mgm_set = Arc::default();
let mut handler = MgmHandlerLis3Mdl::new(
id,
"TEST_MGM",
mode_node,
composite_request_rx,
hk_reply_tx,
TestSwitchHelper::default(),
tm_sender,
TestSpiInterface::default(),
shared_mgm_set,
);
handler.add_mode_parent(PUS_MODE_SERVICE.into(), reply_tx_to_pus);
handler.add_mode_parent(MGM_ASSEMBLY.into(), reply_tx_to_parent);
Self { Self {
mode_request_tx: request_tx, mode_request_tx: request_tx,
mode_reply_rx_to_pus: reply_rx_to_pus, mode_reply_rx_to_pus: reply_rx_to_pus,
mode_reply_rx_to_parent: reply_rx_to_parent, mode_reply_rx_to_parent: reply_rx_to_parent,
composite_request_tx, composite_request_tx,
handler,
tm_rx, tm_rx,
hk_reply_rx, hk_reply_rx,
handler: MgmHandlerLis3Mdl::new(
UniqueApidTargetId::new(Apid::Acs as u16, 1),
"TEST_MGM",
mode_interface,
composite_request_rx,
hk_reply_tx,
TestSwitchHelper::default(),
tm_tx,
TestSpiInterface::default(),
shared_mgm_set,
),
} }
} }
} }
@ -575,7 +631,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 +692,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

@ -149,11 +149,13 @@ pub mod components {
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub enum AcsId { pub enum AcsId {
Mgm0 = 0, Mgm0 = 0,
Assembly = 1,
} }
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
pub enum EpsId { pub enum EpsId {
Pcdu = 0, Pcdu = 0,
Subsystem = 1,
} }
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
@ -176,8 +178,12 @@ pub mod components {
UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusHk as u32); UniqueApidTargetId::new(Apid::GenericPus as u16, PusId::PusHk as u32);
pub const PUS_SCHED_SERVICE: UniqueApidTargetId = pub const PUS_SCHED_SERVICE: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Sched as u16, 0); UniqueApidTargetId::new(Apid::Sched as u16, 0);
pub const MGM_ASSEMBLY: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Assembly as u32);
pub const MGM_HANDLER_0: UniqueApidTargetId = pub const MGM_HANDLER_0: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32); UniqueApidTargetId::new(Apid::Acs as u16, AcsId::Mgm0 as u32);
pub const EPS_SUBSYSTEM: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Subsystem as u32);
pub const PCDU_HANDLER: UniqueApidTargetId = pub const PCDU_HANDLER: UniqueApidTargetId =
UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Pcdu as u32); UniqueApidTargetId::new(Apid::Eps as u16, EpsId::Pcdu as u32);
pub const UDP_SERVER: UniqueApidTargetId = pub const UDP_SERVER: UniqueApidTargetId =

View File

@ -8,15 +8,19 @@ use derive_new::new;
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
use satrs::{ use satrs::{
hk::{HkRequest, HkRequestVariant}, hk::{HkRequest, HkRequestVariant},
mode::{ModeAndSubmode, ModeError, ModeProvider, ModeReply, ModeRequestHandler}, mode::{
ModeAndSubmode, ModeError, ModeProvider, ModeReply, ModeRequestHandler,
ModeRequestHandlerMpscBounded,
},
mode_tree::{ModeChild, ModeNode},
power::SwitchRequest, power::SwitchRequest,
pus::{EcssTmSender, PusTmVariant}, pus::{EcssTmSender, PusTmVariant},
queue::{GenericSendError, GenericTargetedMessagingError}, queue::GenericSendError,
request::{GenericMessage, MessageMetadata, UniqueApidTargetId}, request::{GenericMessage, MessageMetadata, UniqueApidTargetId},
spacepackets::ByteConversionError, spacepackets::ByteConversionError,
}; };
use satrs_example::{ use satrs_example::{
config::components::{NO_SENDER, PUS_MODE_SERVICE}, config::components::{NO_SENDER, PCDU_HANDLER, PUS_MODE_SERVICE},
DeviceMode, TimestampHelper, DeviceMode, TimestampHelper,
}; };
use satrs_minisim::{ use satrs_minisim::{
@ -28,7 +32,6 @@ use satrs_minisim::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
acs::mgm::MpscModeLeafInterface,
hk::PusHkHelper, hk::PusHkHelper,
pus::hk::{HkReply, HkReplyVariant}, pus::hk::{HkReply, HkReplyVariant},
requests::CompositeRequest, requests::CompositeRequest,
@ -203,9 +206,9 @@ pub type SharedSwitchSet = Arc<Mutex<SwitchSet>>;
pub struct PcduHandler<ComInterface: SerialInterface, TmSender: EcssTmSender> { pub struct PcduHandler<ComInterface: SerialInterface, TmSender: EcssTmSender> {
id: UniqueApidTargetId, id: UniqueApidTargetId,
dev_str: &'static str, dev_str: &'static str,
mode_interface: MpscModeLeafInterface, mode_node: ModeRequestHandlerMpscBounded,
composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>, composite_request_rx: mpsc::Receiver<GenericMessage<CompositeRequest>>,
hk_reply_tx: mpsc::Sender<GenericMessage<HkReply>>, hk_reply_tx: mpsc::SyncSender<GenericMessage<HkReply>>,
switch_request_rx: mpsc::Receiver<GenericMessage<SwitchRequest>>, switch_request_rx: mpsc::Receiver<GenericMessage<SwitchRequest>>,
tm_sender: TmSender, tm_sender: TmSender,
pub com_interface: ComInterface, pub com_interface: ComInterface,
@ -324,8 +327,9 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> PcduHandler<ComInter
pub fn handle_mode_requests(&mut self) { pub fn handle_mode_requests(&mut self) {
loop { loop {
// TODO: Only allow one set mode request per cycle? // TODO: Only allow one set mode request per cycle?
match self.mode_interface.request_rx.try_recv() { match self.mode_node.try_recv_mode_request() {
Ok(msg) => { Ok(opt_msg) => {
if let Some(msg) = opt_msg {
let result = self.handle_mode_request(msg); let result = self.handle_mode_request(msg);
// TODO: Trigger event? // TODO: Trigger event?
if result.is_err() { if result.is_err() {
@ -335,14 +339,18 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> PcduHandler<ComInter
result.err().unwrap() result.err().unwrap()
); );
} }
}
Err(e) => {
if e != mpsc::TryRecvError::Empty {
log::warn!("{}: failed to receive mode request: {:?}", self.dev_str, e);
} else { } else {
break; break;
} }
} }
Err(e) => match e {
satrs::queue::GenericReceiveError::Empty => {
break;
}
satrs::queue::GenericReceiveError::TxDisconnected(_) => {
log::warn!("{}: failed to receive mode request: {:?}", self.dev_str, e);
}
},
} }
} }
} }
@ -412,6 +420,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 {:?}",
@ -466,10 +475,9 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeRequestHandler
requestor.sender_id() requestor.sender_id()
); );
} }
self.mode_interface self.mode_node
.reply_to_pus_tx .send_mode_reply(requestor, reply)
.send(GenericMessage::new(requestor, reply)) .map_err(|_| GenericSendError::RxDisconnected)?;
.map_err(|_| GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected))?;
Ok(()) Ok(())
} }
@ -482,6 +490,24 @@ impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeRequestHandler
} }
} }
impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeNode
for PcduHandler<ComInterface, TmSender>
{
fn id(&self) -> satrs::ComponentId {
PCDU_HANDLER.into()
}
}
impl<ComInterface: SerialInterface, TmSender: EcssTmSender> ModeChild
for PcduHandler<ComInterface, TmSender>
{
type Sender = mpsc::SyncSender<GenericMessage<ModeReply>>;
fn add_mode_parent(&mut self, id: satrs::ComponentId, reply_sender: Self::Sender) {
self.mode_node.add_message_target(id, reply_sender);
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::sync::mpsc; use std::sync::mpsc;
@ -489,7 +515,7 @@ mod tests {
use satrs::{ use satrs::{
mode::ModeRequest, power::SwitchStateBinary, request::GenericMessage, tmtc::PacketAsVec, mode::ModeRequest, power::SwitchStateBinary, request::GenericMessage, tmtc::PacketAsVec,
}; };
use satrs_example::config::components::{Apid, MGM_HANDLER_0}; use satrs_example::config::components::{Apid, EPS_SUBSYSTEM, MGM_HANDLER_0, PCDU_HANDLER};
use satrs_minisim::eps::SwitchMapBinary; use satrs_minisim::eps::SwitchMapBinary;
use super::*; use super::*;
@ -530,7 +556,7 @@ mod tests {
} }
pub struct PcduTestbench { pub struct PcduTestbench {
pub mode_request_tx: mpsc::Sender<GenericMessage<ModeRequest>>, pub mode_request_tx: mpsc::SyncSender<GenericMessage<ModeRequest>>,
pub mode_reply_rx_to_pus: mpsc::Receiver<GenericMessage<ModeReply>>, pub mode_reply_rx_to_pus: mpsc::Receiver<GenericMessage<ModeReply>>,
pub mode_reply_rx_to_parent: mpsc::Receiver<GenericMessage<ModeReply>>, pub mode_reply_rx_to_parent: mpsc::Receiver<GenericMessage<ModeReply>>,
pub composite_request_tx: mpsc::Sender<GenericMessage<CompositeRequest>>, pub composite_request_tx: mpsc::Sender<GenericMessage<CompositeRequest>>,
@ -542,19 +568,29 @@ mod tests {
impl PcduTestbench { impl PcduTestbench {
pub fn new() -> Self { pub fn new() -> Self {
let (mode_request_tx, mode_request_rx) = mpsc::channel(); let (mode_request_tx, mode_request_rx) = mpsc::sync_channel(5);
let (mode_reply_tx_to_pus, mode_reply_rx_to_pus) = mpsc::channel(); let (mode_reply_tx_to_pus, mode_reply_rx_to_pus) = mpsc::sync_channel(5);
let (mode_reply_tx_to_parent, mode_reply_rx_to_parent) = mpsc::sync_channel(5); let (mode_reply_tx_to_parent, mode_reply_rx_to_parent) = mpsc::sync_channel(5);
let mode_interface = MpscModeLeafInterface { let mode_node =
request_rx: mode_request_rx, ModeRequestHandlerMpscBounded::new(PCDU_HANDLER.into(), mode_request_rx);
reply_to_pus_tx: mode_reply_tx_to_pus,
reply_to_parent_tx: mode_reply_tx_to_parent,
};
let (composite_request_tx, composite_request_rx) = mpsc::channel(); let (composite_request_tx, composite_request_rx) = mpsc::channel();
let (hk_reply_tx, hk_reply_rx) = mpsc::channel(); let (hk_reply_tx, hk_reply_rx) = mpsc::sync_channel(10);
let (tm_tx, tm_rx) = mpsc::channel::<PacketAsVec>(); let (tm_tx, tm_rx) = mpsc::channel::<PacketAsVec>();
let (switch_request_tx, switch_reqest_rx) = mpsc::channel(); let (switch_request_tx, switch_reqest_rx) = mpsc::channel();
let shared_switch_map = Arc::new(Mutex::new(SwitchSet::default())); let shared_switch_map = Arc::new(Mutex::new(SwitchSet::default()));
let mut handler = PcduHandler::new(
UniqueApidTargetId::new(Apid::Eps as u16, 0),
"TEST_PCDU",
mode_node,
composite_request_rx,
hk_reply_tx,
switch_reqest_rx,
tm_tx,
SerialInterfaceTest::default(),
shared_switch_map,
);
handler.add_mode_parent(EPS_SUBSYSTEM.into(), mode_reply_tx_to_parent);
handler.add_mode_parent(PUS_MODE_SERVICE.into(), mode_reply_tx_to_pus);
Self { Self {
mode_request_tx, mode_request_tx,
mode_reply_rx_to_pus, mode_reply_rx_to_pus,
@ -563,17 +599,7 @@ mod tests {
hk_reply_rx, hk_reply_rx,
tm_rx, tm_rx,
switch_request_tx, switch_request_tx,
handler: PcduHandler::new( handler,
UniqueApidTargetId::new(Apid::Eps as u16, 0),
"TEST_PCDU",
mode_interface,
composite_request_rx,
hk_reply_tx,
switch_reqest_rx,
tm_tx,
SerialInterfaceTest::default(),
shared_switch_map,
),
} }
} }
@ -660,7 +686,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 +721,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

@ -1,19 +1,20 @@
use std::time::Duration; use std::time::Duration;
use std::{ use std::{
collections::{HashSet, VecDeque}, collections::{HashSet, VecDeque},
fmt::Debug,
marker::PhantomData,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use log::{info, warn}; use log::{info, warn};
use satrs::tmtc::StoreAndSendError;
use satrs::{ use satrs::{
encoding::ccsds::{SpValidity, SpacePacketValidator}, encoding::ccsds::{SpValidity, SpacePacketValidator},
hal::std::tcp_server::{HandledConnectionHandler, ServerConfig, TcpSpacepacketsServer}, hal::std::tcp_server::{HandledConnectionHandler, ServerConfig, TcpSpacepacketsServer},
spacepackets::{CcsdsPacket, PacketId}, spacepackets::{CcsdsPacket, PacketId},
tmtc::{PacketSenderRaw, PacketSource}, tmtc::PacketSource,
}; };
use crate::tmtc::sender::TmTcSender;
#[derive(Default)] #[derive(Default)]
pub struct ConnectionFinishedHandler {} pub struct ConnectionFinishedHandler {}
@ -111,31 +112,23 @@ pub type TcpServer<ReceivesTc, SendError> = TcpSpacepacketsServer<
SendError, SendError,
>; >;
pub struct TcpTask<TcSender: PacketSenderRaw<Error = SendError>, SendError: Debug + 'static>( pub struct TcpTask(pub TcpServer<TmTcSender, StoreAndSendError>);
pub TcpServer<TcSender, SendError>,
PhantomData<SendError>,
);
impl<TcSender: PacketSenderRaw<Error = SendError>, SendError: Debug + 'static> impl TcpTask {
TcpTask<TcSender, SendError>
{
pub fn new( pub fn new(
cfg: ServerConfig, cfg: ServerConfig,
tm_source: SyncTcpTmSource, tm_source: SyncTcpTmSource,
tc_sender: TcSender, tc_sender: TmTcSender,
valid_ids: HashSet<PacketId>, valid_ids: HashSet<PacketId>,
) -> Result<Self, std::io::Error> { ) -> Result<Self, std::io::Error> {
Ok(Self( Ok(Self(TcpSpacepacketsServer::new(
TcpSpacepacketsServer::new(
cfg, cfg,
tm_source, tm_source,
tc_sender, tc_sender,
SimplePacketValidator { valid_ids }, SimplePacketValidator { valid_ids },
ConnectionFinishedHandler::default(), ConnectionFinishedHandler::default(),
None, None,
)?, )?))
PhantomData,
))
} }
pub fn periodic_operation(&mut self) { pub fn periodic_operation(&mut self) {

View File

@ -1,15 +1,16 @@
use core::fmt::Debug;
use std::net::{SocketAddr, UdpSocket}; use std::net::{SocketAddr, UdpSocket};
use std::sync::mpsc; use std::sync::mpsc;
use log::{info, warn}; use log::{info, warn};
use satrs::pus::HandlingStatus; use satrs::pus::HandlingStatus;
use satrs::tmtc::{PacketAsVec, PacketInPool, PacketSenderRaw}; use satrs::tmtc::{PacketAsVec, PacketInPool, StoreAndSendError};
use satrs::{ use satrs::{
hal::std::udp_server::{ReceiveResult, UdpTcServer}, hal::std::udp_server::{ReceiveResult, UdpTcServer},
pool::{PoolProviderWithGuards, SharedStaticMemoryPool}, pool::{PoolProviderWithGuards, SharedStaticMemoryPool},
}; };
use crate::tmtc::sender::TmTcSender;
pub trait UdpTmHandler { pub trait UdpTmHandler {
fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, recv_addr: &SocketAddr); fn send_tm_to_udp_client(&mut self, socket: &UdpSocket, recv_addr: &SocketAddr);
} }
@ -65,21 +66,12 @@ impl UdpTmHandler for DynamicUdpTmHandler {
} }
} }
pub struct UdpTmtcServer< pub struct UdpTmtcServer<TmHandler: UdpTmHandler> {
TcSender: PacketSenderRaw<Error = SendError>, pub udp_tc_server: UdpTcServer<TmTcSender, StoreAndSendError>,
TmHandler: UdpTmHandler,
SendError,
> {
pub udp_tc_server: UdpTcServer<TcSender, SendError>,
pub tm_handler: TmHandler, pub tm_handler: TmHandler,
} }
impl< impl<TmHandler: UdpTmHandler> UdpTmtcServer<TmHandler> {
TcSender: PacketSenderRaw<Error = SendError>,
TmHandler: UdpTmHandler,
SendError: Debug + 'static,
> UdpTmtcServer<TcSender, TmHandler, SendError>
{
pub fn periodic_operation(&mut self) { pub fn periodic_operation(&mut self) {
loop { loop {
if self.poll_tc_server() == HandlingStatus::Empty { if self.poll_tc_server() == HandlingStatus::Empty {
@ -115,7 +107,6 @@ impl<
mod tests { mod tests {
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use std::{ use std::{
cell::RefCell,
collections::VecDeque, collections::VecDeque,
net::IpAddr, net::IpAddr,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
@ -126,30 +117,16 @@ mod tests {
ecss::{tc::PusTcCreator, WritablePusPacket}, ecss::{tc::PusTcCreator, WritablePusPacket},
SpHeader, SpHeader,
}, },
tmtc::PacketSenderRaw,
ComponentId, ComponentId,
}; };
use satrs_example::config::{components, OBSW_SERVER_ADDR}; use satrs_example::config::{components, OBSW_SERVER_ADDR};
use crate::tmtc::sender::{MockSender, TmTcSender};
use super::*; use super::*;
const UDP_SERVER_ID: ComponentId = 0x05; const UDP_SERVER_ID: ComponentId = 0x05;
#[derive(Default, Debug)]
pub struct TestSender {
tc_vec: RefCell<VecDeque<PacketAsVec>>,
}
impl PacketSenderRaw for TestSender {
type Error = ();
fn send_packet(&self, sender_id: ComponentId, tc_raw: &[u8]) -> Result<(), Self::Error> {
let mut mut_queue = self.tc_vec.borrow_mut();
mut_queue.push_back(PacketAsVec::new(sender_id, tc_raw.to_vec()));
Ok(())
}
}
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct TestTmHandler { pub struct TestTmHandler {
addrs_to_send_to: Arc<Mutex<VecDeque<SocketAddr>>>, addrs_to_send_to: Arc<Mutex<VecDeque<SocketAddr>>>,
@ -164,8 +141,7 @@ mod tests {
#[test] #[test]
fn test_basic() { fn test_basic() {
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), 0); let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), 0);
let test_receiver = TestSender::default(); let test_receiver = TmTcSender::Mock(MockSender::default());
// let tc_queue = test_receiver.tc_vec.clone();
let udp_tc_server = let udp_tc_server =
UdpTcServer::new(UDP_SERVER_ID, sock_addr, 2048, test_receiver).unwrap(); UdpTcServer::new(UDP_SERVER_ID, sock_addr, 2048, test_receiver).unwrap();
let tm_handler = TestTmHandler::default(); let tm_handler = TestTmHandler::default();
@ -175,7 +151,13 @@ mod tests {
tm_handler, tm_handler,
}; };
udp_dyn_server.periodic_operation(); udp_dyn_server.periodic_operation();
let queue = udp_dyn_server.udp_tc_server.tc_sender.tc_vec.borrow(); let queue = udp_dyn_server
.udp_tc_server
.tc_sender
.get_mock_sender()
.unwrap()
.0
.borrow();
assert!(queue.is_empty()); assert!(queue.is_empty());
assert!(tm_handler_calls.lock().unwrap().is_empty()); assert!(tm_handler_calls.lock().unwrap().is_empty());
} }
@ -183,8 +165,7 @@ mod tests {
#[test] #[test]
fn test_transactions() { fn test_transactions() {
let sock_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0); let sock_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 0);
let test_receiver = TestSender::default(); let test_receiver = TmTcSender::Mock(MockSender::default());
// let tc_queue = test_receiver.tc_vec.clone();
let udp_tc_server = let udp_tc_server =
UdpTcServer::new(UDP_SERVER_ID, sock_addr, 2048, test_receiver).unwrap(); UdpTcServer::new(UDP_SERVER_ID, sock_addr, 2048, test_receiver).unwrap();
let server_addr = udp_tc_server.socket.local_addr().unwrap(); let server_addr = udp_tc_server.socket.local_addr().unwrap();
@ -204,7 +185,13 @@ mod tests {
client.send_to(&ping_tc, server_addr).unwrap(); client.send_to(&ping_tc, server_addr).unwrap();
udp_dyn_server.periodic_operation(); udp_dyn_server.periodic_operation();
{ {
let mut queue = udp_dyn_server.udp_tc_server.tc_sender.tc_vec.borrow_mut(); let mut queue = udp_dyn_server
.udp_tc_server
.tc_sender
.get_mock_sender()
.unwrap()
.0
.borrow_mut();
assert!(!queue.is_empty()); assert!(!queue.is_empty());
let packet_with_sender = queue.pop_front().unwrap(); let packet_with_sender = queue.pop_front().unwrap();
assert_eq!(packet_with_sender.packet, ping_tc); assert_eq!(packet_with_sender.packet, ping_tc);
@ -219,7 +206,13 @@ mod tests {
assert_eq!(received_addr, client_addr); assert_eq!(received_addr, client_addr);
} }
udp_dyn_server.periodic_operation(); udp_dyn_server.periodic_operation();
let queue = udp_dyn_server.udp_tc_server.tc_sender.tc_vec.borrow(); let queue = udp_dyn_server
.udp_tc_server
.tc_sender
.get_mock_sender()
.unwrap()
.0
.borrow();
assert!(queue.is_empty()); assert!(queue.is_empty());
drop(queue); drop(queue);
// Still tries to send to the same client. // Still tries to send to the same client.

View File

@ -1,3 +1,72 @@
use std::{
net::{IpAddr, SocketAddr},
sync::{mpsc, Arc, Mutex},
thread,
time::Duration,
};
use acs::mgm::{MgmHandlerLis3Mdl, SpiDummyInterface, SpiSimInterface, SpiSimInterfaceWrapper};
use eps::{
pcdu::{PcduHandler, SerialInterfaceDummy, SerialInterfaceToSim, SerialSimInterfaceWrapper},
PowerSwitchHelper,
};
use events::EventHandler;
use interface::{
sim_client_udp::create_sim_client,
tcp::{SyncTcpTmSource, TcpTask},
udp::UdpTmtcServer,
};
use log::info;
use logger::setup_logger;
use pus::{
action::create_action_service,
event::create_event_service,
hk::create_hk_service,
mode::create_mode_service,
scheduler::{create_scheduler_service, TcReleaser},
stack::PusStack,
test::create_test_service,
PusTcDistributor, PusTcMpscRouter,
};
use requests::GenericRequestRouter;
use satrs::{
hal::std::{tcp_server::ServerConfig, udp_server::UdpTcServer},
mode::{Mode, ModeAndSubmode, ModeRequest, ModeRequestHandlerMpscBounded},
mode_tree::connect_mode_nodes,
pus::{event_man::EventRequestWithToken, EcssTcInMemConverter, HandlingStatus},
request::{GenericMessage, MessageMetadata},
spacepackets::time::{cds::CdsTime, TimeWriter},
};
use satrs_example::{
config::{
components::{MGM_HANDLER_0, NO_SENDER, PCDU_HANDLER, TCP_SERVER, UDP_SERVER},
pool::create_sched_tc_pool,
tasks::{FREQ_MS_AOCS, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS},
OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT,
},
DeviceMode,
};
use tmtc::sender::TmTcSender;
use tmtc::{tc_source::TcSourceTask, tm_sink::TmSink};
cfg_if::cfg_if! {
if #[cfg(feature = "heap_tmtc")] {
use interface::udp::DynamicUdpTmHandler;
use satrs::pus::EcssTcInVecConverter;
use tmtc::{tc_source::TcSourceTaskDynamic, tm_sink::TmSinkDynamic};
} else {
use std::sync::RwLock;
use interface::udp::StaticUdpTmHandler;
use satrs::pus::EcssTcInSharedPoolConverter;
use satrs::tmtc::{PacketSenderWithSharedPool, SharedPacketPool};
use satrs_example::config::pool::create_static_pools;
use tmtc::{
tc_source::TcSourceTaskStatic,
tm_sink::TmSinkStatic,
};
}
}
mod acs; mod acs;
mod eps; mod eps;
mod events; mod events;
@ -6,106 +75,68 @@ mod interface;
mod logger; mod logger;
mod pus; mod pus;
mod requests; mod requests;
mod spi;
mod tmtc; mod tmtc;
use crate::eps::pcdu::{ fn main() {
PcduHandler, SerialInterfaceDummy, SerialInterfaceToSim, SerialSimInterfaceWrapper, setup_logger().expect("setting up logging with fern failed");
}; println!("Running OBSW example");
use crate::eps::PowerSwitchHelper;
use crate::events::EventHandler;
use crate::interface::udp::DynamicUdpTmHandler;
use crate::pus::stack::PusStack;
use crate::tmtc::tc_source::{TcSourceTaskDynamic, TcSourceTaskStatic};
use crate::tmtc::tm_sink::{TmSinkDynamic, TmSinkStatic};
use log::info;
use pus::test::create_test_service_dynamic;
use satrs::hal::std::tcp_server::ServerConfig;
use satrs::hal::std::udp_server::UdpTcServer;
use satrs::pus::HandlingStatus;
use satrs::request::{GenericMessage, MessageMetadata};
use satrs::tmtc::{PacketSenderWithSharedPool, SharedPacketPool};
use satrs_example::config::pool::{create_sched_tc_pool, create_static_pools};
use satrs_example::config::tasks::{
FREQ_MS_AOCS, FREQ_MS_PUS_STACK, FREQ_MS_UDP_TMTC, SIM_CLIENT_IDLE_DELAY_MS,
};
use satrs_example::config::{OBSW_SERVER_ADDR, PACKET_ID_VALIDATOR, SERVER_PORT};
use satrs_example::DeviceMode;
use crate::acs::mgm::{ cfg_if::cfg_if! {
MgmHandlerLis3Mdl, MpscModeLeafInterface, SpiDummyInterface, SpiSimInterface, if #[cfg(not(feature = "heap_tmtc"))] {
SpiSimInterfaceWrapper,
};
use crate::interface::sim_client_udp::create_sim_client;
use crate::interface::tcp::{SyncTcpTmSource, TcpTask};
use crate::interface::udp::{StaticUdpTmHandler, UdpTmtcServer};
use crate::logger::setup_logger;
use crate::pus::action::{create_action_service_dynamic, create_action_service_static};
use crate::pus::event::{create_event_service_dynamic, create_event_service_static};
use crate::pus::hk::{create_hk_service_dynamic, create_hk_service_static};
use crate::pus::mode::{create_mode_service_dynamic, create_mode_service_static};
use crate::pus::scheduler::{create_scheduler_service_dynamic, create_scheduler_service_static};
use crate::pus::test::create_test_service_static;
use crate::pus::{PusTcDistributor, PusTcMpscRouter};
use crate::requests::{CompositeRequest, GenericRequestRouter};
use satrs::mode::{Mode, ModeAndSubmode, ModeRequest};
use satrs::pus::event_man::EventRequestWithToken;
use satrs::spacepackets::{time::cds::CdsTime, time::TimeWriter};
use satrs_example::config::components::{
MGM_HANDLER_0, NO_SENDER, PCDU_HANDLER, TCP_SERVER, UDP_SERVER,
};
use std::net::{IpAddr, SocketAddr};
use std::sync::{mpsc, Mutex};
use std::sync::{Arc, RwLock};
use std::thread;
use std::time::Duration;
#[allow(dead_code)]
fn static_tmtc_pool_main() {
let (tm_pool, tc_pool) = create_static_pools(); let (tm_pool, tc_pool) = create_static_pools();
let shared_tm_pool = Arc::new(RwLock::new(tm_pool)); let shared_tm_pool = Arc::new(RwLock::new(tm_pool));
let shared_tc_pool = Arc::new(RwLock::new(tc_pool)); let shared_tc_pool = Arc::new(RwLock::new(tc_pool));
let shared_tm_pool_wrapper = SharedPacketPool::new(&shared_tm_pool); let shared_tm_pool_wrapper = SharedPacketPool::new(&shared_tm_pool);
let shared_tc_pool_wrapper = SharedPacketPool::new(&shared_tc_pool); let shared_tc_pool_wrapper = SharedPacketPool::new(&shared_tc_pool);
}
}
let (tc_source_tx, tc_source_rx) = mpsc::sync_channel(50); let (tc_source_tx, tc_source_rx) = mpsc::sync_channel(50);
let (tm_sink_tx, tm_sink_rx) = mpsc::sync_channel(50); let (tm_sink_tx, tm_sink_rx) = mpsc::sync_channel(50);
let (tm_server_tx, tm_server_rx) = mpsc::sync_channel(50); let (tm_server_tx, tm_server_rx) = mpsc::sync_channel(50);
let tm_sink_tx_sender = cfg_if::cfg_if! {
PacketSenderWithSharedPool::new(tm_sink_tx.clone(), shared_tm_pool_wrapper.clone()); if #[cfg(not(feature = "heap_tmtc"))] {
let tm_sender = TmTcSender::Static(
PacketSenderWithSharedPool::new(tm_sink_tx.clone(), shared_tm_pool_wrapper.clone())
);
} else if #[cfg(feature = "heap_tmtc")] {
let tm_sender = TmTcSender::Heap(tm_sink_tx.clone());
}
}
let (sim_request_tx, sim_request_rx) = mpsc::channel(); let (sim_request_tx, sim_request_rx) = mpsc::channel();
let (mgm_sim_reply_tx, mgm_sim_reply_rx) = mpsc::channel(); let (mgm_sim_reply_tx, mgm_sim_reply_rx) = mpsc::channel();
let (pcdu_sim_reply_tx, pcdu_sim_reply_rx) = mpsc::channel(); let (pcdu_sim_reply_tx, pcdu_sim_reply_rx) = mpsc::channel();
let mut opt_sim_client = create_sim_client(sim_request_rx); let mut opt_sim_client = create_sim_client(sim_request_rx);
let (mgm_handler_composite_tx, mgm_handler_composite_rx) = let (mgm_handler_composite_tx, mgm_handler_composite_rx) = mpsc::sync_channel(10);
mpsc::sync_channel::<GenericMessage<CompositeRequest>>(10); let (pcdu_handler_composite_tx, pcdu_handler_composite_rx) = mpsc::sync_channel(30);
let (pcdu_handler_composite_tx, pcdu_handler_composite_rx) = let (mgm_handler_mode_tx, mgm_handler_mode_rx) = mpsc::sync_channel(5);
mpsc::sync_channel::<GenericMessage<CompositeRequest>>(30); let (pcdu_handler_mode_tx, pcdu_handler_mode_rx) = mpsc::sync_channel(5);
let (mgm_handler_mode_tx, mgm_handler_mode_rx) =
mpsc::sync_channel::<GenericMessage<ModeRequest>>(5);
let (pcdu_handler_mode_tx, pcdu_handler_mode_rx) =
mpsc::sync_channel::<GenericMessage<ModeRequest>>(5);
// Some request are targetable. This map is used to retrieve sender handles based on a target ID. // Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let mut request_map = GenericRequestRouter::default(); let mut request_map = GenericRequestRouter::default();
request_map request_map
.composite_router_map .composite_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_composite_tx); .insert(MGM_HANDLER_0.id(), mgm_handler_composite_tx);
request_map
.mode_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_mode_tx);
request_map request_map
.composite_router_map .composite_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx); .insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
request_map
.mode_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx.clone());
// This helper structure is used by all telecommand providers which need to send telecommands // This helper structure is used by all telecommand providers which need to send telecommands
// to the TC source. // to the TC source.
let tc_source = PacketSenderWithSharedPool::new(tc_source_tx, shared_tc_pool_wrapper.clone()); cfg_if::cfg_if! {
if #[cfg(not(feature = "heap_tmtc"))] {
let tc_sender_with_shared_pool =
PacketSenderWithSharedPool::new(tc_source_tx, shared_tc_pool_wrapper.clone());
let tc_in_mem_converter =
EcssTcInMemConverter::Static(EcssTcInSharedPoolConverter::new(shared_tc_pool, 4096));
} else if #[cfg(feature = "heap_tmtc")] {
let tc_in_mem_converter = EcssTcInMemConverter::Heap(EcssTcInVecConverter::default());
}
}
// Create event handling components // Create event handling components
// These sender handles are used to send event requests, for example to enable or disable // These sender handles are used to send event requests, for example to enable or disable
@ -117,17 +148,24 @@ fn static_tmtc_pool_main() {
// in the sat-rs documentation. // in the sat-rs documentation.
let mut event_handler = EventHandler::new(tm_sink_tx.clone(), event_rx, event_request_rx); let mut event_handler = EventHandler::new(tm_sink_tx.clone(), event_rx, event_request_rx);
let (pus_test_tx, pus_test_rx) = mpsc::channel(); let (pus_test_tx, pus_test_rx) = mpsc::sync_channel(20);
let (pus_event_tx, pus_event_rx) = mpsc::channel(); let (pus_event_tx, pus_event_rx) = mpsc::sync_channel(10);
let (pus_sched_tx, pus_sched_rx) = mpsc::channel(); let (pus_sched_tx, pus_sched_rx) = mpsc::sync_channel(50);
let (pus_hk_tx, pus_hk_rx) = mpsc::channel(); let (pus_hk_tx, pus_hk_rx) = mpsc::sync_channel(50);
let (pus_action_tx, pus_action_rx) = mpsc::channel(); let (pus_action_tx, pus_action_rx) = mpsc::sync_channel(50);
let (pus_mode_tx, pus_mode_rx) = mpsc::channel(); let (pus_mode_tx, pus_mode_rx) = mpsc::sync_channel(50);
let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::channel(); let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::channel();
let (pus_hk_reply_tx, pus_hk_reply_rx) = mpsc::channel(); let (pus_hk_reply_tx, pus_hk_reply_rx) = mpsc::sync_channel(50);
let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::channel(); let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::sync_channel(30);
cfg_if::cfg_if! {
if #[cfg(not(feature = "heap_tmtc"))] {
let tc_releaser = TcReleaser::Static(tc_sender_with_shared_pool.clone());
} else if #[cfg(feature = "heap_tmtc")] {
let tc_releaser = TcReleaser::Heap(tc_source_tx.clone());
}
}
let pus_router = PusTcMpscRouter { let pus_router = PusTcMpscRouter {
test_tc_sender: pus_test_tx, test_tc_sender: pus_test_tx,
event_tc_sender: pus_event_tx, event_tc_sender: pus_event_tx,
@ -136,41 +174,42 @@ fn static_tmtc_pool_main() {
action_tc_sender: pus_action_tx, action_tc_sender: pus_action_tx,
mode_tc_sender: pus_mode_tx, mode_tc_sender: pus_mode_tx,
}; };
let pus_test_service = create_test_service_static( let pus_test_service = create_test_service(
tm_sink_tx_sender.clone(), tm_sender.clone(),
shared_tc_pool.clone(), tc_in_mem_converter.clone(),
event_tx.clone(), event_tx.clone(),
pus_test_rx, pus_test_rx,
); );
let pus_scheduler_service = create_scheduler_service_static( let pus_scheduler_service = create_scheduler_service(
tm_sink_tx_sender.clone(), tm_sender.clone(),
tc_source.clone(), tc_in_mem_converter.clone(),
tc_releaser,
pus_sched_rx, pus_sched_rx,
create_sched_tc_pool(), create_sched_tc_pool(),
); );
let pus_event_service = create_event_service_static( let pus_event_service = create_event_service(
tm_sink_tx_sender.clone(), tm_sender.clone(),
shared_tc_pool.clone(), tc_in_mem_converter.clone(),
pus_event_rx, pus_event_rx,
event_request_tx, event_request_tx,
); );
let pus_action_service = create_action_service_static( let pus_action_service = create_action_service(
tm_sink_tx_sender.clone(), tm_sender.clone(),
shared_tc_pool.clone(), tc_in_mem_converter.clone(),
pus_action_rx, pus_action_rx,
request_map.clone(), request_map.clone(),
pus_action_reply_rx, pus_action_reply_rx,
); );
let pus_hk_service = create_hk_service_static( let pus_hk_service = create_hk_service(
tm_sink_tx_sender.clone(), tm_sender.clone(),
shared_tc_pool.clone(), tc_in_mem_converter.clone(),
pus_hk_rx, pus_hk_rx,
request_map.clone(), request_map.clone(),
pus_hk_reply_rx, pus_hk_reply_rx,
); );
let pus_mode_service = create_mode_service_static( let pus_mode_service = create_mode_service(
tm_sink_tx_sender.clone(), tm_sender.clone(),
shared_tc_pool.clone(), tc_in_mem_converter.clone(),
pus_mode_rx, pus_mode_rx,
request_map, request_map,
pus_mode_reply_rx, pus_mode_reply_rx,
@ -184,21 +223,36 @@ fn static_tmtc_pool_main() {
pus_mode_service, pus_mode_service,
); );
let mut tmtc_task = TcSourceTaskStatic::new( cfg_if::cfg_if! {
if #[cfg(not(feature = "heap_tmtc"))] {
let mut tmtc_task = TcSourceTask::Static(TcSourceTaskStatic::new(
shared_tc_pool_wrapper.clone(), shared_tc_pool_wrapper.clone(),
tc_source_rx, tc_source_rx,
PusTcDistributor::new(tm_sink_tx_sender, pus_router), PusTcDistributor::new(tm_sender.clone(), pus_router),
); ));
let tc_sender = TmTcSender::Static(tc_sender_with_shared_pool);
let udp_tm_handler = StaticUdpTmHandler {
tm_rx: tm_server_rx,
tm_store: shared_tm_pool.clone(),
};
} else if #[cfg(feature = "heap_tmtc")] {
let mut tmtc_task = TcSourceTask::Heap(TcSourceTaskDynamic::new(
tc_source_rx,
PusTcDistributor::new(tm_sender.clone(), pus_router),
));
let tc_sender = TmTcSender::Heap(tc_source_tx.clone());
let udp_tm_handler = DynamicUdpTmHandler {
tm_rx: tm_server_rx,
};
}
}
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT); let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
let udp_tc_server = UdpTcServer::new(UDP_SERVER.id(), sock_addr, 2048, tc_source.clone()) let udp_tc_server = UdpTcServer::new(UDP_SERVER.id(), sock_addr, 2048, tc_sender.clone())
.expect("creating UDP TMTC server failed"); .expect("creating UDP TMTC server failed");
let mut udp_tmtc_server = UdpTmtcServer { let mut udp_tmtc_server = UdpTmtcServer {
udp_tc_server, udp_tc_server,
tm_handler: StaticUdpTmHandler { tm_handler: udp_tm_handler,
tm_rx: tm_server_rx,
tm_store: shared_tm_pool.clone(),
},
}; };
let tcp_server_cfg = ServerConfig::new( let tcp_server_cfg = ServerConfig::new(
@ -212,32 +266,35 @@ fn static_tmtc_pool_main() {
let mut tcp_server = TcpTask::new( let mut tcp_server = TcpTask::new(
tcp_server_cfg, tcp_server_cfg,
sync_tm_tcp_source.clone(), sync_tm_tcp_source.clone(),
tc_source.clone(), tc_sender,
PACKET_ID_VALIDATOR.clone(), PACKET_ID_VALIDATOR.clone(),
) )
.expect("tcp server creation failed"); .expect("tcp server creation failed");
let mut tm_sink = TmSinkStatic::new( cfg_if::cfg_if! {
if #[cfg(not(feature = "heap_tmtc"))] {
let mut tm_sink = TmSink::Static(TmSinkStatic::new(
shared_tm_pool_wrapper, shared_tm_pool_wrapper,
sync_tm_tcp_source, sync_tm_tcp_source,
tm_sink_rx, tm_sink_rx,
tm_server_tx, tm_server_tx,
); ));
} else if #[cfg(feature = "heap_tmtc")] {
let (mgm_handler_mode_reply_to_parent_tx, _mgm_handler_mode_reply_to_parent_rx) = let mut tm_sink = TmSink::Heap(TmSinkDynamic::new(
mpsc::sync_channel(5); sync_tm_tcp_source,
tm_sink_rx,
tm_server_tx,
));
}
}
let shared_switch_set = Arc::new(Mutex::default()); let shared_switch_set = Arc::new(Mutex::default());
let (switch_request_tx, switch_request_rx) = mpsc::sync_channel(20); let (switch_request_tx, switch_request_rx) = mpsc::sync_channel(20);
let switch_helper = PowerSwitchHelper::new(switch_request_tx, shared_switch_set.clone()); let switch_helper = PowerSwitchHelper::new(switch_request_tx, shared_switch_set.clone());
let shared_mgm_set = Arc::default(); let shared_mgm_set = Arc::default();
let mgm_mode_leaf_interface = MpscModeLeafInterface { let mgm_mode_node =
request_rx: mgm_handler_mode_rx, ModeRequestHandlerMpscBounded::new(MGM_HANDLER_0.into(), mgm_handler_mode_rx);
reply_to_pus_tx: pus_mode_reply_tx.clone(),
reply_to_parent_tx: mgm_handler_mode_reply_to_parent_tx,
};
let mgm_spi_interface = if let Some(sim_client) = opt_sim_client.as_mut() { let mgm_spi_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
sim_client.add_reply_recipient(satrs_minisim::SimComponent::MgmLis3Mdl, mgm_sim_reply_tx); sim_client.add_reply_recipient(satrs_minisim::SimComponent::MgmLis3Mdl, mgm_sim_reply_tx);
SpiSimInterfaceWrapper::Sim(SpiSimInterface { SpiSimInterfaceWrapper::Sim(SpiSimInterface {
@ -250,22 +307,22 @@ fn static_tmtc_pool_main() {
let mut mgm_handler = MgmHandlerLis3Mdl::new( let mut mgm_handler = MgmHandlerLis3Mdl::new(
MGM_HANDLER_0, MGM_HANDLER_0,
"MGM_0", "MGM_0",
mgm_mode_leaf_interface, mgm_mode_node,
mgm_handler_composite_rx, mgm_handler_composite_rx,
pus_hk_reply_tx.clone(), pus_hk_reply_tx.clone(),
switch_helper.clone(), switch_helper.clone(),
tm_sink_tx.clone(), tm_sender,
mgm_spi_interface, mgm_spi_interface,
shared_mgm_set, shared_mgm_set,
); );
// Connect PUS service to device handler.
connect_mode_nodes(
&mut pus_stack.mode_srv,
mgm_handler_mode_tx,
&mut mgm_handler,
pus_mode_reply_tx.clone(),
);
let (pcdu_handler_mode_reply_to_parent_tx, _pcdu_handler_mode_reply_to_parent_rx) =
mpsc::sync_channel(10);
let pcdu_mode_leaf_interface = MpscModeLeafInterface {
request_rx: pcdu_handler_mode_rx,
reply_to_pus_tx: pus_mode_reply_tx,
reply_to_parent_tx: pcdu_handler_mode_reply_to_parent_tx,
};
let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() { let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
sim_client.add_reply_recipient(satrs_minisim::SimComponent::Pcdu, pcdu_sim_reply_tx); sim_client.add_reply_recipient(satrs_minisim::SimComponent::Pcdu, pcdu_sim_reply_tx);
SerialSimInterfaceWrapper::Sim(SerialInterfaceToSim::new( SerialSimInterfaceWrapper::Sim(SerialInterfaceToSim::new(
@ -275,11 +332,12 @@ fn static_tmtc_pool_main() {
} else { } else {
SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default()) SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default())
}; };
let pcdu_mode_node =
ModeRequestHandlerMpscBounded::new(PCDU_HANDLER.into(), pcdu_handler_mode_rx);
let mut pcdu_handler = PcduHandler::new( let mut pcdu_handler = PcduHandler::new(
PCDU_HANDLER, PCDU_HANDLER,
"PCDU", "PCDU",
pcdu_mode_leaf_interface, pcdu_mode_node,
pcdu_handler_composite_rx, pcdu_handler_composite_rx,
pus_hk_reply_tx, pus_hk_reply_tx,
switch_request_rx, switch_request_rx,
@ -287,11 +345,21 @@ fn static_tmtc_pool_main() {
pcdu_serial_interface, pcdu_serial_interface,
shared_switch_set, shared_switch_set,
); );
connect_mode_nodes(
&mut pus_stack.mode_srv,
pcdu_handler_mode_tx.clone(),
&mut pcdu_handler,
pus_mode_reply_tx,
);
// The PCDU is a critical component which should be in normal mode immediately. // The PCDU is a critical component which should be in normal mode immediately.
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");
@ -357,11 +425,13 @@ fn static_tmtc_pool_main() {
.spawn(move || loop { .spawn(move || loop {
// TODO: We should introduce something like a fixed timeslot helper to allow a more // TODO: We should introduce something like a fixed timeslot helper to allow a more
// declarative API. It would also be very useful for the AOCS task. // declarative API. It would also be very useful for the AOCS task.
pcdu_handler.periodic_operation(eps::pcdu::OpCode::RegularOp); //
// TODO: The fixed timeslot handler exists.. use it.
pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::RegularOp);
thread::sleep(Duration::from_millis(50)); thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(eps::pcdu::OpCode::PollAndRecvReplies); pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(50)); thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(eps::pcdu::OpCode::PollAndRecvReplies); pcdu_handler.periodic_operation(crate::eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(300)); thread::sleep(Duration::from_millis(300));
}) })
.unwrap(); .unwrap();
@ -397,322 +467,6 @@ fn static_tmtc_pool_main() {
.expect("Joining PUS handler thread failed"); .expect("Joining PUS handler thread failed");
} }
#[allow(dead_code)]
fn dyn_tmtc_pool_main() {
let (tc_source_tx, tc_source_rx) = mpsc::channel();
let (tm_sink_tx, tm_sink_rx) = mpsc::channel();
let (tm_server_tx, tm_server_rx) = mpsc::channel();
let (sim_request_tx, sim_request_rx) = mpsc::channel();
let (mgm_sim_reply_tx, mgm_sim_reply_rx) = mpsc::channel();
let (pcdu_sim_reply_tx, pcdu_sim_reply_rx) = mpsc::channel();
let mut opt_sim_client = create_sim_client(sim_request_rx);
// Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let (mgm_handler_composite_tx, mgm_handler_composite_rx) =
mpsc::sync_channel::<GenericMessage<CompositeRequest>>(5);
let (pcdu_handler_composite_tx, pcdu_handler_composite_rx) =
mpsc::sync_channel::<GenericMessage<CompositeRequest>>(10);
let (mgm_handler_mode_tx, mgm_handler_mode_rx) =
mpsc::sync_channel::<GenericMessage<ModeRequest>>(5);
let (pcdu_handler_mode_tx, pcdu_handler_mode_rx) =
mpsc::sync_channel::<GenericMessage<ModeRequest>>(10);
// Some request are targetable. This map is used to retrieve sender handles based on a target ID.
let mut request_map = GenericRequestRouter::default();
request_map
.composite_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_composite_tx);
request_map
.mode_router_map
.insert(MGM_HANDLER_0.id(), mgm_handler_mode_tx);
request_map
.composite_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_composite_tx);
request_map
.mode_router_map
.insert(PCDU_HANDLER.id(), pcdu_handler_mode_tx.clone());
// Create event handling components
// These sender handles are used to send event requests, for example to enable or disable
// certain events.
let (event_tx, event_rx) = mpsc::sync_channel(100);
let (event_request_tx, event_request_rx) = mpsc::channel::<EventRequestWithToken>();
// The event task is the core handler to perform the event routing and TM handling as specified
// in the sat-rs documentation.
let mut event_handler = EventHandler::new(tm_sink_tx.clone(), event_rx, event_request_rx);
let (pus_test_tx, pus_test_rx) = mpsc::channel();
let (pus_event_tx, pus_event_rx) = mpsc::channel();
let (pus_sched_tx, pus_sched_rx) = mpsc::channel();
let (pus_hk_tx, pus_hk_rx) = mpsc::channel();
let (pus_action_tx, pus_action_rx) = mpsc::channel();
let (pus_mode_tx, pus_mode_rx) = mpsc::channel();
let (_pus_action_reply_tx, pus_action_reply_rx) = mpsc::channel();
let (pus_hk_reply_tx, pus_hk_reply_rx) = mpsc::channel();
let (pus_mode_reply_tx, pus_mode_reply_rx) = mpsc::channel();
let pus_router = PusTcMpscRouter {
test_tc_sender: pus_test_tx,
event_tc_sender: pus_event_tx,
sched_tc_sender: pus_sched_tx,
hk_tc_sender: pus_hk_tx,
action_tc_sender: pus_action_tx,
mode_tc_sender: pus_mode_tx,
};
let pus_test_service =
create_test_service_dynamic(tm_sink_tx.clone(), event_tx.clone(), pus_test_rx);
let pus_scheduler_service = create_scheduler_service_dynamic(
tm_sink_tx.clone(),
tc_source_tx.clone(),
pus_sched_rx,
create_sched_tc_pool(),
);
let pus_event_service =
create_event_service_dynamic(tm_sink_tx.clone(), pus_event_rx, event_request_tx);
let pus_action_service = create_action_service_dynamic(
tm_sink_tx.clone(),
pus_action_rx,
request_map.clone(),
pus_action_reply_rx,
);
let pus_hk_service = create_hk_service_dynamic(
tm_sink_tx.clone(),
pus_hk_rx,
request_map.clone(),
pus_hk_reply_rx,
);
let pus_mode_service = create_mode_service_dynamic(
tm_sink_tx.clone(),
pus_mode_rx,
request_map,
pus_mode_reply_rx,
);
let mut pus_stack = PusStack::new(
pus_test_service,
pus_hk_service,
pus_event_service,
pus_action_service,
pus_scheduler_service,
pus_mode_service,
);
let mut tmtc_task = TcSourceTaskDynamic::new(
tc_source_rx,
PusTcDistributor::new(tm_sink_tx.clone(), pus_router),
);
let sock_addr = SocketAddr::new(IpAddr::V4(OBSW_SERVER_ADDR), SERVER_PORT);
let udp_tc_server = UdpTcServer::new(UDP_SERVER.id(), sock_addr, 2048, tc_source_tx.clone())
.expect("creating UDP TMTC server failed");
let mut udp_tmtc_server = UdpTmtcServer {
udp_tc_server,
tm_handler: DynamicUdpTmHandler {
tm_rx: tm_server_rx,
},
};
let tcp_server_cfg = ServerConfig::new(
TCP_SERVER.id(),
sock_addr,
Duration::from_millis(400),
4096,
8192,
);
let sync_tm_tcp_source = SyncTcpTmSource::new(200);
let mut tcp_server = TcpTask::new(
tcp_server_cfg,
sync_tm_tcp_source.clone(),
tc_source_tx.clone(),
PACKET_ID_VALIDATOR.clone(),
)
.expect("tcp server creation failed");
let mut tm_funnel = TmSinkDynamic::new(sync_tm_tcp_source, tm_sink_rx, tm_server_tx);
let shared_switch_set = Arc::new(Mutex::default());
let (switch_request_tx, switch_request_rx) = mpsc::sync_channel(20);
let switch_helper = PowerSwitchHelper::new(switch_request_tx, shared_switch_set.clone());
let (mgm_handler_mode_reply_to_parent_tx, _mgm_handler_mode_reply_to_parent_rx) =
mpsc::sync_channel(5);
let shared_mgm_set = Arc::default();
let mode_leaf_interface = MpscModeLeafInterface {
request_rx: mgm_handler_mode_rx,
reply_to_pus_tx: pus_mode_reply_tx.clone(),
reply_to_parent_tx: mgm_handler_mode_reply_to_parent_tx,
};
let mgm_spi_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
sim_client.add_reply_recipient(satrs_minisim::SimComponent::MgmLis3Mdl, mgm_sim_reply_tx);
SpiSimInterfaceWrapper::Sim(SpiSimInterface {
sim_request_tx: sim_request_tx.clone(),
sim_reply_rx: mgm_sim_reply_rx,
})
} else {
SpiSimInterfaceWrapper::Dummy(SpiDummyInterface::default())
};
let mut mgm_handler = MgmHandlerLis3Mdl::new(
MGM_HANDLER_0,
"MGM_0",
mode_leaf_interface,
mgm_handler_composite_rx,
pus_hk_reply_tx.clone(),
switch_helper.clone(),
tm_sink_tx.clone(),
mgm_spi_interface,
shared_mgm_set,
);
let (pcdu_handler_mode_reply_to_parent_tx, _pcdu_handler_mode_reply_to_parent_rx) =
mpsc::sync_channel(10);
let pcdu_mode_leaf_interface = MpscModeLeafInterface {
request_rx: pcdu_handler_mode_rx,
reply_to_pus_tx: pus_mode_reply_tx,
reply_to_parent_tx: pcdu_handler_mode_reply_to_parent_tx,
};
let pcdu_serial_interface = if let Some(sim_client) = opt_sim_client.as_mut() {
sim_client.add_reply_recipient(satrs_minisim::SimComponent::Pcdu, pcdu_sim_reply_tx);
SerialSimInterfaceWrapper::Sim(SerialInterfaceToSim::new(
sim_request_tx.clone(),
pcdu_sim_reply_rx,
))
} else {
SerialSimInterfaceWrapper::Dummy(SerialInterfaceDummy::default())
};
let mut pcdu_handler = PcduHandler::new(
PCDU_HANDLER,
"PCDU",
pcdu_mode_leaf_interface,
pcdu_handler_composite_rx,
pus_hk_reply_tx,
switch_request_rx,
tm_sink_tx,
pcdu_serial_interface,
shared_switch_set,
);
// The PCDU is a critical component which should be in normal mode immediately.
pcdu_handler_mode_tx
.send(GenericMessage::new(
MessageMetadata::new(0, NO_SENDER),
ModeRequest::SetMode(ModeAndSubmode::new(DeviceMode::Normal as Mode, 0)),
))
.expect("sending initial mode request failed");
info!("Starting TMTC and UDP task");
let jh_udp_tmtc = thread::Builder::new()
.name("sat-rs tmtc-udp".to_string())
.spawn(move || {
info!("Running UDP server on port {SERVER_PORT}");
loop {
udp_tmtc_server.periodic_operation();
tmtc_task.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_UDP_TMTC));
}
})
.unwrap();
info!("Starting TCP task");
let jh_tcp = thread::Builder::new()
.name("sat-rs tcp".to_string())
.spawn(move || {
info!("Running TCP server on port {SERVER_PORT}");
loop {
tcp_server.periodic_operation();
}
})
.unwrap();
info!("Starting TM funnel task");
let jh_tm_funnel = thread::Builder::new()
.name("sat-rs tm-sink".to_string())
.spawn(move || loop {
tm_funnel.operation();
})
.unwrap();
let mut opt_jh_sim_client = None;
if let Some(mut sim_client) = opt_sim_client {
info!("Starting UDP sim client task");
opt_jh_sim_client = Some(
thread::Builder::new()
.name("sat-rs sim adapter".to_string())
.spawn(move || loop {
if sim_client.operation() == HandlingStatus::Empty {
std::thread::sleep(Duration::from_millis(SIM_CLIENT_IDLE_DELAY_MS));
}
})
.unwrap(),
);
}
info!("Starting AOCS thread");
let jh_aocs = thread::Builder::new()
.name("sat-rs aocs".to_string())
.spawn(move || loop {
mgm_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_AOCS));
})
.unwrap();
info!("Starting EPS thread");
let jh_eps = thread::Builder::new()
.name("sat-rs eps".to_string())
.spawn(move || loop {
// TODO: We should introduce something like a fixed timeslot helper to allow a more
// declarative API. It would also be very useful for the AOCS task.
pcdu_handler.periodic_operation(eps::pcdu::OpCode::RegularOp);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(50));
pcdu_handler.periodic_operation(eps::pcdu::OpCode::PollAndRecvReplies);
thread::sleep(Duration::from_millis(300));
})
.unwrap();
info!("Starting PUS handler thread");
let jh_pus_handler = thread::Builder::new()
.name("sat-rs pus".to_string())
.spawn(move || loop {
pus_stack.periodic_operation();
event_handler.periodic_operation();
thread::sleep(Duration::from_millis(FREQ_MS_PUS_STACK));
})
.unwrap();
jh_udp_tmtc
.join()
.expect("Joining UDP TMTC server thread failed");
jh_tcp
.join()
.expect("Joining TCP TMTC server thread failed");
jh_tm_funnel
.join()
.expect("Joining TM Funnel thread failed");
if let Some(jh_sim_client) = opt_jh_sim_client {
jh_sim_client
.join()
.expect("Joining SIM client thread failed");
}
jh_aocs.join().expect("Joining AOCS thread failed");
jh_eps.join().expect("Joining EPS thread failed");
jh_pus_handler
.join()
.expect("Joining PUS handler thread failed");
}
fn main() {
setup_logger().expect("setting up logging with fern failed");
println!("Running OBSW example");
#[cfg(not(feature = "dyn_tmtc"))]
static_tmtc_pool_main();
#[cfg(feature = "dyn_tmtc")]
dyn_tmtc_pool_main();
}
pub fn update_time(time_provider: &mut CdsTime, timestamp: &mut [u8]) { pub fn update_time(time_provider: &mut CdsTime, timestamp: &mut [u8]) {
time_provider time_provider
.update_from_now() .update_from_now()

View File

@ -1,6 +1,5 @@
use log::warn; use log::warn;
use satrs::action::{ActionRequest, ActionRequestVariant}; use satrs::action::{ActionRequest, ActionRequestVariant};
use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::action::{ use satrs::pus::action::{
ActionReplyPus, ActionReplyVariant, ActivePusActionRequestStd, DefaultActiveActionRequestMap, ActionReplyPus, ActionReplyVariant, ActivePusActionRequestStd, DefaultActiveActionRequestMap,
}; };
@ -10,21 +9,20 @@ use satrs::pus::verification::{
VerificationReportingProvider, VerificationToken, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter, EcssTmSender, EcssTmtcError,
EcssTcInVecConverter, EcssTmSender, EcssTmtcError, GenericConversionError, MpscTcReceiver, GenericConversionError, MpscTcReceiver, PusPacketHandlingError, PusReplyHandler,
MpscTmAsVecSender, PusPacketHandlingError, PusReplyHandler, PusServiceHelper, PusServiceHelper, PusTcToRequestConverter,
PusTcToRequestConverter,
}; };
use satrs::request::{GenericMessage, UniqueApidTargetId}; use satrs::request::{GenericMessage, UniqueApidTargetId};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{EcssEnumU16, PusPacket, PusServiceId}; use satrs::spacepackets::ecss::{EcssEnumU16, PusPacket, PusServiceId};
use satrs::tmtc::{PacketAsVec, PacketSenderWithSharedPool};
use satrs_example::config::components::PUS_ACTION_SERVICE; use satrs_example::config::components::PUS_ACTION_SERVICE;
use satrs_example::config::tmtc_err; use satrs_example::config::tmtc_err;
use std::sync::mpsc; use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use crate::tmtc::sender::TmTcSender;
use super::{ use super::{
create_verification_reporter, generic_pus_request_timeout_handler, HandlingStatus, create_verification_reporter, generic_pus_request_timeout_handler, HandlingStatus,
@ -207,20 +205,20 @@ impl PusTcToRequestConverter<ActivePusActionRequestStd, ActionRequest> for Actio
} }
} }
pub fn create_action_service_static( pub fn create_action_service(
tm_sender: PacketSenderWithSharedPool, tm_sender: TmTcSender,
tc_pool: SharedStaticMemoryPool, tc_in_mem_converter: EcssTcInMemConverter,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>, pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
action_router: GenericRequestRouter, action_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<ActionReplyPus>>, reply_receiver: mpsc::Receiver<GenericMessage<ActionReplyPus>>,
) -> ActionServiceWrapper<PacketSenderWithSharedPool, EcssTcInSharedStoreConverter> { ) -> ActionServiceWrapper {
let action_request_handler = PusTargetedRequestService::new( let action_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new( PusServiceHelper::new(
PUS_ACTION_SERVICE.id(), PUS_ACTION_SERVICE.id(),
pus_action_rx, pus_action_rx,
tm_sender, tm_sender,
create_verification_reporter(PUS_ACTION_SERVICE.id(), PUS_ACTION_SERVICE.apid), create_verification_reporter(PUS_ACTION_SERVICE.id(), PUS_ACTION_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048), tc_in_mem_converter,
), ),
ActionRequestConverter::default(), ActionRequestConverter::default(),
// TODO: Implementation which does not use run-time allocation? Maybe something like // TODO: Implementation which does not use run-time allocation? Maybe something like
@ -235,36 +233,11 @@ pub fn create_action_service_static(
} }
} }
pub fn create_action_service_dynamic( pub struct ActionServiceWrapper {
tm_funnel_tx: mpsc::Sender<PacketAsVec>,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
action_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<ActionReplyPus>>,
) -> ActionServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
let action_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_ACTION_SERVICE.id(),
pus_action_rx,
tm_funnel_tx,
create_verification_reporter(PUS_ACTION_SERVICE.id(), PUS_ACTION_SERVICE.apid),
EcssTcInVecConverter::default(),
),
ActionRequestConverter::default(),
DefaultActiveActionRequestMap::default(),
ActionReplyHandler::default(),
action_router,
reply_receiver,
);
ActionServiceWrapper {
service: action_request_handler,
}
}
pub struct ActionServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> {
pub(crate) service: PusTargetedRequestService< pub(crate) service: PusTargetedRequestService<
MpscTcReceiver, MpscTcReceiver,
TmSender, TmTcSender,
TcInMemConverter, EcssTcInMemConverter,
VerificationReporter, VerificationReporter,
ActionRequestConverter, ActionRequestConverter,
ActionReplyHandler, ActionReplyHandler,
@ -275,9 +248,7 @@ pub struct ActionServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTc
>, >,
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> TargetedPusService impl TargetedPusService for ActionServiceWrapper {
for ActionServiceWrapper<TmSender, TcInMemConverter>
{
const SERVICE_ID: u8 = PusServiceId::Action as u8; const SERVICE_ID: u8 = PusServiceId::Action as u8;
const SERVICE_STR: &'static str = "action"; const SERVICE_STR: &'static str = "action";
@ -303,9 +274,10 @@ mod tests {
use satrs::pus::test_util::{ use satrs::pus::test_util::{
TEST_APID, TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1, TEST_UNIQUE_ID_0, TEST_UNIQUE_ID_1, TEST_APID, TEST_COMPONENT_ID_0, TEST_COMPONENT_ID_1, TEST_UNIQUE_ID_0, TEST_UNIQUE_ID_1,
}; };
use satrs::pus::verification;
use satrs::pus::verification::test_util::TestVerificationReporter; use satrs::pus::verification::test_util::TestVerificationReporter;
use satrs::pus::{verification, EcssTcInVecConverter};
use satrs::request::MessageMetadata; use satrs::request::MessageMetadata;
use satrs::tmtc::PacketAsVec;
use satrs::ComponentId; use satrs::ComponentId;
use satrs::{ use satrs::{
res_code::ResultU16, res_code::ResultU16,

View File

@ -1,34 +1,32 @@
use std::sync::mpsc; use std::sync::mpsc;
use crate::pus::create_verification_reporter; use crate::pus::create_verification_reporter;
use satrs::pool::SharedStaticMemoryPool; use crate::tmtc::sender::TmTcSender;
use satrs::pus::event_man::EventRequestWithToken; use satrs::pus::event_man::EventRequestWithToken;
use satrs::pus::event_srv::PusEventServiceHandler; use satrs::pus::event_srv::PusEventServiceHandler;
use satrs::pus::verification::VerificationReporter; use satrs::pus::verification::VerificationReporter;
use satrs::pus::{ use satrs::pus::{
DirectPusPacketHandlerResult, EcssTcAndToken, EcssTcInMemConverter, DirectPusPacketHandlerResult, EcssTcAndToken, EcssTcInMemConverter, MpscTcReceiver,
EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTmSender, MpscTcReceiver, PartialPusHandlingError, PusServiceHelper,
MpscTmAsVecSender, PartialPusHandlingError, PusServiceHelper,
}; };
use satrs::spacepackets::ecss::PusServiceId; use satrs::spacepackets::ecss::PusServiceId;
use satrs::tmtc::{PacketAsVec, PacketSenderWithSharedPool};
use satrs_example::config::components::PUS_EVENT_MANAGEMENT; use satrs_example::config::components::PUS_EVENT_MANAGEMENT;
use super::{DirectPusService, HandlingStatus}; use super::{DirectPusService, HandlingStatus};
pub fn create_event_service_static( pub fn create_event_service(
tm_sender: PacketSenderWithSharedPool, tm_sender: TmTcSender,
tc_pool: SharedStaticMemoryPool, tm_in_pool_converter: EcssTcInMemConverter,
pus_event_rx: mpsc::Receiver<EcssTcAndToken>, pus_event_rx: mpsc::Receiver<EcssTcAndToken>,
event_request_tx: mpsc::Sender<EventRequestWithToken>, event_request_tx: mpsc::Sender<EventRequestWithToken>,
) -> EventServiceWrapper<PacketSenderWithSharedPool, EcssTcInSharedStoreConverter> { ) -> EventServiceWrapper {
let pus_5_handler = PusEventServiceHandler::new( let pus_5_handler = PusEventServiceHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
PUS_EVENT_MANAGEMENT.id(), PUS_EVENT_MANAGEMENT.id(),
pus_event_rx, pus_event_rx,
tm_sender, tm_sender,
create_verification_reporter(PUS_EVENT_MANAGEMENT.id(), PUS_EVENT_MANAGEMENT.apid), create_verification_reporter(PUS_EVENT_MANAGEMENT.id(), PUS_EVENT_MANAGEMENT.apid),
EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048), tm_in_pool_converter,
), ),
event_request_tx, event_request_tx,
); );
@ -37,34 +35,16 @@ pub fn create_event_service_static(
} }
} }
pub fn create_event_service_dynamic( pub struct EventServiceWrapper {
tm_funnel_tx: mpsc::Sender<PacketAsVec>, pub handler: PusEventServiceHandler<
pus_event_rx: mpsc::Receiver<EcssTcAndToken>, MpscTcReceiver,
event_request_tx: mpsc::Sender<EventRequestWithToken>, TmTcSender,
) -> EventServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> { EcssTcInMemConverter,
let pus_5_handler = PusEventServiceHandler::new( VerificationReporter,
PusServiceHelper::new( >,
PUS_EVENT_MANAGEMENT.id(),
pus_event_rx,
tm_funnel_tx,
create_verification_reporter(PUS_EVENT_MANAGEMENT.id(), PUS_EVENT_MANAGEMENT.apid),
EcssTcInVecConverter::default(),
),
event_request_tx,
);
EventServiceWrapper {
handler: pus_5_handler,
}
} }
pub struct EventServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> { impl DirectPusService for EventServiceWrapper {
pub handler:
PusEventServiceHandler<MpscTcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
}
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> DirectPusService
for EventServiceWrapper<TmSender, TcInMemConverter>
{
const SERVICE_ID: u8 = PusServiceId::Event as u8; const SERVICE_ID: u8 = PusServiceId::Event as u8;
const SERVICE_STR: &'static str = "events"; const SERVICE_STR: &'static str = "events";

View File

@ -1,21 +1,18 @@
use derive_new::new; use derive_new::new;
use satrs::hk::{CollectionIntervalFactor, HkRequest, HkRequestVariant, UniqueId}; use satrs::hk::{CollectionIntervalFactor, HkRequest, HkRequestVariant, UniqueId};
use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, TcStateAccepted, TcStateStarted, VerificationReporter, FailParams, TcStateAccepted, TcStateStarted, VerificationReporter,
VerificationReportingProvider, VerificationToken, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap, EcssTcAndToken, ActivePusRequestStd, ActiveRequestProvider, DefaultActiveRequestMap, EcssTcAndToken,
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTmSender, EcssTcInMemConverter, EcssTmSender, EcssTmtcError, GenericConversionError, MpscTcReceiver,
EcssTmtcError, GenericConversionError, MpscTcReceiver, MpscTmAsVecSender,
PusPacketHandlingError, PusReplyHandler, PusServiceHelper, PusTcToRequestConverter, PusPacketHandlingError, PusReplyHandler, PusServiceHelper, PusTcToRequestConverter,
}; };
use satrs::request::{GenericMessage, UniqueApidTargetId}; use satrs::request::{GenericMessage, UniqueApidTargetId};
use satrs::res_code::ResultU16; use satrs::res_code::ResultU16;
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{hk, PusPacket, PusServiceId}; use satrs::spacepackets::ecss::{hk, PusPacket, PusServiceId};
use satrs::tmtc::{PacketAsVec, PacketSenderWithSharedPool};
use satrs_example::config::components::PUS_HK_SERVICE; use satrs_example::config::components::PUS_HK_SERVICE;
use satrs_example::config::{hk_err, tmtc_err}; use satrs_example::config::{hk_err, tmtc_err};
use std::sync::mpsc; use std::sync::mpsc;
@ -23,6 +20,7 @@ use std::time::Duration;
use crate::pus::{create_verification_reporter, generic_pus_request_timeout_handler}; use crate::pus::{create_verification_reporter, generic_pus_request_timeout_handler};
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use crate::tmtc::sender::TmTcSender;
use super::{HandlingStatus, PusTargetedRequestService, TargetedPusService}; use super::{HandlingStatus, PusTargetedRequestService, TargetedPusService};
@ -242,20 +240,20 @@ impl PusTcToRequestConverter<ActivePusRequestStd, HkRequest> for HkRequestConver
} }
} }
pub fn create_hk_service_static( pub fn create_hk_service(
tm_sender: PacketSenderWithSharedPool, tm_sender: TmTcSender,
tc_pool: SharedStaticMemoryPool, tc_in_mem_converter: EcssTcInMemConverter,
pus_hk_rx: mpsc::Receiver<EcssTcAndToken>, pus_hk_rx: mpsc::Receiver<EcssTcAndToken>,
request_router: GenericRequestRouter, request_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>, reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>,
) -> HkServiceWrapper<PacketSenderWithSharedPool, EcssTcInSharedStoreConverter> { ) -> HkServiceWrapper {
let pus_3_handler = PusTargetedRequestService::new( let pus_3_handler = PusTargetedRequestService::new(
PusServiceHelper::new( PusServiceHelper::new(
PUS_HK_SERVICE.id(), PUS_HK_SERVICE.id(),
pus_hk_rx, pus_hk_rx,
tm_sender, tm_sender,
create_verification_reporter(PUS_HK_SERVICE.id(), PUS_HK_SERVICE.apid), create_verification_reporter(PUS_HK_SERVICE.id(), PUS_HK_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool, 2048), tc_in_mem_converter,
), ),
HkRequestConverter::default(), HkRequestConverter::default(),
DefaultActiveRequestMap::default(), DefaultActiveRequestMap::default(),
@ -268,36 +266,11 @@ pub fn create_hk_service_static(
} }
} }
pub fn create_hk_service_dynamic( pub struct HkServiceWrapper {
tm_funnel_tx: mpsc::Sender<PacketAsVec>,
pus_hk_rx: mpsc::Receiver<EcssTcAndToken>,
request_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<HkReply>>,
) -> HkServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
let pus_3_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_HK_SERVICE.id(),
pus_hk_rx,
tm_funnel_tx,
create_verification_reporter(PUS_HK_SERVICE.id(), PUS_HK_SERVICE.apid),
EcssTcInVecConverter::default(),
),
HkRequestConverter::default(),
DefaultActiveRequestMap::default(),
HkReplyHandler::default(),
request_router,
reply_receiver,
);
HkServiceWrapper {
service: pus_3_handler,
}
}
pub struct HkServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> {
pub(crate) service: PusTargetedRequestService< pub(crate) service: PusTargetedRequestService<
MpscTcReceiver, MpscTcReceiver,
TmSender, TmTcSender,
TcInMemConverter, EcssTcInMemConverter,
VerificationReporter, VerificationReporter,
HkRequestConverter, HkRequestConverter,
HkReplyHandler, HkReplyHandler,
@ -308,9 +281,7 @@ pub struct HkServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMe
>, >,
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> TargetedPusService impl TargetedPusService for HkServiceWrapper {
for HkServiceWrapper<TmSender, TcInMemConverter>
{
const SERVICE_ID: u8 = PusServiceId::Housekeeping as u8; const SERVICE_ID: u8 = PusServiceId::Housekeeping as u8;
const SERVICE_STR: &'static str = "housekeeping"; const SERVICE_STR: &'static str = "housekeeping";

View File

@ -1,4 +1,5 @@
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use crate::tmtc::sender::TmTcSender;
use log::warn; use log::warn;
use satrs::pool::PoolAddr; use satrs::pool::PoolAddr;
use satrs::pus::verification::{ use satrs::pus::verification::{
@ -6,7 +7,7 @@ use satrs::pus::verification::{
VerificationReporterCfg, VerificationReportingProvider, VerificationToken, VerificationReporterCfg, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
ActiveRequestMapProvider, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConverter, ActiveRequestMapProvider, ActiveRequestProvider, EcssTcAndToken, EcssTcInMemConversionProvider,
EcssTcReceiver, EcssTmSender, EcssTmtcError, GenericConversionError, GenericRoutingError, EcssTcReceiver, EcssTmSender, EcssTmtcError, GenericConversionError, GenericRoutingError,
HandlingStatus, PusPacketHandlingError, PusReplyHandler, PusRequestRouter, PusServiceHelper, HandlingStatus, PusPacketHandlingError, PusReplyHandler, PusRequestRouter, PusServiceHelper,
PusTcToRequestConverter, TcInMemory, PusTcToRequestConverter, TcInMemory,
@ -21,7 +22,7 @@ use satrs_example::config::components::PUS_ROUTING_SERVICE;
use satrs_example::config::{tmtc_err, CustomPusServiceId}; use satrs_example::config::{tmtc_err, CustomPusServiceId};
use satrs_example::TimestampHelper; use satrs_example::TimestampHelper;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::mpsc::{self, Sender}; use std::sync::mpsc;
pub mod action; pub mod action;
pub mod event; pub mod event;
@ -40,26 +41,26 @@ pub fn create_verification_reporter(owner_id: ComponentId, apid: Apid) -> Verifi
/// Simple router structure which forwards PUS telecommands to dedicated handlers. /// Simple router structure which forwards PUS telecommands to dedicated handlers.
pub struct PusTcMpscRouter { pub struct PusTcMpscRouter {
pub test_tc_sender: Sender<EcssTcAndToken>, pub test_tc_sender: mpsc::SyncSender<EcssTcAndToken>,
pub event_tc_sender: Sender<EcssTcAndToken>, pub event_tc_sender: mpsc::SyncSender<EcssTcAndToken>,
pub sched_tc_sender: Sender<EcssTcAndToken>, pub sched_tc_sender: mpsc::SyncSender<EcssTcAndToken>,
pub hk_tc_sender: Sender<EcssTcAndToken>, pub hk_tc_sender: mpsc::SyncSender<EcssTcAndToken>,
#[allow(dead_code)] #[allow(dead_code)]
pub action_tc_sender: Sender<EcssTcAndToken>, pub action_tc_sender: mpsc::SyncSender<EcssTcAndToken>,
pub mode_tc_sender: Sender<EcssTcAndToken>, pub mode_tc_sender: mpsc::SyncSender<EcssTcAndToken>,
} }
pub struct PusTcDistributor<TmSender: EcssTmSender> { pub struct PusTcDistributor {
#[allow(dead_code)] #[allow(dead_code)]
pub id: ComponentId, pub id: ComponentId,
pub tm_sender: TmSender, pub tm_sender: TmTcSender,
pub verif_reporter: VerificationReporter, pub verif_reporter: VerificationReporter,
pub pus_router: PusTcMpscRouter, pub pus_router: PusTcMpscRouter,
stamp_helper: TimestampHelper, stamp_helper: TimestampHelper,
} }
impl<TmSender: EcssTmSender> PusTcDistributor<TmSender> { impl PusTcDistributor {
pub fn new(tm_sender: TmSender, pus_router: PusTcMpscRouter) -> Self { pub fn new(tm_sender: TmTcSender, pus_router: PusTcMpscRouter) -> Self {
Self { Self {
id: PUS_ROUTING_SERVICE.raw(), id: PUS_ROUTING_SERVICE.raw(),
tm_sender, tm_sender,
@ -269,7 +270,7 @@ pub trait DirectPusService {
pub struct PusTargetedRequestService< pub struct PusTargetedRequestService<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
RequestConverter: PusTcToRequestConverter<ActiveRequestInfo, RequestType, Error = GenericConversionError>, RequestConverter: PusTcToRequestConverter<ActiveRequestInfo, RequestType, Error = GenericConversionError>,
ReplyHandler: PusReplyHandler<ActiveRequestInfo, ReplyType, Error = EcssTmtcError>, ReplyHandler: PusReplyHandler<ActiveRequestInfo, ReplyType, Error = EcssTmtcError>,
@ -291,7 +292,7 @@ pub struct PusTargetedRequestService<
impl< impl<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
RequestConverter: PusTcToRequestConverter<ActiveRequestInfo, RequestType, Error = GenericConversionError>, RequestConverter: PusTcToRequestConverter<ActiveRequestInfo, RequestType, Error = GenericConversionError>,
ReplyHandler: PusReplyHandler<ActiveRequestInfo, ReplyType, Error = EcssTmtcError>, ReplyHandler: PusReplyHandler<ActiveRequestInfo, ReplyType, Error = EcssTmtcError>,

View File

@ -1,15 +1,14 @@
use derive_new::new; use derive_new::new;
use satrs::tmtc::{PacketAsVec, PacketSenderWithSharedPool}; use satrs::mode_tree::{ModeNode, ModeParent};
use std::sync::mpsc; use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use satrs::pool::SharedStaticMemoryPool; use crate::tmtc::sender::TmTcSender;
use satrs::pus::verification::VerificationReporter; use satrs::pus::verification::VerificationReporter;
use satrs::pus::{ use satrs::pus::{
DefaultActiveRequestMap, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, DefaultActiveRequestMap, EcssTcAndToken, EcssTcInMemConverter, MpscTcReceiver,
EcssTcInVecConverter, MpscTcReceiver, MpscTmAsVecSender, PusPacketHandlingError, PusPacketHandlingError, PusServiceHelper,
PusServiceHelper,
}; };
use satrs::request::GenericMessage; use satrs::request::GenericMessage;
use satrs::{ use satrs::{
@ -110,6 +109,7 @@ impl PusReplyHandler<ActivePusRequestStd, ModeReply> for ModeReplyHandler {
), ),
)?; )?;
} }
ModeReply::ModeInfo(_mode_and_submode) => (),
}; };
Ok(true) Ok(true)
} }
@ -190,7 +190,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)),
@ -202,20 +208,20 @@ impl PusTcToRequestConverter<ActivePusRequestStd, ModeRequest> for ModeRequestCo
} }
} }
pub fn create_mode_service_static( pub fn create_mode_service(
tm_sender: PacketSenderWithSharedPool, tm_sender: TmTcSender,
tc_pool: SharedStaticMemoryPool, tc_in_mem_converter: EcssTcInMemConverter,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>, pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
mode_router: GenericRequestRouter, mode_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<ModeReply>>, reply_receiver: mpsc::Receiver<GenericMessage<ModeReply>>,
) -> ModeServiceWrapper<PacketSenderWithSharedPool, EcssTcInSharedStoreConverter> { ) -> ModeServiceWrapper {
let mode_request_handler = PusTargetedRequestService::new( let mode_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new( PusServiceHelper::new(
PUS_MODE_SERVICE.id(), PUS_MODE_SERVICE.id(),
pus_action_rx, pus_action_rx,
tm_sender, tm_sender,
create_verification_reporter(PUS_MODE_SERVICE.id(), PUS_MODE_SERVICE.apid), create_verification_reporter(PUS_MODE_SERVICE.id(), PUS_MODE_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool, 2048), tc_in_mem_converter,
), ),
ModeRequestConverter::default(), ModeRequestConverter::default(),
DefaultActiveRequestMap::default(), DefaultActiveRequestMap::default(),
@ -228,36 +234,11 @@ pub fn create_mode_service_static(
} }
} }
pub fn create_mode_service_dynamic( pub struct ModeServiceWrapper {
tm_funnel_tx: mpsc::Sender<PacketAsVec>,
pus_action_rx: mpsc::Receiver<EcssTcAndToken>,
mode_router: GenericRequestRouter,
reply_receiver: mpsc::Receiver<GenericMessage<ModeReply>>,
) -> ModeServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
let mode_request_handler = PusTargetedRequestService::new(
PusServiceHelper::new(
PUS_MODE_SERVICE.id(),
pus_action_rx,
tm_funnel_tx,
create_verification_reporter(PUS_MODE_SERVICE.id(), PUS_MODE_SERVICE.apid),
EcssTcInVecConverter::default(),
),
ModeRequestConverter::default(),
DefaultActiveRequestMap::default(),
ModeReplyHandler::new(PUS_MODE_SERVICE.id()),
mode_router,
reply_receiver,
);
ModeServiceWrapper {
service: mode_request_handler,
}
}
pub struct ModeServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> {
pub(crate) service: PusTargetedRequestService< pub(crate) service: PusTargetedRequestService<
MpscTcReceiver, MpscTcReceiver,
TmSender, TmTcSender,
TcInMemConverter, EcssTcInMemConverter,
VerificationReporter, VerificationReporter,
ModeRequestConverter, ModeRequestConverter,
ModeReplyHandler, ModeReplyHandler,
@ -268,9 +249,24 @@ pub struct ModeServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcIn
>, >,
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> TargetedPusService impl ModeNode for ModeServiceWrapper {
for ModeServiceWrapper<TmSender, TcInMemConverter> fn id(&self) -> ComponentId {
{ self.service.service_helper.id()
}
}
impl ModeParent for ModeServiceWrapper {
type Sender = mpsc::SyncSender<GenericMessage<ModeRequest>>;
fn add_mode_child(&mut self, id: ComponentId, request_sender: Self::Sender) {
self.service
.request_router
.mode_router_map
.insert(id, request_sender);
}
}
impl TargetedPusService for ModeServiceWrapper {
const SERVICE_ID: u8 = CustomPusServiceId::Mode as u8; const SERVICE_ID: u8 = CustomPusServiceId::Mode as u8;
const SERVICE_STR: &'static str = "mode"; const SERVICE_STR: &'static str = "mode";
@ -346,7 +342,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

@ -2,15 +2,15 @@ use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use crate::pus::create_verification_reporter; use crate::pus::create_verification_reporter;
use crate::tmtc::sender::TmTcSender;
use log::info; use log::info;
use satrs::pool::{PoolProvider, StaticMemoryPool}; use satrs::pool::{PoolProvider, StaticMemoryPool};
use satrs::pus::scheduler::{PusScheduler, TcInfo}; use satrs::pus::scheduler::{PusScheduler, TcInfo};
use satrs::pus::scheduler_srv::PusSchedServiceHandler; use satrs::pus::scheduler_srv::PusSchedServiceHandler;
use satrs::pus::verification::VerificationReporter; use satrs::pus::verification::VerificationReporter;
use satrs::pus::{ use satrs::pus::{
DirectPusPacketHandlerResult, EcssTcAndToken, EcssTcInMemConverter, DirectPusPacketHandlerResult, EcssTcAndToken, EcssTcInMemConverter, MpscTcReceiver,
EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTmSender, MpscTcReceiver, PartialPusHandlingError, PusServiceHelper,
MpscTmAsVecSender, PartialPusHandlingError, PusServiceHelper,
}; };
use satrs::spacepackets::ecss::PusServiceId; use satrs::spacepackets::ecss::PusServiceId;
use satrs::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool}; use satrs::tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool};
@ -19,11 +19,11 @@ use satrs_example::config::components::PUS_SCHED_SERVICE;
use super::{DirectPusService, HandlingStatus}; use super::{DirectPusService, HandlingStatus};
pub trait TcReleaser { pub trait TcReleaseProvider {
fn release(&mut self, sender_id: ComponentId, enabled: bool, info: &TcInfo, tc: &[u8]) -> bool; fn release(&mut self, sender_id: ComponentId, enabled: bool, info: &TcInfo, tc: &[u8]) -> bool;
} }
impl TcReleaser for PacketSenderWithSharedPool { impl TcReleaseProvider for PacketSenderWithSharedPool {
fn release( fn release(
&mut self, &mut self,
sender_id: ComponentId, sender_id: ComponentId,
@ -48,7 +48,7 @@ impl TcReleaser for PacketSenderWithSharedPool {
} }
} }
impl TcReleaser for mpsc::Sender<PacketAsVec> { impl TcReleaseProvider for mpsc::SyncSender<PacketAsVec> {
fn release( fn release(
&mut self, &mut self,
sender_id: ComponentId, sender_id: ComponentId,
@ -65,23 +65,35 @@ impl TcReleaser for mpsc::Sender<PacketAsVec> {
} }
} }
pub struct SchedulingServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> #[allow(dead_code)]
{ pub enum TcReleaser {
Static(PacketSenderWithSharedPool),
Heap(mpsc::SyncSender<PacketAsVec>),
}
impl TcReleaseProvider for TcReleaser {
fn release(&mut self, sender_id: ComponentId, enabled: bool, info: &TcInfo, tc: &[u8]) -> bool {
match self {
TcReleaser::Static(sender) => sender.release(sender_id, enabled, info, tc),
TcReleaser::Heap(sender) => sender.release(sender_id, enabled, info, tc),
}
}
}
pub struct SchedulingServiceWrapper {
pub pus_11_handler: PusSchedServiceHandler< pub pus_11_handler: PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
TmSender, TmTcSender,
TcInMemConverter, EcssTcInMemConverter,
VerificationReporter, VerificationReporter,
PusScheduler, PusScheduler,
>, >,
pub sched_tc_pool: StaticMemoryPool, pub sched_tc_pool: StaticMemoryPool,
pub releaser_buf: [u8; 4096], pub releaser_buf: [u8; 4096],
pub tc_releaser: Box<dyn TcReleaser + Send>, pub tc_releaser: TcReleaser,
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> DirectPusService impl DirectPusService for SchedulingServiceWrapper {
for SchedulingServiceWrapper<TmSender, TcInMemConverter>
{
const SERVICE_ID: u8 = PusServiceId::Verification as u8; const SERVICE_ID: u8 = PusServiceId::Verification as u8;
const SERVICE_STR: &'static str = "verification"; const SERVICE_STR: &'static str = "verification";
@ -134,9 +146,7 @@ impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> DirectPusSe
} }
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> impl SchedulingServiceWrapper {
SchedulingServiceWrapper<TmSender, TcInMemConverter>
{
pub fn release_tcs(&mut self) { pub fn release_tcs(&mut self) {
let id = self.pus_11_handler.service_helper.id(); let id = self.pus_11_handler.service_helper.id();
let releaser = |enabled: bool, info: &TcInfo, tc: &[u8]| -> bool { let releaser = |enabled: bool, info: &TcInfo, tc: &[u8]| -> bool {
@ -162,12 +172,13 @@ impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter>
} }
} }
pub fn create_scheduler_service_static( pub fn create_scheduler_service(
tm_sender: PacketSenderWithSharedPool, tm_sender: TmTcSender,
tc_releaser: PacketSenderWithSharedPool, tc_in_mem_converter: EcssTcInMemConverter,
tc_releaser: TcReleaser,
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>, pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool, sched_tc_pool: StaticMemoryPool,
) -> SchedulingServiceWrapper<PacketSenderWithSharedPool, EcssTcInSharedStoreConverter> { ) -> SchedulingServiceWrapper {
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5)) let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed"); .expect("Creating PUS Scheduler failed");
let pus_11_handler = PusSchedServiceHandler::new( let pus_11_handler = PusSchedServiceHandler::new(
@ -176,7 +187,7 @@ pub fn create_scheduler_service_static(
pus_sched_rx, pus_sched_rx,
tm_sender, tm_sender,
create_verification_reporter(PUS_SCHED_SERVICE.id(), PUS_SCHED_SERVICE.apid), create_verification_reporter(PUS_SCHED_SERVICE.id(), PUS_SCHED_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_releaser.shared_packet_store().0.clone(), 2048), tc_in_mem_converter,
), ),
scheduler, scheduler,
); );
@ -184,34 +195,6 @@ pub fn create_scheduler_service_static(
pus_11_handler, pus_11_handler,
sched_tc_pool, sched_tc_pool,
releaser_buf: [0; 4096], releaser_buf: [0; 4096],
tc_releaser: Box::new(tc_releaser), tc_releaser,
}
}
pub fn create_scheduler_service_dynamic(
tm_funnel_tx: mpsc::Sender<PacketAsVec>,
tc_source_sender: mpsc::Sender<PacketAsVec>,
pus_sched_rx: mpsc::Receiver<EcssTcAndToken>,
sched_tc_pool: StaticMemoryPool,
) -> SchedulingServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> {
//let sched_srv_receiver =
//MpscTcReceiver::new(PUS_SCHED_SERVICE.raw(), "PUS_11_TC_RECV", pus_sched_rx);
let scheduler = PusScheduler::new_with_current_init_time(Duration::from_secs(5))
.expect("Creating PUS Scheduler failed");
let pus_11_handler = PusSchedServiceHandler::new(
PusServiceHelper::new(
PUS_SCHED_SERVICE.id(),
pus_sched_rx,
tm_funnel_tx,
create_verification_reporter(PUS_SCHED_SERVICE.id(), PUS_SCHED_SERVICE.apid),
EcssTcInVecConverter::default(),
),
scheduler,
);
SchedulingServiceWrapper {
pus_11_handler,
sched_tc_pool,
releaser_buf: [0; 4096],
tc_releaser: Box::new(tc_source_sender),
} }
} }

View File

@ -1,9 +1,6 @@
use crate::pus::mode::ModeServiceWrapper; use crate::pus::mode::ModeServiceWrapper;
use derive_new::new; use derive_new::new;
use satrs::{ use satrs::spacepackets::time::{cds, TimeWriter};
pus::{EcssTcInMemConverter, EcssTmSender},
spacepackets::time::{cds, TimeWriter},
};
use super::{ use super::{
action::ActionServiceWrapper, event::EventServiceWrapper, hk::HkServiceWrapper, action::ActionServiceWrapper, event::EventServiceWrapper, hk::HkServiceWrapper,
@ -11,21 +8,17 @@ use super::{
HandlingStatus, TargetedPusService, HandlingStatus, TargetedPusService,
}; };
// TODO: For better extensibility, we could create 2 vectors: One for direct PUS services and one
// for targeted services..
#[derive(new)] #[derive(new)]
pub struct PusStack<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> { pub struct PusStack {
test_srv: TestCustomServiceWrapper<TmSender, TcInMemConverter>, pub test_srv: TestCustomServiceWrapper,
hk_srv_wrapper: HkServiceWrapper<TmSender, TcInMemConverter>, pub hk_srv_wrapper: HkServiceWrapper,
event_srv: EventServiceWrapper<TmSender, TcInMemConverter>, pub event_srv: EventServiceWrapper,
action_srv_wrapper: ActionServiceWrapper<TmSender, TcInMemConverter>, pub action_srv_wrapper: ActionServiceWrapper,
schedule_srv: SchedulingServiceWrapper<TmSender, TcInMemConverter>, pub schedule_srv: SchedulingServiceWrapper,
mode_srv: ModeServiceWrapper<TmSender, TcInMemConverter>, pub mode_srv: ModeServiceWrapper,
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> impl PusStack {
PusStack<TmSender, TcInMemConverter>
{
pub fn periodic_operation(&mut self) { pub fn periodic_operation(&mut self) {
// Release all telecommands which reached their release time before calling the service // Release all telecommands which reached their release time before calling the service
// handlers. // handlers.

View File

@ -1,35 +1,34 @@
use crate::pus::create_verification_reporter; use crate::pus::create_verification_reporter;
use crate::tmtc::sender::TmTcSender;
use log::info; use log::info;
use satrs::event_man::{EventMessage, EventMessageU32}; use satrs::event_man::{EventMessage, EventMessageU32};
use satrs::pool::SharedStaticMemoryPool;
use satrs::pus::test::PusService17TestHandler; use satrs::pus::test::PusService17TestHandler;
use satrs::pus::verification::{FailParams, VerificationReporter, VerificationReportingProvider}; use satrs::pus::verification::{FailParams, VerificationReporter, VerificationReportingProvider};
use satrs::pus::PartialPusHandlingError;
use satrs::pus::{ use satrs::pus::{
DirectPusPacketHandlerResult, EcssTcAndToken, EcssTcInMemConverter, EcssTcInVecConverter, DirectPusPacketHandlerResult, EcssTcAndToken, EcssTcInMemConversionProvider,
EcssTmSender, MpscTcReceiver, MpscTmAsVecSender, PusServiceHelper, EcssTcInMemConverter, MpscTcReceiver, PusServiceHelper,
}; };
use satrs::pus::{EcssTcInSharedStoreConverter, PartialPusHandlingError};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::{PusPacket, PusServiceId}; use satrs::spacepackets::ecss::{PusPacket, PusServiceId};
use satrs::tmtc::{PacketAsVec, PacketSenderWithSharedPool};
use satrs_example::config::components::PUS_TEST_SERVICE; use satrs_example::config::components::PUS_TEST_SERVICE;
use satrs_example::config::{tmtc_err, TEST_EVENT}; use satrs_example::config::{tmtc_err, TEST_EVENT};
use std::sync::mpsc; use std::sync::mpsc;
use super::{DirectPusService, HandlingStatus}; use super::{DirectPusService, HandlingStatus};
pub fn create_test_service_static( pub fn create_test_service(
tm_sender: PacketSenderWithSharedPool, tm_sender: TmTcSender,
tc_pool: SharedStaticMemoryPool, tc_in_mem_converter: EcssTcInMemConverter,
event_sender: mpsc::SyncSender<EventMessageU32>, event_sender: mpsc::SyncSender<EventMessageU32>,
pus_test_rx: mpsc::Receiver<EcssTcAndToken>, pus_test_rx: mpsc::Receiver<EcssTcAndToken>,
) -> TestCustomServiceWrapper<PacketSenderWithSharedPool, EcssTcInSharedStoreConverter> { ) -> TestCustomServiceWrapper {
let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new( let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new(
PUS_TEST_SERVICE.id(), PUS_TEST_SERVICE.id(),
pus_test_rx, pus_test_rx,
tm_sender, tm_sender,
create_verification_reporter(PUS_TEST_SERVICE.id(), PUS_TEST_SERVICE.apid), create_verification_reporter(PUS_TEST_SERVICE.id(), PUS_TEST_SERVICE.apid),
EcssTcInSharedStoreConverter::new(tc_pool, 2048), tc_in_mem_converter,
)); ));
TestCustomServiceWrapper { TestCustomServiceWrapper {
handler: pus17_handler, handler: pus17_handler,
@ -37,34 +36,17 @@ pub fn create_test_service_static(
} }
} }
pub fn create_test_service_dynamic( pub struct TestCustomServiceWrapper {
tm_funnel_tx: mpsc::Sender<PacketAsVec>, pub handler: PusService17TestHandler<
event_sender: mpsc::SyncSender<EventMessageU32>, MpscTcReceiver,
pus_test_rx: mpsc::Receiver<EcssTcAndToken>, TmTcSender,
) -> TestCustomServiceWrapper<MpscTmAsVecSender, EcssTcInVecConverter> { EcssTcInMemConverter,
let pus17_handler = PusService17TestHandler::new(PusServiceHelper::new( VerificationReporter,
PUS_TEST_SERVICE.id(), >,
pus_test_rx,
tm_funnel_tx,
create_verification_reporter(PUS_TEST_SERVICE.id(), PUS_TEST_SERVICE.apid),
EcssTcInVecConverter::default(),
));
TestCustomServiceWrapper {
handler: pus17_handler,
event_tx: event_sender,
}
}
pub struct TestCustomServiceWrapper<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter>
{
pub handler:
PusService17TestHandler<MpscTcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub event_tx: mpsc::SyncSender<EventMessageU32>, pub event_tx: mpsc::SyncSender<EventMessageU32>,
} }
impl<TmSender: EcssTmSender, TcInMemConverter: EcssTcInMemConverter> DirectPusService impl DirectPusService for TestCustomServiceWrapper {
for TestCustomServiceWrapper<TmSender, TcInMemConverter>
{
const SERVICE_ID: u8 = PusServiceId::Test as u8; const SERVICE_ID: u8 = PusServiceId::Test as u8;
const SERVICE_STR: &'static str = "test"; const SERVICE_STR: &'static str = "test";

6
satrs-example/src/spi.rs Normal file
View File

@ -0,0 +1,6 @@
use core::fmt::Debug;
pub trait SpiInterface {
type Error: Debug;
fn transfer(&mut self, tx: &[u8], rx: &mut [u8]) -> Result<(), Self::Error>;
}

View File

@ -1,2 +1,3 @@
pub mod sender;
pub mod tc_source; pub mod tc_source;
pub mod tm_sink; pub mod tm_sink;

View File

@ -0,0 +1,75 @@
use std::{cell::RefCell, collections::VecDeque, sync::mpsc};
use satrs::{
pus::EcssTmSender,
queue::GenericSendError,
spacepackets::ecss::WritablePusPacket,
tmtc::{PacketAsVec, PacketSenderRaw, PacketSenderWithSharedPool, StoreAndSendError},
ComponentId,
};
#[derive(Default, Debug, Clone)]
pub struct MockSender(pub RefCell<VecDeque<PacketAsVec>>);
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub enum TmTcSender {
Static(PacketSenderWithSharedPool),
Heap(mpsc::SyncSender<PacketAsVec>),
Mock(MockSender),
}
impl TmTcSender {
#[allow(dead_code)]
pub fn get_mock_sender(&mut self) -> Option<&mut MockSender> {
match self {
TmTcSender::Mock(sender) => Some(sender),
_ => None,
}
}
}
impl EcssTmSender for TmTcSender {
fn send_tm(
&self,
sender_id: satrs::ComponentId,
tm: satrs::pus::PusTmVariant,
) -> Result<(), satrs::pus::EcssTmtcError> {
match self {
TmTcSender::Static(sync_sender) => sync_sender.send_tm(sender_id, tm),
TmTcSender::Heap(sync_sender) => match tm {
satrs::pus::PusTmVariant::InStore(_) => panic!("can not send TM in store"),
satrs::pus::PusTmVariant::Direct(pus_tm_creator) => sync_sender
.send(PacketAsVec::new(sender_id, pus_tm_creator.to_vec()?))
.map_err(|_| GenericSendError::RxDisconnected.into()),
},
TmTcSender::Mock(_) => Ok(()),
}
}
}
impl PacketSenderRaw for TmTcSender {
type Error = StoreAndSendError;
fn send_packet(&self, sender_id: ComponentId, packet: &[u8]) -> Result<(), Self::Error> {
match self {
TmTcSender::Static(packet_sender_with_shared_pool) => {
packet_sender_with_shared_pool.send_packet(sender_id, packet)
}
TmTcSender::Heap(sync_sender) => sync_sender
.send_packet(sender_id, packet)
.map_err(StoreAndSendError::Send),
TmTcSender::Mock(sender) => sender.send_packet(sender_id, packet),
}
}
}
impl PacketSenderRaw for MockSender {
type Error = StoreAndSendError;
fn send_packet(&self, sender_id: ComponentId, tc_raw: &[u8]) -> Result<(), Self::Error> {
let mut mut_queue = self.0.borrow_mut();
mut_queue.push_back(PacketAsVec::new(sender_id, tc_raw.to_vec()));
Ok(())
}
}

View File

@ -1,12 +1,10 @@
use satrs::{ use satrs::{
pool::PoolProvider, pool::PoolProvider,
pus::HandlingStatus, pus::HandlingStatus,
tmtc::{PacketAsVec, PacketInPool, PacketSenderWithSharedPool, SharedPacketPool}, tmtc::{PacketAsVec, PacketInPool, SharedPacketPool},
}; };
use std::sync::mpsc::{self, TryRecvError}; use std::sync::mpsc::{self, TryRecvError};
use satrs::pus::MpscTmAsVecSender;
use crate::pus::PusTcDistributor; use crate::pus::PusTcDistributor;
// TC source components where static pools are the backing memory of the received telecommands. // TC source components where static pools are the backing memory of the received telecommands.
@ -14,14 +12,15 @@ pub struct TcSourceTaskStatic {
shared_tc_pool: SharedPacketPool, shared_tc_pool: SharedPacketPool,
tc_receiver: mpsc::Receiver<PacketInPool>, tc_receiver: mpsc::Receiver<PacketInPool>,
tc_buf: [u8; 4096], tc_buf: [u8; 4096],
pus_distributor: PusTcDistributor<PacketSenderWithSharedPool>, pus_distributor: PusTcDistributor,
} }
#[allow(dead_code)]
impl TcSourceTaskStatic { impl TcSourceTaskStatic {
pub fn new( pub fn new(
shared_tc_pool: SharedPacketPool, shared_tc_pool: SharedPacketPool,
tc_receiver: mpsc::Receiver<PacketInPool>, tc_receiver: mpsc::Receiver<PacketInPool>,
pus_receiver: PusTcDistributor<PacketSenderWithSharedPool>, pus_receiver: PusTcDistributor,
) -> Self { ) -> Self {
Self { Self {
shared_tc_pool, shared_tc_pool,
@ -67,14 +66,12 @@ impl TcSourceTaskStatic {
// TC source components where the heap is the backing memory of the received telecommands. // TC source components where the heap is the backing memory of the received telecommands.
pub struct TcSourceTaskDynamic { pub struct TcSourceTaskDynamic {
pub tc_receiver: mpsc::Receiver<PacketAsVec>, pub tc_receiver: mpsc::Receiver<PacketAsVec>,
pus_distributor: PusTcDistributor<MpscTmAsVecSender>, pus_distributor: PusTcDistributor,
} }
#[allow(dead_code)]
impl TcSourceTaskDynamic { impl TcSourceTaskDynamic {
pub fn new( pub fn new(tc_receiver: mpsc::Receiver<PacketAsVec>, pus_receiver: PusTcDistributor) -> Self {
tc_receiver: mpsc::Receiver<PacketAsVec>,
pus_receiver: PusTcDistributor<MpscTmAsVecSender>,
) -> Self {
Self { Self {
tc_receiver, tc_receiver,
pus_distributor: pus_receiver, pus_distributor: pus_receiver,
@ -105,3 +102,18 @@ impl TcSourceTaskDynamic {
} }
} }
} }
#[allow(dead_code)]
pub enum TcSourceTask {
Static(TcSourceTaskStatic),
Heap(TcSourceTaskDynamic),
}
impl TcSourceTask {
pub fn periodic_operation(&mut self) {
match self {
TcSourceTask::Static(task) => task.periodic_operation(),
TcSourceTask::Heap(task) => task.periodic_operation(),
}
}
}

View File

@ -89,6 +89,7 @@ pub struct TmSinkStatic {
tm_server_tx: mpsc::SyncSender<PacketInPool>, tm_server_tx: mpsc::SyncSender<PacketInPool>,
} }
#[allow(dead_code)]
impl TmSinkStatic { impl TmSinkStatic {
pub fn new( pub fn new(
shared_tm_store: SharedPacketPool, shared_tm_store: SharedPacketPool,
@ -132,14 +133,15 @@ impl TmSinkStatic {
pub struct TmSinkDynamic { pub struct TmSinkDynamic {
common: TmFunnelCommon, common: TmFunnelCommon,
tm_funnel_rx: mpsc::Receiver<PacketAsVec>, tm_funnel_rx: mpsc::Receiver<PacketAsVec>,
tm_server_tx: mpsc::Sender<PacketAsVec>, tm_server_tx: mpsc::SyncSender<PacketAsVec>,
} }
#[allow(dead_code)]
impl TmSinkDynamic { impl TmSinkDynamic {
pub fn new( pub fn new(
sync_tm_tcp_source: SyncTcpTmSource, sync_tm_tcp_source: SyncTcpTmSource,
tm_funnel_rx: mpsc::Receiver<PacketAsVec>, tm_funnel_rx: mpsc::Receiver<PacketAsVec>,
tm_server_tx: mpsc::Sender<PacketAsVec>, tm_server_tx: mpsc::SyncSender<PacketAsVec>,
) -> Self { ) -> Self {
Self { Self {
common: TmFunnelCommon::new(sync_tm_tcp_source), common: TmFunnelCommon::new(sync_tm_tcp_source),
@ -162,3 +164,18 @@ impl TmSinkDynamic {
} }
} }
} }
#[allow(dead_code)]
pub enum TmSink {
Static(TmSinkStatic),
Heap(TmSinkDynamic),
}
impl TmSink {
pub fn operation(&mut self) {
match self {
TmSink::Static(static_sink) => static_sink.operation(),
TmSink::Heap(dynamic_sink) => dynamic_sink.operation(),
}
}
}

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<(), GenericSendError>;
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<(), GenericSendError>;
}
#[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<(), GenericSendError> {
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<(), GenericSendError> {
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<(), GenericSendError> {
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<(), GenericSendError> {
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

@ -11,8 +11,10 @@ pub use alloc_mod::*;
pub use std_mod::*; pub use std_mod::*;
use crate::{ use crate::{
queue::GenericTargetedMessagingError, queue::{GenericReceiveError, GenericSendError},
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].
@ -147,34 +159,33 @@ pub trait ModeRequestSender {
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError>; ) -> Result<(), GenericSendError>;
} }
pub trait ModeRequestReceiver { pub trait ModeRequestReceiver {
fn try_recv_mode_request( fn try_recv_mode_request(
&self, &self,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError>; ) -> Result<Option<GenericMessage<ModeRequest>>, GenericReceiveError>;
} }
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(
&self, &self,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeRequest>>, GenericReceiveError> {
self.try_recv_message() self.try_recv_message()
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, thiserror::Error)]
pub enum ModeError { pub enum ModeError {
Messaging(GenericTargetedMessagingError), #[error("Messaging send error: {0}")]
} Send(#[from] GenericSendError),
#[error("Messaging receive error: {0}")]
impl From<GenericTargetedMessagingError> for ModeError { Receive(#[from] GenericReceiveError),
fn from(value: GenericTargetedMessagingError) -> Self { #[error("busy with other mode request")]
Self::Messaging(value) Busy,
}
} }
pub trait ModeProvider { pub trait ModeProvider {
@ -196,6 +207,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 +234,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()),
@ -243,15 +256,16 @@ pub trait ModeRequestHandler: ModeProvider {
} }
pub trait ModeReplyReceiver { pub trait ModeReplyReceiver {
fn try_recv_mode_reply( fn try_recv_mode_reply(&self)
&self, -> Result<Option<GenericMessage<ModeReply>>, GenericReceiveError>;
) -> 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>>, GenericReceiveError> {
self.try_recv_message() self.try_recv_message()
} }
} }
@ -264,24 +278,28 @@ pub trait ModeReplySender {
&self, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
reply: ModeReply, reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError>; ) -> Result<(), GenericSendError>;
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub mod alloc_mod { pub mod alloc_mod {
use crate::request::{ use crate::{
MessageSender, MessageSenderAndReceiver, MessageSenderMap, RequestAndReplySenderAndReceiver, queue::{GenericReceiveError, GenericSendError},
request::{
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,
target_id: ComponentId, target_id: ComponentId,
request: ModeReply, request: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
self.send_message(requestor_info, target_id, request) self.send_message(requestor_info, target_id, request)
} }
@ -290,8 +308,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()
@ -301,8 +324,8 @@ pub mod alloc_mod {
&self, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
request: ModeReply, request: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
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,37 +333,67 @@ 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,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeReply>>, GenericReceiveError> {
self.message_receiver.try_recv_message() self.message_receiver.try_recv_message()
} }
} }
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,42 +402,56 @@ 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<(), GenericSendError> {
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,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeReply>>, GenericReceiveError> {
self.reply_receiver.try_recv_message() self.reply_receiver.try_recv_message()
} }
} }
/// 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,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeRequest>>, GenericReceiveError> {
self.try_recv_message() self.try_recv_message()
} }
@ -392,7 +459,7 @@ pub mod alloc_mod {
&self, &self,
requestor_info: MessageMetadata, requestor_info: MessageMetadata,
reply: ModeReply, reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
self.send_message( self.send_message(
requestor_info.request_id(), requestor_info.request_id(),
requestor_info.sender_id(), requestor_info.sender_id(),
@ -403,12 +470,18 @@ 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>>, GenericReceiveError> {
self.try_recv_message() self.try_recv_message()
} }
@ -417,23 +490,38 @@ pub mod alloc_mod {
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
reply: ModeRequest, reply: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
self.send_message(request_id, target_id, reply) self.send_message(request_id, target_id, reply)
} }
} }
/// 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,
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
self.send_message(requestor_info, target_id, request) self.send_message(requestor_info, target_id, request)
} }
@ -442,35 +530,28 @@ 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,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeRequest>>, GenericReceiveError> {
self.message_receiver.try_recv_message() self.message_receiver.try_recv_message()
} }
} }
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()
@ -481,8 +562,8 @@ pub mod alloc_mod {
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
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 +572,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()
@ -522,8 +626,8 @@ pub mod alloc_mod {
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
request: ModeRequest, request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
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,17 +636,28 @@ 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,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ModeRequest>>, GenericReceiveError> {
self.request_receiver.try_recv_message() self.request_receiver.try_recv_message()
} }
} }
@ -552,39 +667,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<(), GenericSendError> {
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

@ -822,7 +822,7 @@ mod alloc_mod {
/// if the next fitting subpool is full. This is useful to ensure the pool remains useful /// if the next fitting subpool is full. This is useful to ensure the pool remains useful
/// for all data sizes as long as possible. However, an undesirable side-effect might be /// for all data sizes as long as possible. However, an undesirable side-effect might be
/// the chocking of larger subpools by underdimensioned smaller subpools. /// the chocking of larger subpools by underdimensioned smaller subpools.
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct StaticPoolConfig { pub struct StaticPoolConfig {
cfg: Vec<SubpoolConfig>, cfg: Vec<SubpoolConfig>,
spill_to_higher_subpools: bool, spill_to_higher_subpools: bool,
@ -881,6 +881,7 @@ mod alloc_mod {
/// [address][PoolAddr] type. Adding any data to the pool will yield a store address. /// [address][PoolAddr] type. Adding any data to the pool will yield a store address.
/// Modification and read operations are done using a reference to a store address. Deletion /// Modification and read operations are done using a reference to a store address. Deletion
/// will consume the store address. /// will consume the store address.
#[derive(Debug)]
pub struct StaticMemoryPool { pub struct StaticMemoryPool {
pool_cfg: StaticPoolConfig, pool_cfg: StaticPoolConfig,
pool: Vec<Vec<u8>>, pool: Vec<Vec<u8>>,

View File

@ -66,9 +66,10 @@ impl GenericActionReplyPus {
pub mod alloc_mod { pub mod alloc_mod {
use crate::{ use crate::{
action::ActionRequest, action::ActionRequest,
queue::GenericTargetedMessagingError, queue::{GenericReceiveError, GenericSendError},
request::{ request::{
GenericMessage, MessageReceiver, MessageSender, MessageSenderAndReceiver, RequestId, GenericMessage, MessageReceiverProvider, MessageSenderAndReceiver,
MessageSenderProvider, MessageSenderStoreProvider, RequestId,
}, },
ComponentId, ComponentId,
}; };
@ -76,15 +77,18 @@ 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,
) -> Result<Option<GenericMessage<ActionRequest>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ActionRequest>>, GenericReceiveError> {
self.try_recv_message() self.try_recv_message()
} }
@ -93,22 +97,31 @@ pub mod alloc_mod {
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
reply: ActionReplyPus, reply: ActionReplyPus,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
self.send_message(request_id, target_id, reply) self.send_message(request_id, target_id, reply)
} }
} }
/// 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,
) -> Result<Option<GenericMessage<ActionReplyPus>>, GenericTargetedMessagingError> { ) -> Result<Option<GenericMessage<ActionReplyPus>>, GenericReceiveError> {
self.try_recv_message() self.try_recv_message()
} }
@ -117,7 +130,7 @@ pub mod alloc_mod {
request_id: RequestId, request_id: RequestId,
target_id: ComponentId, target_id: ComponentId,
request: ActionRequest, request: ActionRequest,
) -> Result<(), GenericTargetedMessagingError> { ) -> Result<(), GenericSendError> {
self.send_message(request_id, target_id, request) self.send_message(request_id, target_id, request)
} }
} }
@ -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

@ -9,14 +9,14 @@ use std::sync::mpsc::Sender;
use super::verification::VerificationReportingProvider; use super::verification::VerificationReportingProvider;
use super::{ use super::{
EcssTcInMemConverter, EcssTcReceiver, EcssTmSender, GenericConversionError, EcssTcInMemConversionProvider, EcssTcReceiver, EcssTmSender, GenericConversionError,
GenericRoutingError, HandlingStatus, PusServiceHelper, GenericRoutingError, HandlingStatus, PusServiceHelper,
}; };
pub struct PusEventServiceHandler< pub struct PusEventServiceHandler<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> { > {
pub service_helper: pub service_helper:
@ -27,7 +27,7 @@ pub struct PusEventServiceHandler<
impl< impl<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> PusEventServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter> > PusEventServiceHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
@ -170,7 +170,7 @@ mod tests {
event_man::EventRequestWithToken, event_man::EventRequestWithToken,
tests::PusServiceHandlerWithSharedStoreCommon, tests::PusServiceHandlerWithSharedStoreCommon,
verification::{TcStateAccepted, VerificationToken}, verification::{TcStateAccepted, VerificationToken},
DirectPusPacketHandlerResult, EcssTcInSharedStoreConverter, PusPacketHandlingError, DirectPusPacketHandlerResult, EcssTcInSharedPoolConverter, PusPacketHandlingError,
}, },
}; };
@ -183,7 +183,7 @@ mod tests {
handler: PusEventServiceHandler< handler: PusEventServiceHandler<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
>, >,
} }

View File

@ -947,7 +947,7 @@ pub mod std_mod {
} }
} }
pub trait EcssTcInMemConverter { pub trait EcssTcInMemConversionProvider {
fn cache(&mut self, possible_packet: &TcInMemory) -> Result<(), PusTcFromMemError>; fn cache(&mut self, possible_packet: &TcInMemory) -> Result<(), PusTcFromMemError>;
fn tc_slice_raw(&self) -> &[u8]; fn tc_slice_raw(&self) -> &[u8];
@ -980,7 +980,7 @@ pub mod std_mod {
pub pus_tc_raw: Option<Vec<u8>>, pub pus_tc_raw: Option<Vec<u8>>,
} }
impl EcssTcInMemConverter for EcssTcInVecConverter { impl EcssTcInMemConversionProvider for EcssTcInVecConverter {
fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> { fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> {
self.pus_tc_raw = None; self.pus_tc_raw = None;
match tc_in_memory { match tc_in_memory {
@ -1011,24 +1011,25 @@ pub mod std_mod {
/// [SharedStaticMemoryPool] structure. This is useful if run-time allocation for these /// [SharedStaticMemoryPool] structure. This is useful if run-time allocation for these
/// packets should be avoided. Please note that this structure is not able to convert TCs which /// packets should be avoided. Please note that this structure is not able to convert TCs which
/// are stored as a `Vec<u8>`. /// are stored as a `Vec<u8>`.
pub struct EcssTcInSharedStoreConverter { #[derive(Clone)]
pub struct EcssTcInSharedPoolConverter {
sender_id: Option<ComponentId>, sender_id: Option<ComponentId>,
shared_tc_store: SharedStaticMemoryPool, shared_tc_pool: SharedStaticMemoryPool,
pus_buf: Vec<u8>, pus_buf: Vec<u8>,
} }
impl EcssTcInSharedStoreConverter { impl EcssTcInSharedPoolConverter {
pub fn new(shared_tc_store: SharedStaticMemoryPool, max_expected_tc_size: usize) -> Self { pub fn new(shared_tc_store: SharedStaticMemoryPool, max_expected_tc_size: usize) -> Self {
Self { Self {
sender_id: None, sender_id: None,
shared_tc_store, shared_tc_pool: shared_tc_store,
pus_buf: alloc::vec![0; max_expected_tc_size], pus_buf: alloc::vec![0; max_expected_tc_size],
} }
} }
pub fn copy_tc_to_buf(&mut self, addr: PoolAddr) -> Result<(), PusTcFromMemError> { pub fn copy_tc_to_buf(&mut self, addr: PoolAddr) -> Result<(), PusTcFromMemError> {
// Keep locked section as short as possible. // Keep locked section as short as possible.
let mut tc_pool = self.shared_tc_store.write().map_err(|_| { let mut tc_pool = self.shared_tc_pool.write().map_err(|_| {
PusTcFromMemError::EcssTmtc(EcssTmtcError::Store(PoolError::LockError)) PusTcFromMemError::EcssTmtc(EcssTmtcError::Store(PoolError::LockError))
})?; })?;
let tc_size = tc_pool.len_of_data(&addr).map_err(EcssTmtcError::Store)?; let tc_size = tc_pool.len_of_data(&addr).map_err(EcssTmtcError::Store)?;
@ -1048,7 +1049,7 @@ pub mod std_mod {
} }
} }
impl EcssTcInMemConverter for EcssTcInSharedStoreConverter { impl EcssTcInMemConversionProvider for EcssTcInSharedPoolConverter {
fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> { fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> {
match tc_in_memory { match tc_in_memory {
super::TcInMemory::Pool(packet_in_pool) => { super::TcInMemory::Pool(packet_in_pool) => {
@ -1071,6 +1072,44 @@ pub mod std_mod {
} }
} }
// TODO: alloc feature flag?
#[derive(Clone)]
pub enum EcssTcInMemConverter {
Static(EcssTcInSharedPoolConverter),
Heap(EcssTcInVecConverter),
}
impl EcssTcInMemConverter {
pub fn new_static(static_store_converter: EcssTcInSharedPoolConverter) -> Self {
EcssTcInMemConverter::Static(static_store_converter)
}
pub fn new_heap(heap_converter: EcssTcInVecConverter) -> Self {
EcssTcInMemConverter::Heap(heap_converter)
}
}
impl EcssTcInMemConversionProvider for EcssTcInMemConverter {
fn cache(&mut self, tc_in_memory: &TcInMemory) -> Result<(), PusTcFromMemError> {
match self {
EcssTcInMemConverter::Static(converter) => converter.cache(tc_in_memory),
EcssTcInMemConverter::Heap(converter) => converter.cache(tc_in_memory),
}
}
fn tc_slice_raw(&self) -> &[u8] {
match self {
EcssTcInMemConverter::Static(converter) => converter.tc_slice_raw(),
EcssTcInMemConverter::Heap(converter) => converter.tc_slice_raw(),
}
}
fn sender_id(&self) -> Option<ComponentId> {
match self {
EcssTcInMemConverter::Static(converter) => converter.sender_id(),
EcssTcInMemConverter::Heap(converter) => converter.sender_id(),
}
}
}
pub struct PusServiceBase< pub struct PusServiceBase<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
@ -1094,7 +1133,7 @@ pub mod std_mod {
pub struct PusServiceHelper< pub struct PusServiceHelper<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> { > {
pub common: PusServiceBase<TcReceiver, TmSender, VerificationReporter>, pub common: PusServiceBase<TcReceiver, TmSender, VerificationReporter>,
@ -1104,7 +1143,7 @@ pub mod std_mod {
impl< impl<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter> > PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
@ -1221,9 +1260,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 +1272,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 +1309,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,
@ -1346,7 +1386,7 @@ pub mod tests {
pub type PusServiceHelperStatic = PusServiceHelper< pub type PusServiceHelperStatic = PusServiceHelper<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
>; >;
@ -1373,8 +1413,7 @@ pub mod tests {
VerificationReporter::new(TEST_COMPONENT_ID_0.id(), &verif_cfg); VerificationReporter::new(TEST_COMPONENT_ID_0.id(), &verif_cfg);
let test_srv_tm_sender = let test_srv_tm_sender =
PacketSenderWithSharedPool::new(tm_tx, shared_tm_pool_wrapper.clone()); PacketSenderWithSharedPool::new(tm_tx, shared_tm_pool_wrapper.clone());
let in_store_converter = let in_store_converter = EcssTcInSharedPoolConverter::new(shared_tc_pool.clone(), 2048);
EcssTcInSharedStoreConverter::new(shared_tc_pool.clone(), 2048);
( (
Self { Self {
pus_buf: RefCell::new([0; 2048]), pus_buf: RefCell::new([0; 2048]),

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,7 +1,7 @@
use super::scheduler::PusSchedulerProvider; use super::scheduler::PusSchedulerProvider;
use super::verification::{VerificationReporter, VerificationReportingProvider}; use super::verification::{VerificationReporter, VerificationReportingProvider};
use super::{ use super::{
DirectPusPacketHandlerResult, EcssTcInMemConverter, EcssTcInSharedStoreConverter, DirectPusPacketHandlerResult, EcssTcInMemConversionProvider, EcssTcInSharedPoolConverter,
EcssTcInVecConverter, EcssTcReceiver, EcssTmSender, HandlingStatus, MpscTcReceiver, EcssTcInVecConverter, EcssTcReceiver, EcssTmSender, HandlingStatus, MpscTcReceiver,
PartialPusHandlingError, PusServiceHelper, PartialPusHandlingError, PusServiceHelper,
}; };
@ -24,7 +24,7 @@ use std::sync::mpsc;
pub struct PusSchedServiceHandler< pub struct PusSchedServiceHandler<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
PusScheduler: PusSchedulerProvider, PusScheduler: PusSchedulerProvider,
> { > {
@ -36,7 +36,7 @@ pub struct PusSchedServiceHandler<
impl< impl<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
Scheduler: PusSchedulerProvider, Scheduler: PusSchedulerProvider,
> >
@ -229,7 +229,7 @@ pub type PusService11SchedHandlerDynWithBoundedMpsc<PusScheduler> = PusSchedServ
pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusSchedServiceHandler< pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
PusScheduler, PusScheduler,
>; >;
@ -238,7 +238,7 @@ pub type PusService11SchedHandlerStaticWithMpsc<PusScheduler> = PusSchedServiceH
pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusSchedServiceHandler< pub type PusService11SchedHandlerStaticWithBoundedMpsc<PusScheduler> = PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
PusScheduler, PusScheduler,
>; >;
@ -253,7 +253,7 @@ mod tests {
scheduler::{self, PusSchedulerProvider, TcInfo}, scheduler::{self, PusSchedulerProvider, TcInfo},
tests::PusServiceHandlerWithSharedStoreCommon, tests::PusServiceHandlerWithSharedStoreCommon,
verification::{RequestId, TcStateAccepted, VerificationToken}, verification::{RequestId, TcStateAccepted, VerificationToken},
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
}; };
use crate::pus::{DirectPusPacketHandlerResult, MpscTcReceiver, PusPacketHandlingError}; use crate::pus::{DirectPusPacketHandlerResult, MpscTcReceiver, PusPacketHandlingError};
use crate::tmtc::PacketSenderWithSharedPool; use crate::tmtc::PacketSenderWithSharedPool;
@ -276,7 +276,7 @@ mod tests {
handler: PusSchedServiceHandler< handler: PusSchedServiceHandler<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
TestScheduler, TestScheduler,
>, >,

View File

@ -9,8 +9,9 @@ use std::sync::mpsc;
use super::verification::{VerificationReporter, VerificationReportingProvider}; use super::verification::{VerificationReporter, VerificationReportingProvider};
use super::{ use super::{
EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiver, EcssTcInMemConversionProvider, EcssTcInSharedPoolConverter, EcssTcInVecConverter,
EcssTmSender, GenericConversionError, HandlingStatus, MpscTcReceiver, PusServiceHelper, EcssTcReceiver, EcssTmSender, GenericConversionError, HandlingStatus, MpscTcReceiver,
PusServiceHelper,
}; };
/// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets. /// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets.
@ -18,7 +19,7 @@ use super::{
pub struct PusService17TestHandler< pub struct PusService17TestHandler<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> { > {
pub service_helper: pub service_helper:
@ -28,7 +29,7 @@ pub struct PusService17TestHandler<
impl< impl<
TcReceiver: EcssTcReceiver, TcReceiver: EcssTcReceiver,
TmSender: EcssTmSender, TmSender: EcssTmSender,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConversionProvider,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> PusService17TestHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter> > PusService17TestHandler<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
@ -127,7 +128,7 @@ pub type PusService17TestHandlerDynWithBoundedMpsc = PusService17TestHandler<
pub type PusService17TestHandlerStaticWithBoundedMpsc = PusService17TestHandler< pub type PusService17TestHandlerStaticWithBoundedMpsc = PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
>; >;
@ -142,7 +143,7 @@ mod tests {
}; };
use crate::pus::verification::{TcStateAccepted, VerificationToken}; use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{ use crate::pus::{
DirectPusPacketHandlerResult, EcssTcInSharedStoreConverter, EcssTcInVecConverter, DirectPusPacketHandlerResult, EcssTcInSharedPoolConverter, EcssTcInVecConverter,
GenericConversionError, HandlingStatus, MpscTcReceiver, MpscTmAsVecSender, GenericConversionError, HandlingStatus, MpscTcReceiver, MpscTmAsVecSender,
PartialPusHandlingError, PusPacketHandlingError, PartialPusHandlingError, PusPacketHandlingError,
}; };
@ -162,7 +163,7 @@ mod tests {
handler: PusService17TestHandler< handler: PusService17TestHandler<
MpscTcReceiver, MpscTcReceiver,
PacketSenderWithSharedPool, PacketSenderWithSharedPool,
EcssTcInSharedStoreConverter, EcssTcInSharedPoolConverter,
VerificationReporter, VerificationReporter,
>, >,
} }

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

@ -13,7 +13,10 @@ use spacepackets::{
ByteConversionError, ByteConversionError,
}; };
use crate::{queue::GenericTargetedMessagingError, ComponentId}; use crate::{
queue::{GenericReceiveError, GenericSendError},
ComponentId,
};
/// Generic request ID type. Requests can be associated with an ID to have a unique identifier /// Generic request ID type. Requests can be associated with an ID to have a unique identifier
/// for them. This can be useful for tasks like tracking their progress. /// for them. This can be useful for tasks like tracking their progress.
@ -140,37 +143,38 @@ 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<(), GenericSendError>;
} }
// 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>>, GenericReceiveError>;
} }
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) -> Result<Option<GenericMessage<MSG>>, GenericReceiveError> {
&self,
) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
self.0.try_recv() self.0.try_recv()
} }
} }
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,43 +187,129 @@ 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) -> Result<Option<GenericMessage<MSG>>, GenericReceiveError> {
&self,
) -> Result<Option<GenericMessage<MSG>>, GenericTargetedMessagingError> {
self.reply_receiver.0.try_recv() self.reply_receiver.0.try_recv()
} }
} }
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<(), GenericSendError>;
}
#[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<(), GenericSendError> {
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))
}
}
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> { ) -> Result<(), GenericSendError> {
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))
}
}
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<(), GenericSendError> {
if self.0.contains_key(&target_channel_id) { if self.0.contains_key(&target_channel_id) {
return self return self
.0 .0
@ -227,29 +317,42 @@ pub mod alloc_mod {
.unwrap() .unwrap()
.send(GenericMessage::new(requestor_info, message)); .send(GenericMessage::new(requestor_info, message));
} }
Err(GenericSendError::TargetDoesNotExist(target_channel_id).into()) Err(GenericSendError::TargetDoesNotExist(target_channel_id))
} }
} }
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 +365,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<(), GenericSendError> {
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 +377,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>>, GenericReceiveError> {
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,21 +452,19 @@ 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<(), GenericSendError> {
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<(), GenericSendError> {
if let Err(e) = self.try_send(message) { if let Err(e) = self.try_send(message) {
return match e { return match e {
mpsc::TrySendError::Full(_) => Err(GenericSendError::QueueFull(None).into()), mpsc::TrySendError::Full(_) => Err(GenericSendError::QueueFull(None)),
mpsc::TrySendError::Disconnected(_) => { mpsc::TrySendError::Disconnected(_) => Err(GenericSendError::RxDisconnected),
Err(GenericSendError::RxDisconnected.into())
}
}; };
} }
Ok(()) Ok(())
@ -357,14 +474,14 @@ 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>>, GenericReceiveError> {
match self.try_recv() { match self.try_recv() {
Ok(msg) => Ok(Some(msg)), Ok(msg) => Ok(Some(msg)),
Err(e) => match e { Err(e) => match e {
mpsc::TryRecvError::Empty => Ok(None), mpsc::TryRecvError::Empty => Ok(None),
mpsc::TryRecvError::Disconnected => { mpsc::TryRecvError::Disconnected => {
Err(GenericReceiveError::TxDisconnected(None).into()) Err(GenericReceiveError::TxDisconnected(None))
} }
}, },
} }
@ -385,8 +502,8 @@ mod tests {
}; };
use crate::{ use crate::{
queue::{GenericReceiveError, GenericSendError, GenericTargetedMessagingError}, queue::{GenericReceiveError, GenericSendError},
request::{MessageMetadata, MessageSenderMap}, request::{MessageMetadata, MessageSenderMap, MessageSenderStoreProvider},
}; };
use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId}; use super::{GenericMessage, MessageReceiverWithId, UniqueApidTargetId};
@ -478,9 +595,7 @@ mod tests {
let reply = receiver.try_recv_message(); let reply = receiver.try_recv_message();
assert!(reply.is_err()); assert!(reply.is_err());
let error = reply.unwrap_err(); let error = reply.unwrap_err();
if let GenericTargetedMessagingError::Receive(GenericReceiveError::TxDisconnected(None)) = if let GenericReceiveError::TxDisconnected(None) = error {
error
{
} else { } else {
panic!("unexpected error type"); panic!("unexpected error type");
} }
@ -529,9 +644,7 @@ mod tests {
); );
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::TargetDoesNotExist(target)) = if let GenericSendError::TargetDoesNotExist(target) = error {
error
{
assert_eq!(target, TEST_CHANNEL_ID_2); assert_eq!(target, TEST_CHANNEL_ID_2);
} else { } else {
panic!("Unexpected error type"); panic!("Unexpected error type");
@ -556,7 +669,7 @@ mod tests {
); );
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::QueueFull(capacity)) = error { if let GenericSendError::QueueFull(capacity) = error {
assert!(capacity.is_none()); assert!(capacity.is_none());
} else { } else {
panic!("Unexpected error type {}", error); panic!("Unexpected error type {}", error);
@ -576,7 +689,7 @@ mod tests {
); );
assert!(result.is_err()); assert!(result.is_err());
let error = result.unwrap_err(); let error = result.unwrap_err();
if let GenericTargetedMessagingError::Send(GenericSendError::RxDisconnected) = error { if let GenericSendError::RxDisconnected = error {
} else { } else {
panic!("Unexpected error type {}", error); panic!("Unexpected error type {}", error);
} }

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

View File

@ -14,6 +14,7 @@ use crate::{
}; };
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use alloc_mod::*; pub use alloc_mod::*;
use core::fmt::Debug;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use downcast_rs::{impl_downcast, Downcast}; use downcast_rs::{impl_downcast, Downcast};
use spacepackets::{ use spacepackets::{
@ -170,7 +171,7 @@ where
} }
/// Helper trait for any generic (static) store which allows storing raw or CCSDS packets. /// Helper trait for any generic (static) store which allows storing raw or CCSDS packets.
pub trait CcsdsPacketPool { pub trait CcsdsPacketPool: Debug {
fn add_ccsds_tc(&mut self, _: &SpHeader, tc_raw: &[u8]) -> Result<PoolAddr, PoolError> { fn add_ccsds_tc(&mut self, _: &SpHeader, tc_raw: &[u8]) -> Result<PoolAddr, PoolError> {
self.add_raw_tc(tc_raw) self.add_raw_tc(tc_raw)
} }
@ -190,7 +191,7 @@ pub trait PusTmPool {
} }
/// Generic trait for any sender component able to send packets stored inside a pool structure. /// Generic trait for any sender component able to send packets stored inside a pool structure.
pub trait PacketInPoolSender: Send { pub trait PacketInPoolSender: Debug + Send {
fn send_packet( fn send_packet(
&self, &self,
sender_id: ComponentId, sender_id: ComponentId,
@ -235,7 +236,7 @@ pub mod std_mod {
/// Newtype wrapper around the [SharedStaticMemoryPool] to enable extension helper traits on /// Newtype wrapper around the [SharedStaticMemoryPool] to enable extension helper traits on
/// top of the regular shared memory pool API. /// top of the regular shared memory pool API.
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct SharedPacketPool(pub SharedStaticMemoryPool); pub struct SharedPacketPool(pub SharedStaticMemoryPool);
impl SharedPacketPool { impl SharedPacketPool {
@ -287,7 +288,6 @@ pub mod std_mod {
} }
} }
#[cfg(feature = "std")]
impl PacketSenderRaw for mpsc::Sender<PacketAsVec> { impl PacketSenderRaw for mpsc::Sender<PacketAsVec> {
type Error = GenericSendError; type Error = GenericSendError;
@ -297,7 +297,6 @@ pub mod std_mod {
} }
} }
#[cfg(feature = "std")]
impl PacketSenderRaw for mpsc::SyncSender<PacketAsVec> { impl PacketSenderRaw for mpsc::SyncSender<PacketAsVec> {
type Error = GenericSendError; type Error = GenericSendError;
@ -362,7 +361,7 @@ pub mod std_mod {
/// This is the primary structure used to send packets stored in a dedicated memory pool /// This is the primary structure used to send packets stored in a dedicated memory pool
/// structure. /// structure.
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct PacketSenderWithSharedPool< pub struct PacketSenderWithSharedPool<
Sender: PacketInPoolSender = mpsc::SyncSender<PacketInPool>, Sender: PacketInPoolSender = mpsc::SyncSender<PacketInPool>,
PacketPool: CcsdsPacketPool = SharedPacketPool, PacketPool: CcsdsPacketPool = SharedPacketPool,

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()),
)) ))