Mode Sequences and Tables #211
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@ -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
3
docs.sh
Executable file
@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options"
|
||||||
|
cargo +nightly doc --all-features --open
|
@ -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"
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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,25 +264,28 @@ 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) => {
|
||||||
let result = self.handle_mode_request(msg);
|
if let Some(msg) = opt_msg {
|
||||||
// TODO: Trigger event?
|
let result = self.handle_mode_request(msg);
|
||||||
if result.is_err() {
|
// TODO: Trigger event?
|
||||||
log::warn!(
|
if result.is_err() {
|
||||||
"{}: mode request failed with error {:?}",
|
log::warn!(
|
||||||
self.dev_str,
|
"{}: mode request failed with error {:?}",
|
||||||
result.err().unwrap()
|
self.dev_str,
|
||||||
);
|
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();
|
||||||
|
@ -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 =
|
||||||
|
@ -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,25 +327,30 @@ 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) => {
|
||||||
let result = self.handle_mode_request(msg);
|
if let Some(msg) = opt_msg {
|
||||||
// TODO: Trigger event?
|
let result = self.handle_mode_request(msg);
|
||||||
if result.is_err() {
|
// TODO: Trigger event?
|
||||||
log::warn!(
|
if result.is_err() {
|
||||||
"{}: mode request failed with error {:?}",
|
log::warn!(
|
||||||
self.dev_str,
|
"{}: mode request failed with error {:?}",
|
||||||
result.err().unwrap()
|
self.dev_str,
|
||||||
);
|
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
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
let (tm_pool, tc_pool) = create_static_pools();
|
||||||
};
|
let shared_tm_pool = Arc::new(RwLock::new(tm_pool));
|
||||||
use crate::interface::sim_client_udp::create_sim_client;
|
let shared_tc_pool = Arc::new(RwLock::new(tc_pool));
|
||||||
use crate::interface::tcp::{SyncTcpTmSource, TcpTask};
|
let shared_tm_pool_wrapper = SharedPacketPool::new(&shared_tm_pool);
|
||||||
use crate::interface::udp::{StaticUdpTmHandler, UdpTmtcServer};
|
let shared_tc_pool_wrapper = SharedPacketPool::new(&shared_tc_pool);
|
||||||
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 shared_tm_pool = Arc::new(RwLock::new(tm_pool));
|
|
||||||
let shared_tc_pool = Arc::new(RwLock::new(tc_pool));
|
|
||||||
let shared_tm_pool_wrapper = SharedPacketPool::new(&shared_tm_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! {
|
||||||
shared_tc_pool_wrapper.clone(),
|
if #[cfg(not(feature = "heap_tmtc"))] {
|
||||||
tc_source_rx,
|
let mut tmtc_task = TcSourceTask::Static(TcSourceTaskStatic::new(
|
||||||
PusTcDistributor::new(tm_sink_tx_sender, pus_router),
|
shared_tc_pool_wrapper.clone(),
|
||||||
);
|
tc_source_rx,
|
||||||
|
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! {
|
||||||
shared_tm_pool_wrapper,
|
if #[cfg(not(feature = "heap_tmtc"))] {
|
||||||
sync_tm_tcp_source,
|
let mut tm_sink = TmSink::Static(TmSinkStatic::new(
|
||||||
tm_sink_rx,
|
shared_tm_pool_wrapper,
|
||||||
tm_server_tx,
|
sync_tm_tcp_source,
|
||||||
);
|
tm_sink_rx,
|
||||||
|
tm_server_tx,
|
||||||
let (mgm_handler_mode_reply_to_parent_tx, _mgm_handler_mode_reply_to_parent_rx) =
|
));
|
||||||
mpsc::sync_channel(5);
|
} else if #[cfg(feature = "heap_tmtc")] {
|
||||||
|
let mut tm_sink = TmSink::Heap(TmSinkDynamic::new(
|
||||||
|
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()
|
||||||
|
@ -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,9 @@ 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,
|
|
||||||
TcInMemConverter,
|
|
||||||
VerificationReporter,
|
VerificationReporter,
|
||||||
ActionRequestConverter,
|
ActionRequestConverter,
|
||||||
ActionReplyHandler,
|
ActionReplyHandler,
|
||||||
@ -275,9 +246,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 +272,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,
|
||||||
@ -338,7 +308,7 @@ mod tests {
|
|||||||
{
|
{
|
||||||
pub fn new_for_action(owner_id: ComponentId, target_id: ComponentId) -> Self {
|
pub fn new_for_action(owner_id: ComponentId, target_id: ComponentId) -> Self {
|
||||||
let _ = env_logger::builder().is_test(true).try_init();
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
let (tm_funnel_tx, tm_funnel_rx) = mpsc::channel();
|
let (tm_funnel_tx, tm_funnel_rx) = mpsc::sync_channel(5);
|
||||||
let (pus_action_tx, pus_action_rx) = mpsc::channel();
|
let (pus_action_tx, pus_action_rx) = mpsc::channel();
|
||||||
let (action_reply_tx, action_reply_rx) = mpsc::channel();
|
let (action_reply_tx, action_reply_rx) = mpsc::channel();
|
||||||
let (action_req_tx, action_req_rx) = mpsc::sync_channel(10);
|
let (action_req_tx, action_req_rx) = mpsc::sync_channel(10);
|
||||||
@ -352,9 +322,9 @@ mod tests {
|
|||||||
PusServiceHelper::new(
|
PusServiceHelper::new(
|
||||||
owner_id,
|
owner_id,
|
||||||
pus_action_rx,
|
pus_action_rx,
|
||||||
tm_funnel_tx.clone(),
|
TmTcSender::Heap(tm_funnel_tx.clone()),
|
||||||
verif_reporter,
|
verif_reporter,
|
||||||
EcssTcInVecConverter::default(),
|
EcssTcInMemConverter::Heap(EcssTcInVecConverter::default()),
|
||||||
),
|
),
|
||||||
ActionRequestConverter::default(),
|
ActionRequestConverter::default(),
|
||||||
DefaultActiveActionRequestMap::default(),
|
DefaultActiveActionRequestMap::default(),
|
||||||
|
@ -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";
|
||||||
|
@ -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,9 @@ 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,
|
|
||||||
TcInMemConverter,
|
|
||||||
VerificationReporter,
|
VerificationReporter,
|
||||||
HkRequestConverter,
|
HkRequestConverter,
|
||||||
HkReplyHandler,
|
HkReplyHandler,
|
||||||
@ -308,9 +279,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";
|
||||||
|
|
||||||
|
@ -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,10 +7,10 @@ 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,
|
EcssTcInMemConverter, EcssTcReceiver, EcssTmSender, EcssTmtcError, GenericConversionError,
|
||||||
HandlingStatus, PusPacketHandlingError, PusReplyHandler, PusRequestRouter, PusServiceHelper,
|
GenericRoutingError, HandlingStatus, PusPacketHandlingError, PusReplyHandler, PusRequestRouter,
|
||||||
PusTcToRequestConverter, TcInMemory,
|
PusServiceHelper, PusTcToRequestConverter, TcInMemory,
|
||||||
};
|
};
|
||||||
use satrs::queue::{GenericReceiveError, GenericSendError};
|
use satrs::queue::{GenericReceiveError, GenericSendError};
|
||||||
use satrs::request::{Apid, GenericMessage, MessageMetadata};
|
use satrs::request::{Apid, GenericMessage, MessageMetadata};
|
||||||
@ -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,
|
||||||
@ -268,8 +269,6 @@ pub trait DirectPusService {
|
|||||||
/// 3. [Self::check_for_request_timeouts] which checks for request timeouts, covering step 7.
|
/// 3. [Self::check_for_request_timeouts] which checks for request timeouts, covering step 7.
|
||||||
pub struct PusTargetedRequestService<
|
pub struct PusTargetedRequestService<
|
||||||
TcReceiver: EcssTcReceiver,
|
TcReceiver: EcssTcReceiver,
|
||||||
TmSender: EcssTmSender,
|
|
||||||
TcInMemConverter: EcssTcInMemConverter,
|
|
||||||
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>,
|
||||||
@ -279,7 +278,7 @@ pub struct PusTargetedRequestService<
|
|||||||
ReplyType,
|
ReplyType,
|
||||||
> {
|
> {
|
||||||
pub service_helper:
|
pub service_helper:
|
||||||
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
|
PusServiceHelper<TcReceiver, TmTcSender, EcssTcInMemConverter, VerificationReporter>,
|
||||||
pub request_router: GenericRequestRouter,
|
pub request_router: GenericRequestRouter,
|
||||||
pub request_converter: RequestConverter,
|
pub request_converter: RequestConverter,
|
||||||
pub active_request_map: ActiveRequestMap,
|
pub active_request_map: ActiveRequestMap,
|
||||||
@ -290,8 +289,6 @@ pub struct PusTargetedRequestService<
|
|||||||
|
|
||||||
impl<
|
impl<
|
||||||
TcReceiver: EcssTcReceiver,
|
TcReceiver: EcssTcReceiver,
|
||||||
TmSender: EcssTmSender,
|
|
||||||
TcInMemConverter: EcssTcInMemConverter,
|
|
||||||
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>,
|
||||||
@ -302,8 +299,6 @@ impl<
|
|||||||
>
|
>
|
||||||
PusTargetedRequestService<
|
PusTargetedRequestService<
|
||||||
TcReceiver,
|
TcReceiver,
|
||||||
TmSender,
|
|
||||||
TcInMemConverter,
|
|
||||||
VerificationReporter,
|
VerificationReporter,
|
||||||
RequestConverter,
|
RequestConverter,
|
||||||
ReplyHandler,
|
ReplyHandler,
|
||||||
@ -318,8 +313,8 @@ where
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
service_helper: PusServiceHelper<
|
service_helper: PusServiceHelper<
|
||||||
TcReceiver,
|
TcReceiver,
|
||||||
TmSender,
|
TmTcSender,
|
||||||
TcInMemConverter,
|
EcssTcInMemConverter,
|
||||||
VerificationReporter,
|
VerificationReporter,
|
||||||
>,
|
>,
|
||||||
request_converter: RequestConverter,
|
request_converter: RequestConverter,
|
||||||
@ -545,7 +540,7 @@ pub(crate) mod tests {
|
|||||||
use satrs::{
|
use satrs::{
|
||||||
pus::{
|
pus::{
|
||||||
verification::test_util::TestVerificationReporter, ActivePusRequestStd,
|
verification::test_util::TestVerificationReporter, ActivePusRequestStd,
|
||||||
ActiveRequestMapProvider, EcssTcInVecConverter, MpscTcReceiver,
|
ActiveRequestMapProvider, MpscTcReceiver,
|
||||||
},
|
},
|
||||||
request::UniqueApidTargetId,
|
request::UniqueApidTargetId,
|
||||||
spacepackets::{
|
spacepackets::{
|
||||||
@ -766,8 +761,6 @@ pub(crate) mod tests {
|
|||||||
> {
|
> {
|
||||||
pub service: PusTargetedRequestService<
|
pub service: PusTargetedRequestService<
|
||||||
MpscTcReceiver,
|
MpscTcReceiver,
|
||||||
MpscTmAsVecSender,
|
|
||||||
EcssTcInVecConverter,
|
|
||||||
TestVerificationReporter,
|
TestVerificationReporter,
|
||||||
RequestConverter,
|
RequestConverter,
|
||||||
ReplyHandler,
|
ReplyHandler,
|
||||||
|
@ -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,9 @@ 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,
|
|
||||||
TcInMemConverter,
|
|
||||||
VerificationReporter,
|
VerificationReporter,
|
||||||
ModeRequestConverter,
|
ModeRequestConverter,
|
||||||
ModeReplyHandler,
|
ModeReplyHandler,
|
||||||
@ -268,9 +247,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 +340,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]
|
||||||
|
@ -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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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
6
satrs-example/src/spi.rs
Normal 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>;
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
|
pub mod sender;
|
||||||
pub mod tc_source;
|
pub mod tc_source;
|
||||||
pub mod tm_sink;
|
pub mod tm_sink;
|
||||||
|
75
satrs-example/src/tmtc/sender.rs
Normal file
75
satrs-example/src/tmtc/sender.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
448
satrs/src/dev_mgmt.rs
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
use crate::{
|
||||||
|
mode::{ModeAndSubmode, ModeReply, ModeRequest, ModeRequestSender},
|
||||||
|
mode_tree::{ModeStoreProvider, ModeStoreVec},
|
||||||
|
queue::{GenericSendError, GenericTargetedMessagingError},
|
||||||
|
request::{GenericMessage, RequestId},
|
||||||
|
ComponentId,
|
||||||
|
};
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct ActiveModeCommandContext {
|
||||||
|
pub target_mode: ModeAndSubmode,
|
||||||
|
pub active_request_id: RequestId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
pub enum DevManagerHelperResult {
|
||||||
|
#[default]
|
||||||
|
Idle,
|
||||||
|
Busy,
|
||||||
|
ModeCommandingDone(ActiveModeCommandContext),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DevManagerHelperError {
|
||||||
|
ChildNotInStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DevManagerUserHook: Debug {
|
||||||
|
fn send_mode_cmd_to_child(
|
||||||
|
&self,
|
||||||
|
request_id: RequestId,
|
||||||
|
target_id: ComponentId,
|
||||||
|
mode: ModeAndSubmode,
|
||||||
|
forced: bool,
|
||||||
|
children_mode_store: &mut ModeStoreVec,
|
||||||
|
mode_req_sender: &impl ModeRequestSender,
|
||||||
|
) -> Result<(), 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
39
satrs/src/health.rs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
use crate::ComponentId;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum HealthState {
|
||||||
|
Healthy = 1,
|
||||||
|
Faulty = 2,
|
||||||
|
PermanentFaulty = 3,
|
||||||
|
ExternalControl = 4,
|
||||||
|
NeedsRecovery = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HealthTableProvider {
|
||||||
|
fn health(&self, id: ComponentId) -> Option<HealthState>;
|
||||||
|
fn set_health(&mut self, id: ComponentId, health: HealthState);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct HealthTableMapSync(
|
||||||
|
std::sync::Arc<std::sync::Mutex<hashbrown::HashMap<ComponentId, HealthState>>>,
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl HealthTableMapSync {
|
||||||
|
pub fn new(health_table: hashbrown::HashMap<ComponentId, HealthState>) -> Self {
|
||||||
|
Self(std::sync::Arc::new(std::sync::Mutex::new(health_table)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl HealthTableProvider for HealthTableMapSync {
|
||||||
|
fn health(&self, id: ComponentId) -> Option<HealthState> {
|
||||||
|
self.0.lock().unwrap().get(&id).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_health(&mut self, id: ComponentId, health: HealthState) {
|
||||||
|
self.0.lock().unwrap().insert(id, health);
|
||||||
|
}
|
||||||
|
}
|
@ -22,14 +22,21 @@ extern crate downcast_rs;
|
|||||||
#[cfg(any(feature = "std", test))]
|
#[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;
|
||||||
|
@ -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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -775,7 +775,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,
|
||||||
@ -834,6 +834,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>>,
|
||||||
|
@ -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>>,
|
||||||
|
>,
|
||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
|
@ -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]),
|
||||||
|
@ -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.
|
||||||
|
@ -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,
|
||||||
>,
|
>,
|
||||||
|
@ -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,
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
|
@ -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")]
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
1610
satrs/src/subsystem.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
@ -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()),
|
||||||
))
|
))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user