Request and Reply Messaging Abstraction and first Consumers #136

Closed
muellerr wants to merge 95 commits from request-reply-messaging-mode-tree into main
9 changed files with 566 additions and 601 deletions
Showing only changes of commit d2c4cd7428 - Show all commits

View File

@ -1,7 +1,10 @@
use log::{error, warn}; use log::{error, warn};
use satrs::action::{ActionRequest, ActionRequestVariant}; use satrs::action::{ActionRequest, ActionRequestVariant};
use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pool::{SharedStaticMemoryPool, StoreAddr};
use satrs::pus::action::PusService8ActionRequestHandler; use satrs::pus::action::{
ActionReplyPusWithActionId, ActiveActionRequest, DefaultActiveActionRequestMap,
PusService8ActionRequestHandler, PusService8ReplyHandler,
};
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, TcStateAccepted, VerificationReporterWithSharedPoolMpscBoundedSender, FailParams, TcStateAccepted, VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider, VerificationToken, VerificationReporterWithVecMpscSender, VerificationReportingProvider, VerificationToken,
@ -9,8 +12,9 @@ use satrs::pus::verification::{
use satrs::pus::{ use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter,
EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult,
PusPacketHandlingError, PusServiceHelper, PusTcToRequestConverter, TmAsVecSenderWithId, PusPacketHandlingError, PusServiceHelper, PusTcToRequestConverter, ReplyHandlerHook,
TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId, TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc,
TmInSharedPoolSenderWithId,
}; };
use satrs::request::TargetAndApidId; use satrs::request::TargetAndApidId;
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
@ -22,8 +26,6 @@ use std::sync::mpsc::{self};
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use super::GenericRoutingErrorHandler;
#[derive(Default)] #[derive(Default)]
pub struct ExampleActionRequestConverter {} pub struct ExampleActionRequestConverter {}
@ -97,19 +99,29 @@ pub fn create_action_service_static(
"PUS_8_TC_RECV", "PUS_8_TC_RECV",
pus_action_rx, pus_action_rx,
); );
let pus_8_handler = PusService8ActionRequestHandler::new( let action_request_handler = PusService8ActionRequestHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
action_srv_receiver, action_srv_receiver,
action_srv_tm_sender, action_srv_tm_sender.clone(),
PUS_APID, PUS_APID,
verif_reporter.clone(), verif_reporter.clone(),
EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048), EcssTcInSharedStoreConverter::new(tc_pool.clone(), 2048),
), ),
ExampleActionRequestConverter::default(), ExampleActionRequestConverter::default(),
action_router, action_router,
GenericRoutingErrorHandler::<8>::default(),
); );
Pus8Wrapper { pus_8_handler } let action_reply_handler = PusService8ReplyHandler::new_from_now(
verif_reporter.clone(),
DefaultActiveActionRequestMap::default(),
1024,
PusActionReplyHook::default(),
action_srv_tm_sender,
)
.expect("Failed to create PUS 8 reply handler");
Pus8Wrapper {
action_request_handler,
action_reply_handler,
}
} }
pub fn create_action_service_dynamic( pub fn create_action_service_dynamic(
@ -133,35 +145,69 @@ pub fn create_action_service_dynamic(
"PUS_8_TC_RECV", "PUS_8_TC_RECV",
pus_action_rx, pus_action_rx,
); );
let pus_8_handler = PusService8ActionRequestHandler::new( let action_request_handler = PusService8ActionRequestHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
action_srv_receiver, action_srv_receiver,
action_srv_tm_sender, action_srv_tm_sender.clone(),
PUS_APID, PUS_APID,
verif_reporter.clone(), verif_reporter.clone(),
EcssTcInVecConverter::default(), EcssTcInVecConverter::default(),
), ),
ExampleActionRequestConverter::default(), ExampleActionRequestConverter::default(),
action_router, action_router,
GenericRoutingErrorHandler::<8>::default(),
); );
Pus8Wrapper { pus_8_handler } let action_reply_handler = PusService8ReplyHandler::new_from_now(
verif_reporter.clone(),
DefaultActiveActionRequestMap::default(),
1024,
PusActionReplyHook::default(),
action_srv_tm_sender,
)
.expect("Failed to create PUS 8 reply handler");
Pus8Wrapper {
action_request_handler,
action_reply_handler,
}
} }
#[derive(Default)]
pub struct PusActionReplyHook {}
impl ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithActionId> for PusActionReplyHook {
fn handle_unexpected_reply(
&mut self,
reply: &satrs::request::GenericMessage<ActionReplyPusWithActionId>,
) {
println!("received unexpected action reply {:?}", reply);
}
fn timeout_callback(&self, active_request: &ActiveActionRequest) {
println!("active request {active_request:?} timed out");
}
fn timeout_error_code(&self) -> satrs::res_code::ResultU16 {
todo!()
}
}
pub struct Pus8Wrapper< pub struct Pus8Wrapper<
TcReceiver: EcssTcReceiverCore, TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore, TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> { > {
pub(crate) pus_8_handler: PusService8ActionRequestHandler< pub(crate) action_request_handler: PusService8ActionRequestHandler<
TcReceiver, TcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
ExampleActionRequestConverter, ExampleActionRequestConverter,
GenericRequestRouter, GenericRequestRouter,
GenericRoutingErrorHandler<8>, >,
pub(crate) action_reply_handler: PusService8ReplyHandler<
VerificationReporter,
DefaultActiveActionRequestMap,
PusActionReplyHook,
TmSender,
>, >,
} }
@ -173,7 +219,7 @@ impl<
> Pus8Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter> > Pus8Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
{ {
pub fn handle_next_packet(&mut self) -> bool { pub fn handle_next_packet(&mut self) -> bool {
match self.pus_8_handler.handle_one_tc() { match self.action_request_handler.handle_one_tc() {
Ok(result) => match result { Ok(result) => match result {
PusPacketHandlerResult::RequestHandled => {} PusPacketHandlerResult::RequestHandled => {}
PusPacketHandlerResult::RequestHandledPartialSuccess(e) => { PusPacketHandlerResult::RequestHandledPartialSuccess(e) => {
@ -193,6 +239,7 @@ impl<
error!("PUS packet handling error: {error:?}") error!("PUS packet handling error: {error:?}")
} }
} }
// self.action_reply_handler.handle_replies();
false false
} }
} }

View File

@ -1,18 +1,16 @@
use log::{error, warn}; use log::{error, warn};
use satrs::hk::{CollectionIntervalFactor, HkRequest}; use satrs::hk::{CollectionIntervalFactor, HkRequest};
use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pool::{SharedStaticMemoryPool, StoreAddr};
use satrs::pus::hk::{PusHkToRequestConverter, PusService3HkHandler}; use satrs::pus::hk::PusService3HkRequestHandler;
use satrs::pus::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use satrs::pus::verification::{ use satrs::pus::verification::{
FailParams, TcStateAccepted, VerificationReportingProvider, VerificationToken, FailParams, TcStateAccepted, VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider, VerificationToken,
}; };
use satrs::pus::{ use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter,
EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult,
PusPacketHandlingError, PusServiceHelper, TmAsVecSenderWithId, TmAsVecSenderWithMpsc, PusPacketHandlingError, PusServiceHelper, PusTcToRequestConverter, TmAsVecSenderWithId,
TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId,
}; };
use satrs::request::TargetAndApidId; use satrs::request::TargetAndApidId;
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
@ -24,12 +22,10 @@ use std::sync::mpsc::{self};
use crate::requests::GenericRequestRouter; use crate::requests::GenericRequestRouter;
use super::GenericRoutingErrorHandler;
#[derive(Default)] #[derive(Default)]
pub struct ExampleHkRequestConverter {} pub struct ExampleHkRequestConverter {}
impl PusHkToRequestConverter for ExampleHkRequestConverter { impl PusTcToRequestConverter<HkRequest> for ExampleHkRequestConverter {
type Error = PusPacketHandlingError; type Error = PusPacketHandlingError;
fn convert( fn convert(
@ -165,7 +161,7 @@ pub fn create_hk_service_static(
); );
let hk_srv_receiver = let hk_srv_receiver =
MpscTcReceiver::new(TcReceiverId::PusHk as ChannelId, "PUS_8_TC_RECV", pus_hk_rx); MpscTcReceiver::new(TcReceiverId::PusHk as ChannelId, "PUS_8_TC_RECV", pus_hk_rx);
let pus_3_handler = PusService3HkHandler::new( let pus_3_handler = PusService3HkRequestHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
hk_srv_receiver, hk_srv_receiver,
hk_srv_tm_sender, hk_srv_tm_sender,
@ -175,7 +171,6 @@ pub fn create_hk_service_static(
), ),
ExampleHkRequestConverter::default(), ExampleHkRequestConverter::default(),
request_router, request_router,
GenericRoutingErrorHandler::default(),
); );
Pus3Wrapper { pus_3_handler } Pus3Wrapper { pus_3_handler }
} }
@ -198,7 +193,7 @@ pub fn create_hk_service_dynamic(
); );
let hk_srv_receiver = let hk_srv_receiver =
MpscTcReceiver::new(TcReceiverId::PusHk as ChannelId, "PUS_8_TC_RECV", pus_hk_rx); MpscTcReceiver::new(TcReceiverId::PusHk as ChannelId, "PUS_8_TC_RECV", pus_hk_rx);
let pus_3_handler = PusService3HkHandler::new( let pus_3_handler = PusService3HkRequestHandler::new(
PusServiceHelper::new( PusServiceHelper::new(
hk_srv_receiver, hk_srv_receiver,
hk_srv_tm_sender, hk_srv_tm_sender,
@ -208,7 +203,6 @@ pub fn create_hk_service_dynamic(
), ),
ExampleHkRequestConverter::default(), ExampleHkRequestConverter::default(),
request_router, request_router,
GenericRoutingErrorHandler::default(),
); );
Pus3Wrapper { pus_3_handler } Pus3Wrapper { pus_3_handler }
} }
@ -219,14 +213,13 @@ pub struct Pus3Wrapper<
TcInMemConverter: EcssTcInMemConverter, TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
> { > {
pub(crate) pus_3_handler: PusService3HkHandler< pub(crate) pus_3_handler: PusService3HkRequestHandler<
TcReceiver, TcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
ExampleHkRequestConverter, ExampleHkRequestConverter,
GenericRequestRouter, GenericRequestRouter,
GenericRoutingErrorHandler<3>,
>, >,
} }

View File

@ -1,9 +1,7 @@
use crate::tmtc::MpscStoreAndSendError; use crate::tmtc::MpscStoreAndSendError;
use log::warn; use log::warn;
use satrs::pus::verification::{FailParams, VerificationReportingProvider}; use satrs::pus::verification::{FailParams, VerificationReportingProvider};
use satrs::pus::{ use satrs::pus::{EcssTcAndToken, PusPacketHandlerResult, TcInMemory};
EcssTcAndToken, GenericRoutingError, PusPacketHandlerResult, PusRoutingErrorHandler, TcInMemory,
};
use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusServiceId; use satrs::spacepackets::ecss::PusServiceId;
use satrs::spacepackets::time::cds::TimeProvider; use satrs::spacepackets::time::cds::TimeProvider;
@ -153,56 +151,3 @@ impl<VerificationReporter: VerificationReportingProvider> PusReceiver<Verificati
Ok(PusPacketHandlerResult::RequestHandled) Ok(PusPacketHandlerResult::RequestHandled)
} }
} }
#[derive(Default)]
pub struct GenericRoutingErrorHandler<const SERVICE_ID: u8> {}
impl<const SERVICE_ID: u8> PusRoutingErrorHandler for GenericRoutingErrorHandler<SERVICE_ID> {
type Error = satrs::pus::GenericRoutingError;
fn handle_error(
&self,
target_id: satrs::TargetId,
token: satrs::pus::verification::VerificationToken<
satrs::pus::verification::TcStateAccepted,
>,
_tc: &PusTcReader,
error: Self::Error,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) {
warn!("Routing request for service {SERVICE_ID} failed: {error:?}");
match error {
GenericRoutingError::UnknownTargetId(id) => {
let mut fail_data: [u8; 8] = [0; 8];
fail_data.copy_from_slice(&id.to_be_bytes());
verif_reporter
.start_failure(
token,
FailParams::new(time_stamp, &tmtc_err::UNKNOWN_TARGET_ID, &fail_data),
)
.expect("Sending start failure failed");
}
GenericRoutingError::SendError(_) => {
let mut fail_data: [u8; 8] = [0; 8];
fail_data.copy_from_slice(&target_id.to_be_bytes());
verif_reporter
.start_failure(
token,
FailParams::new(time_stamp, &tmtc_err::ROUTING_ERROR, &fail_data),
)
.expect("Sending start failure failed");
}
GenericRoutingError::NotEnoughAppData { expected, found } => {
let mut context_info = (found as u32).to_be_bytes().to_vec();
context_info.extend_from_slice(&(expected as u32).to_be_bytes());
verif_reporter
.start_failure(
token,
FailParams::new(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, &context_info),
)
.expect("Sending start failure failed");
}
}
}
}

View File

@ -2,14 +2,19 @@ use std::collections::HashMap;
use std::sync::mpsc; use std::sync::mpsc;
use derive_new::new; use derive_new::new;
use log::warn;
use satrs::action::ActionRequest; use satrs::action::ActionRequest;
use satrs::hk::HkRequest; use satrs::hk::HkRequest;
use satrs::mode::ModeRequest; use satrs::mode::ModeRequest;
use satrs::pus::hk::PusHkRequestRouter; use satrs::pus::verification::{
use satrs::pus::verification::{TcStateAccepted, VerificationToken}; FailParams, TcStateAccepted, VerificationReportingProvider, VerificationToken,
};
use satrs::pus::{GenericRoutingError, PusRequestRouter}; use satrs::pus::{GenericRoutingError, PusRequestRouter};
use satrs::queue::GenericSendError; use satrs::queue::GenericSendError;
use satrs::spacepackets::ecss::tc::PusTcReader;
use satrs::spacepackets::ecss::PusPacket;
use satrs::TargetId; use satrs::TargetId;
use satrs_example::config::tmtc_err;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Clone, Eq, PartialEq, Debug)] #[derive(Clone, Eq, PartialEq, Debug)]
@ -48,7 +53,57 @@ impl RequestWithToken {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct GenericRequestRouter(pub HashMap<TargetId, mpsc::Sender<RequestWithToken>>); pub struct GenericRequestRouter(pub HashMap<TargetId, mpsc::Sender<RequestWithToken>>);
impl PusHkRequestRouter for GenericRequestRouter { impl GenericRequestRouter {
fn handle_error_generic(
&self,
target_id: satrs::TargetId,
token: satrs::pus::verification::VerificationToken<
satrs::pus::verification::TcStateAccepted,
>,
tc: &PusTcReader,
error: GenericRoutingError,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) {
warn!(
"Routing request for service {} failed: {error:?}",
tc.service()
);
match error {
GenericRoutingError::UnknownTargetId(id) => {
let mut fail_data: [u8; 8] = [0; 8];
fail_data.copy_from_slice(&id.to_be_bytes());
verif_reporter
.start_failure(
token,
FailParams::new(time_stamp, &tmtc_err::UNKNOWN_TARGET_ID, &fail_data),
)
.expect("Sending start failure failed");
}
GenericRoutingError::SendError(_) => {
let mut fail_data: [u8; 8] = [0; 8];
fail_data.copy_from_slice(&target_id.to_be_bytes());
verif_reporter
.start_failure(
token,
FailParams::new(time_stamp, &tmtc_err::ROUTING_ERROR, &fail_data),
)
.expect("Sending start failure failed");
}
GenericRoutingError::NotEnoughAppData { expected, found } => {
let mut context_info = (found as u32).to_be_bytes().to_vec();
context_info.extend_from_slice(&(expected as u32).to_be_bytes());
verif_reporter
.start_failure(
token,
FailParams::new(time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, &context_info),
)
.expect("Sending start failure failed");
}
}
}
}
impl PusRequestRouter<HkRequest> for GenericRequestRouter {
type Error = GenericRoutingError; type Error = GenericRoutingError;
fn route( fn route(
@ -68,6 +123,19 @@ impl PusHkRequestRouter for GenericRequestRouter {
} }
Ok(()) Ok(())
} }
fn handle_error(
&self,
target_id: satrs::TargetId,
token: satrs::pus::verification::VerificationToken<
satrs::pus::verification::TcStateAccepted,
>,
tc: &PusTcReader,
error: GenericRoutingError,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) {
self.handle_error_generic(target_id, token, tc, error, time_stamp, verif_reporter)
}
} }
impl PusRequestRouter<ActionRequest> for GenericRequestRouter { impl PusRequestRouter<ActionRequest> for GenericRequestRouter {
@ -90,4 +158,17 @@ impl PusRequestRouter<ActionRequest> for GenericRequestRouter {
} }
Ok(()) Ok(())
} }
fn handle_error(
&self,
target_id: satrs::TargetId,
token: satrs::pus::verification::VerificationToken<
satrs::pus::verification::TcStateAccepted,
>,
tc: &PusTcReader,
error: GenericRoutingError,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) {
self.handle_error_generic(target_id, token, tc, error, time_stamp, verif_reporter)
}
} }

View File

@ -1,4 +1,5 @@
use core::mem::size_of; use core::mem::size_of;
use satrs_shared::res_code::ResultU16;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use spacepackets::ByteConversionError; use spacepackets::ByteConversionError;
@ -53,7 +54,7 @@ impl ModeAndSubmode {
}) })
} }
pub fn to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> { pub fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
if buf.len() < Self::RAW_LEN { if buf.len() < Self::RAW_LEN {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
expected: Self::RAW_LEN, expected: Self::RAW_LEN,
@ -114,6 +115,13 @@ pub enum ModeRequest {
AnnounceModeRecursive, AnnounceModeRecursive,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TargetedModeRequest {
target_id: TargetId,
mode_request: ModeRequest,
}
#[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 {
@ -121,20 +129,15 @@ pub enum ModeReply {
ModeInfo(ModeAndSubmode), 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. Returns the mode which was reached in the end. // Can not reach the commanded mode. Contains a reason as a [ResultU16].
CantReachMode(ModeAndSubmode), CantReachMode(ResultU16),
WrongMode { WrongMode {
expected: ModeAndSubmode, expected: ModeAndSubmode,
reached: ModeAndSubmode, reached: ModeAndSubmode,
}, },
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub type GenericModeReply = GenericMessage<ModeReply>;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TargetedModeRequest {
target_id: TargetId,
mode_request: ModeRequest,
}
pub trait ModeRequestSender { pub trait ModeRequestSender {
fn local_channel_id(&self) -> ChannelId; fn local_channel_id(&self) -> ChannelId;
@ -146,37 +149,12 @@ pub trait ModeRequestSender {
) -> Result<(), GenericTargetedMessagingError>; ) -> Result<(), GenericTargetedMessagingError>;
} }
pub trait ModeReplySender {
fn local_channel_id(&self) -> ChannelId;
fn send_mode_reply(
&self,
request_id: RequestId,
target_id: ChannelId,
reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError>;
}
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>>, GenericTargetedMessagingError>;
} }
pub trait ModeReplyReceiver {
fn try_recv_mode_reply(
&self,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError>;
}
impl<R: MessageReceiver<ModeReply>> ModeReplyReceiver for MessageReceiverWithId<ModeReply, R> {
fn try_recv_mode_reply(
&self,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> {
self.try_recv_message()
}
}
impl<R: MessageReceiver<ModeRequest>> ModeRequestReceiver impl<R: MessageReceiver<ModeRequest>> ModeRequestReceiver
for MessageReceiverWithId<ModeRequest, R> for MessageReceiverWithId<ModeRequest, R>
{ {
@ -214,32 +192,46 @@ pub trait ModeRequestHandler: ModeProvider {
fn handle_mode_reached(&mut self) -> Result<(), GenericTargetedMessagingError>; fn handle_mode_reached(&mut self) -> Result<(), GenericTargetedMessagingError>;
} }
pub trait ModeReplyReceiver {
fn try_recv_mode_reply(
&self,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError>;
}
impl<R: MessageReceiver<ModeReply>> ModeReplyReceiver for MessageReceiverWithId<ModeReply, R> {
fn try_recv_mode_reply(
&self,
) -> Result<Option<GenericMessage<ModeReply>>, GenericTargetedMessagingError> {
self.try_recv_message()
}
}
pub trait ModeReplySender {
fn local_channel_id(&self) -> ChannelId;
fn send_mode_reply(
&self,
request_id: RequestId,
target_id: ChannelId,
reply: ModeReply,
) -> Result<(), GenericTargetedMessagingError>;
}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub mod alloc_mod { pub mod alloc_mod {
use crate::request::{ use crate::{
mode::ModeRequest,
queue::GenericTargetedMessagingError,
request::{
MessageSender, MessageSenderAndReceiver, MessageSenderMap, MessageSenderMapWithId, MessageSender, MessageSenderAndReceiver, MessageSenderMap, MessageSenderMapWithId,
RequestAndReplySenderAndReceiver, RequestAndReplySenderAndReceiver, RequestId,
},
ChannelId,
}; };
use super::*; use super::*;
impl<S: MessageSender<ModeRequest>> MessageSenderMap<ModeRequest, S> {
pub fn send_mode_request(
&self,
request_id: RequestId,
local_id: ChannelId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.send_message(request_id, local_id, target_id, request)
}
pub fn add_request_target(&mut self, target_id: ChannelId, request_sender: S) {
self.add_message_target(target_id, request_sender)
}
}
impl<S: MessageSender<ModeReply>> MessageSenderMap<ModeReply, S> { impl<S: MessageSender<ModeReply>> MessageSenderMap<ModeReply, S> {
pub fn send_mode_reply( pub fn send_mode_reply(
&self, &self,
@ -271,21 +263,6 @@ pub mod alloc_mod {
} }
} }
impl<S: MessageSender<ModeRequest>> ModeRequestSender for MessageSenderMapWithId<ModeRequest, S> {
fn local_channel_id(&self) -> ChannelId {
self.local_channel_id
}
fn send_mode_request(
&self,
request_id: RequestId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.send_message(request_id, target_id, request)
}
}
impl<FROM, S: MessageSender<ModeReply>, R: MessageReceiver<FROM>> ModeReplySender impl<FROM, S: MessageSender<ModeReply>, R: MessageReceiver<FROM>> ModeReplySender
for MessageSenderAndReceiver<ModeReply, FROM, S, R> for MessageSenderAndReceiver<ModeReply, FROM, S, R>
{ {
@ -317,51 +294,6 @@ pub mod alloc_mod {
self.message_receiver.try_recv_message() self.message_receiver.try_recv_message()
} }
} }
impl<TO, S: MessageSender<TO>, R: MessageReceiver<ModeRequest>> ModeRequestReceiver
for MessageSenderAndReceiver<TO, ModeRequest, S, R>
{
fn try_recv_mode_request(
&self,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> {
self.message_receiver.try_recv_message()
}
}
impl<FROM, S: MessageSender<ModeRequest>, R: MessageReceiver<FROM>> ModeRequestSender
for MessageSenderAndReceiver<ModeRequest, FROM, S, R>
{
fn local_channel_id(&self) -> ChannelId {
self.local_channel_id_generic()
}
fn send_mode_request(
&self,
request_id: RequestId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_mode_request(
request_id,
self.local_channel_id(),
target_id,
request,
)
}
}
impl<
REPLY,
S0: MessageSender<ModeRequest>,
R0: MessageReceiver<REPLY>,
S1: MessageSender<REPLY>,
R1: MessageReceiver<ModeRequest>,
> RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
{
pub fn add_request_target(&mut self, target_id: ChannelId, request_sender: S0) {
self.request_sender_map
.add_message_target(target_id, request_sender)
}
}
impl< impl<
REQUEST, REQUEST,
@ -377,34 +309,6 @@ pub mod alloc_mod {
} }
} }
impl<
REPLY,
S0: MessageSender<ModeRequest>,
R0: MessageReceiver<REPLY>,
S1: MessageSender<REPLY>,
R1: MessageReceiver<ModeRequest>,
> ModeRequestSender
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
{
fn local_channel_id(&self) -> ChannelId {
self.local_channel_id_generic()
}
fn send_mode_request(
&self,
request_id: RequestId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.request_sender_map.send_mode_request(
request_id,
self.local_channel_id(),
target_id,
request,
)
}
}
impl< impl<
REQUEST, REQUEST,
S0: MessageSender<REQUEST>, S0: MessageSender<REQUEST>,
@ -448,22 +352,6 @@ pub mod alloc_mod {
} }
} }
impl<
REPLY,
S0: MessageSender<ModeRequest>,
R0: MessageReceiver<REPLY>,
S1: MessageSender<REPLY>,
R1: MessageReceiver<ModeRequest>,
> ModeRequestReceiver
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
{
fn try_recv_mode_request(
&self,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> {
self.request_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<S, R> =
MessageSenderAndReceiver<ModeReply, ModeRequest, S, R>; MessageSenderAndReceiver<ModeReply, ModeRequest, S, R>;
@ -511,6 +399,127 @@ pub mod alloc_mod {
/// process mode requests. /// process mode requests.
pub type ModeInterface<S0, R0, S1, R1> = pub type ModeInterface<S0, R0, S1, R1> =
RequestAndReplySenderAndReceiver<ModeRequest, ModeReply, S0, R0, S1, R1>; RequestAndReplySenderAndReceiver<ModeRequest, ModeReply, S0, R0, S1, R1>;
impl<S: MessageSender<ModeRequest>> MessageSenderMap<ModeRequest, S> {
pub fn send_mode_request(
&self,
request_id: RequestId,
local_id: ChannelId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.send_message(request_id, local_id, target_id, request)
}
pub fn add_request_target(&mut self, target_id: ChannelId, request_sender: S) {
self.add_message_target(target_id, request_sender)
}
}
impl<S: MessageSender<ModeRequest>> ModeRequestSender for MessageSenderMapWithId<ModeRequest, S> {
fn local_channel_id(&self) -> ChannelId {
self.local_channel_id
}
fn send_mode_request(
&self,
request_id: RequestId,
target_id: ChannelId,
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(
&self,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> {
self.message_receiver.try_recv_message()
}
}
impl<FROM, S: MessageSender<ModeRequest>, R: MessageReceiver<FROM>> ModeRequestSender
for MessageSenderAndReceiver<ModeRequest, FROM, S, R>
{
fn local_channel_id(&self) -> ChannelId {
self.local_channel_id_generic()
}
fn send_mode_request(
&self,
request_id: RequestId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.message_sender_map.send_mode_request(
request_id,
self.local_channel_id(),
target_id,
request,
)
}
}
impl<
REPLY,
S0: MessageSender<ModeRequest>,
R0: MessageReceiver<REPLY>,
S1: MessageSender<REPLY>,
R1: MessageReceiver<ModeRequest>,
> RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
{
pub fn add_request_target(&mut self, target_id: ChannelId, request_sender: S0) {
self.request_sender_map
.add_message_target(target_id, request_sender)
}
}
impl<
REPLY,
S0: MessageSender<ModeRequest>,
R0: MessageReceiver<REPLY>,
S1: MessageSender<REPLY>,
R1: MessageReceiver<ModeRequest>,
> ModeRequestSender
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
{
fn local_channel_id(&self) -> ChannelId {
self.local_channel_id_generic()
}
fn send_mode_request(
&self,
request_id: RequestId,
target_id: ChannelId,
request: ModeRequest,
) -> Result<(), GenericTargetedMessagingError> {
self.request_sender_map.send_mode_request(
request_id,
self.local_channel_id(),
target_id,
request,
)
}
}
impl<
REPLY,
S0: MessageSender<ModeRequest>,
R0: MessageReceiver<REPLY>,
S1: MessageSender<REPLY>,
R1: MessageReceiver<ModeRequest>,
> ModeRequestReceiver
for RequestAndReplySenderAndReceiver<ModeRequest, REPLY, S0, R0, S1, R1>
{
fn try_recv_mode_request(
&self,
) -> Result<Option<GenericMessage<ModeRequest>>, GenericTargetedMessagingError> {
self.request_receiver.try_recv_message()
}
}
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -518,6 +527,8 @@ pub mod alloc_mod {
pub mod std_mod { pub mod std_mod {
use std::sync::mpsc; use std::sync::mpsc;
use crate::request::GenericMessage;
use super::*; use super::*;
pub type ModeRequestHandlerMpsc = ModeRequestHandlerInterface< pub type ModeRequestHandlerMpsc = ModeRequestHandlerInterface<
@ -553,115 +564,4 @@ pub mod std_mod {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {}
use std::sync::mpsc;
use crate::{
mode::{ModeAndSubmode, ModeReply, ModeReplySender, ModeRequestSender},
request::GenericMessage,
};
use super::{ModeRequest, ModeRequestorAndHandlerMpsc, ModeRequestorMpsc};
const TEST_CHANNEL_ID_0: u32 = 5;
const TEST_CHANNEL_ID_1: u32 = 6;
const TEST_CHANNEL_ID_2: u32 = 7;
#[test]
fn test_simple_mode_requestor() {
let (reply_sender, reply_receiver) = mpsc::channel();
let (request_sender, request_receiver) = mpsc::channel();
let mut mode_requestor = ModeRequestorMpsc::new(TEST_CHANNEL_ID_0, reply_receiver);
mode_requestor.add_message_target(TEST_CHANNEL_ID_1, request_sender);
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_request = ModeRequest::ReadMode;
mode_requestor
.send_mode_request(request_id, TEST_CHANNEL_ID_1, sent_request)
.expect("send failed");
let request = request_receiver.recv().expect("recv failed");
assert_eq!(request.request_id, 2);
assert_eq!(request.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(request.message, sent_request);
// Send a reply and verify it arrives at the requestor.
let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(1, 5));
reply_sender
.send(GenericMessage::new(
request_id,
TEST_CHANNEL_ID_1,
mode_reply,
))
.expect("send failed");
let reply = mode_requestor.try_recv_mode_reply().expect("recv failed");
assert!(reply.is_some());
let reply = reply.unwrap();
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_1);
assert_eq!(reply.request_id, 2);
assert_eq!(reply.message, mode_reply);
}
#[test]
fn test_mode_requestor_and_request_handler_request_sending() {
let (_reply_sender_to_connector, reply_receiver_of_connector) = mpsc::channel();
let (_request_sender_to_connector, request_receiver_of_connector) = mpsc::channel();
let (request_sender_to_channel_1, request_receiver_channel_1) = mpsc::channel();
//let (reply_sender_to_channel_2, reply_receiver_channel_2) = mpsc::channel();
let mut mode_connector = ModeRequestorAndHandlerMpsc::new(
TEST_CHANNEL_ID_0,
request_receiver_of_connector,
reply_receiver_of_connector,
);
assert_eq!(
ModeRequestSender::local_channel_id(&mode_connector),
TEST_CHANNEL_ID_0
);
assert_eq!(
ModeReplySender::local_channel_id(&mode_connector),
TEST_CHANNEL_ID_0
);
assert_eq!(mode_connector.local_channel_id_generic(), TEST_CHANNEL_ID_0);
mode_connector.add_request_target(TEST_CHANNEL_ID_1, request_sender_to_channel_1);
//mode_connector.add_reply_target(TEST_CHANNEL_ID_2, reply_sender_to_channel_2);
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_request = ModeRequest::ReadMode;
mode_connector
.send_mode_request(request_id, TEST_CHANNEL_ID_1, sent_request)
.expect("send failed");
let request = request_receiver_channel_1.recv().expect("recv failed");
assert_eq!(request.request_id, 2);
assert_eq!(request.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(request.message, ModeRequest::ReadMode);
}
#[test]
fn test_mode_requestor_and_request_handler_reply_sending() {
let (_reply_sender_to_connector, reply_receiver_of_connector) = mpsc::channel();
let (_request_sender_to_connector, request_receiver_of_connector) = mpsc::channel();
let (reply_sender_to_channel_2, reply_receiver_channel_2) = mpsc::channel();
let mut mode_connector = ModeRequestorAndHandlerMpsc::new(
TEST_CHANNEL_ID_0,
request_receiver_of_connector,
reply_receiver_of_connector,
);
mode_connector.add_reply_target(TEST_CHANNEL_ID_2, reply_sender_to_channel_2);
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_reply = ModeReply::ModeInfo(ModeAndSubmode::new(3, 5));
mode_connector
.send_mode_reply(request_id, TEST_CHANNEL_ID_2, sent_reply)
.expect("send failed");
let reply = reply_receiver_channel_2.recv().expect("recv failed");
assert_eq!(reply.request_id, 2);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(reply.message, sent_reply);
}
}

View File

@ -122,7 +122,6 @@ pub mod std_mod {
VerificationReporter, VerificationReporter,
RequestConverter, RequestConverter,
RequestRouter, RequestRouter,
RoutingErrorHandler,
RoutingError = GenericRoutingError, RoutingError = GenericRoutingError,
> = PusTargetedRequestHandler< > = PusTargetedRequestHandler<
TcReceiver, TcReceiver,
@ -131,7 +130,6 @@ pub mod std_mod {
VerificationReporter, VerificationReporter,
RequestConverter, RequestConverter,
RequestRouter, RequestRouter,
RoutingErrorHandler,
ActionRequest, ActionRequest,
RoutingError, RoutingError,
>; >;
@ -326,7 +324,7 @@ mod tests {
pus::{ pus::{
tests::{ tests::{
PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler,
TestConverter, TestRouter, TestRoutingErrorHandler, APP_DATA_TOO_SHORT, TEST_APID, TestConverter, TestRouter, APP_DATA_TOO_SHORT, TEST_APID,
}, },
verification::{ verification::{
self, self,
@ -356,6 +354,20 @@ mod tests {
.push_back((target_id, request)); .push_back((target_id, request));
self.check_for_injected_error() self.check_for_injected_error()
} }
fn handle_error(
&self,
target_id: TargetId,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
error: Self::Error,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) {
self.routing_errors
.borrow_mut()
.push_back((target_id, error));
}
} }
impl PusTcToRequestConverter<ActionRequest> for TestConverter<8> { impl PusTcToRequestConverter<ActionRequest> for TestConverter<8> {
@ -413,7 +425,6 @@ mod tests {
TestVerificationReporter, TestVerificationReporter,
TestConverter<8>, TestConverter<8>,
TestRouter<ActionRequest>, TestRouter<ActionRequest>,
TestRoutingErrorHandler,
>, >,
} }
@ -427,7 +438,6 @@ mod tests {
srv_handler, srv_handler,
TestConverter::default(), TestConverter::default(),
TestRouter::default(), TestRouter::default(),
TestRoutingErrorHandler::default(),
), ),
} }
} }
@ -443,8 +453,8 @@ mod tests {
} }
} }
delegate! { delegate! {
to self.handler.routing_error_handler { to self.handler.request_router {
pub fn retrieve_next_error(&mut self) -> (TargetId, GenericRoutingError); pub fn retrieve_next_routing_error(&mut self) -> (TargetId, GenericRoutingError);
} }
} }
} }
@ -714,7 +724,7 @@ mod tests {
assert_eq!(data, &[]); assert_eq!(data, &[]);
} }
let (target_id, found_error) = action_handler.retrieve_next_error(); let (target_id, found_error) = action_handler.retrieve_next_routing_error();
assert_eq!(target_id, TEST_APID.into()); assert_eq!(target_id, TEST_APID.into());
check_error(found_error); check_error(found_error);
} }

View File

@ -6,6 +6,7 @@ pub use std_mod::*;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[allow(unused_imports)]
pub use alloc_mod::*; pub use alloc_mod::*;
use crate::{hk::HkRequest, TargetId}; use crate::{hk::HkRequest, TargetId};
@ -26,158 +27,33 @@ pub trait PusHkRequestRouter {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub mod alloc_mod { pub mod alloc_mod {}
use spacepackets::ecss::tc::PusTcReader;
use crate::pus::verification::VerificationReportingProvider;
use super::*;
/// This trait is an abstraction for the conversion of a PUS service 8 action telecommand into
/// a [HkRequest].
///
/// Having a dedicated trait for this allows maximum flexiblity and tailoring of the standard.
/// The only requirement is that a valid [TargetId] and a [HkRequest] are returned by the
/// core conversion function.
///
/// The user should take care of performing the error handling as well. Some of the following
/// aspects might be relevant:
///
/// - Checking the validity of the APID, service ID, subservice ID.
/// - Checking the validity of the user data.
///
/// A [VerificationReportingProvider] is passed to the user to also allow handling
/// of the verification process as part of the PUS standard requirements.
pub trait PusHkToRequestConverter {
type Error;
fn convert(
&mut self,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) -> Result<(TargetId, HkRequest), Self::Error>;
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub mod std_mod { pub mod std_mod {
use crate::pus::{ use crate::pus::{GenericRoutingError, PusTargetedRequestHandler};
get_current_cds_short_timestamp, verification::VerificationReportingProvider,
EcssTcInMemConverter, EcssTcReceiverCore, EcssTmSenderCore, GenericRoutingError,
PusPacketHandlerResult, PusPacketHandlingError, PusRoutingErrorHandler, PusServiceHelper,
};
use super::*; use super::*;
/// This is a generic high-level handler for the PUS service 3 housekeeping service. pub type PusService3HkRequestHandler<
///
/// It performs the following handling steps:
///
/// 1. Retrieve the next TC packet from the [PusServiceHelper]. The [EcssTcInMemConverter]
/// allows to configure the used telecommand memory backend.
/// 2. Convert the TC to a targeted action request using the provided
/// [PusHkToRequestConverter]. The generic error type is constrained to the
/// [PusPacketHandlerResult] for the concrete implementation which offers a packet handler.
/// 3. Route the action request using the provided [PusHkRequestRouter]. The generic error
/// type is constrained to the [GenericRoutingError] for the concrete implementation.
/// 4. Handle all routing errors using the provided [PusRoutingErrorHandler]. The generic error
/// type is constrained to the [GenericRoutingError] for the concrete implementation.
pub struct PusService3HkHandler<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
RequestConverter: PusHkToRequestConverter,
RequestRouter: PusHkRequestRouter<Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
RoutingError = GenericRoutingError,
> {
service_helper:
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub request_converter: RequestConverter,
pub request_router: RequestRouter,
pub routing_error_handler: RoutingErrorHandler,
}
impl<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
RequestConverter: PusHkToRequestConverter<Error = PusPacketHandlingError>,
RequestRouter: PusHkRequestRouter<Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
RoutingError: Clone,
>
PusService3HkHandler<
TcReceiver, TcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
RequestConverter, RequestConverter,
RequestRouter, RequestRouter,
RoutingErrorHandler, RoutingError = GenericRoutingError,
RoutingError, > = PusTargetedRequestHandler<
>
where
PusPacketHandlingError: From<RoutingError>,
{
pub fn new(
service_helper: PusServiceHelper<
TcReceiver, TcReceiver,
TmSender, TmSender,
TcInMemConverter, TcInMemConverter,
VerificationReporter, VerificationReporter,
>, RequestConverter,
request_converter: RequestConverter, RequestRouter,
request_router: RequestRouter, HkRequest,
routing_error_handler: RoutingErrorHandler, RoutingError,
) -> Self { >;
Self {
service_helper,
request_converter,
request_router,
routing_error_handler,
}
}
pub fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?;
if possible_packet.is_none() {
return Ok(PusPacketHandlerResult::Empty);
}
let ecss_tc_and_token = possible_packet.unwrap();
let tc = self
.service_helper
.tc_in_mem_converter
.convert_ecss_tc_in_memory_to_reader(&ecss_tc_and_token.tc_in_memory)?;
let mut partial_error = None;
let time_stamp = get_current_cds_short_timestamp(&mut partial_error);
let (target_id, hk_request) = self.request_converter.convert(
ecss_tc_and_token.token,
&tc,
&time_stamp,
&self.service_helper.common.verification_handler,
)?;
if let Err(e) =
self.request_router
.route(target_id, hk_request, ecss_tc_and_token.token)
{
self.routing_error_handler.handle_error(
target_id,
ecss_tc_and_token.token,
&tc,
e.clone(),
&time_stamp,
&self.service_helper.common.verification_handler,
);
return Err(e.into());
}
Ok(PusPacketHandlerResult::RequestHandled)
}
}
} }
#[cfg(test)] #[cfg(test)]
@ -194,13 +70,13 @@ mod tests {
CcsdsPacket, SequenceFlags, SpHeader, CcsdsPacket, SequenceFlags, SpHeader,
}; };
use crate::pus::{MpscTcReceiver, TmAsVecSenderWithMpsc}; use crate::pus::{MpscTcReceiver, PusTcToRequestConverter, TmAsVecSenderWithMpsc};
use crate::{ use crate::{
hk::HkRequest, hk::HkRequest,
pus::{ pus::{
tests::{ tests::{
PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler,
TestConverter, TestRouter, TestRoutingErrorHandler, APP_DATA_TOO_SHORT, TEST_APID, TestConverter, TestRouter, APP_DATA_TOO_SHORT, TEST_APID,
}, },
verification::{ verification::{
tests::TestVerificationReporter, FailParams, RequestId, TcStateAccepted, tests::TestVerificationReporter, FailParams, RequestId, TcStateAccepted,
@ -212,7 +88,7 @@ mod tests {
TargetId, TargetId,
}; };
use super::{PusHkRequestRouter, PusHkToRequestConverter, PusService3HkHandler}; use super::{PusHkRequestRouter, PusService3HkRequestHandler};
impl PusHkRequestRouter for TestRouter<HkRequest> { impl PusHkRequestRouter for TestRouter<HkRequest> {
type Error = GenericRoutingError; type Error = GenericRoutingError;
@ -230,7 +106,7 @@ mod tests {
} }
} }
impl PusHkToRequestConverter for TestConverter<3> { impl PusTcToRequestConverter<HkRequest> for TestConverter<3> {
type Error = PusPacketHandlingError; type Error = PusPacketHandlingError;
fn convert( fn convert(
&mut self, &mut self,
@ -277,14 +153,13 @@ mod tests {
struct Pus3HandlerWithVecTester { struct Pus3HandlerWithVecTester {
common: PusServiceHandlerWithVecCommon<TestVerificationReporter>, common: PusServiceHandlerWithVecCommon<TestVerificationReporter>,
handler: PusService3HkHandler< handler: PusService3HkRequestHandler<
MpscTcReceiver, MpscTcReceiver,
TmAsVecSenderWithMpsc, TmAsVecSenderWithMpsc,
EcssTcInVecConverter, EcssTcInVecConverter,
TestVerificationReporter, TestVerificationReporter,
TestConverter<3>, TestConverter<3>,
TestRouter<HkRequest>, TestRouter<HkRequest>,
TestRoutingErrorHandler,
>, >,
} }
@ -294,11 +169,10 @@ mod tests {
PusServiceHandlerWithVecCommon::new_with_test_verif_sender(); PusServiceHandlerWithVecCommon::new_with_test_verif_sender();
Self { Self {
common, common,
handler: PusService3HkHandler::new( handler: PusService3HkRequestHandler::new(
srv_handler, srv_handler,
TestConverter::default(), TestConverter::default(),
TestRouter::default(), TestRouter::default(),
TestRoutingErrorHandler::default(),
), ),
} }
} }
@ -314,8 +188,8 @@ mod tests {
} }
} }
delegate! { delegate! {
to self.handler.routing_error_handler { to self.handler.request_router {
pub fn retrieve_next_error(&mut self) -> (TargetId, GenericRoutingError); pub fn retrieve_next_routing_error(&mut self) -> (TargetId, GenericRoutingError);
} }
} }
} }
@ -399,7 +273,7 @@ mod tests {
assert_eq!(unique_id, 1); assert_eq!(unique_id, 1);
} }
let (target_id, found_error) = hk_handler.retrieve_next_error(); let (target_id, found_error) = hk_handler.retrieve_next_routing_error();
assert_eq!(target_id, TEST_APID.into()); assert_eq!(target_id, TEST_APID.into());
check_error(found_error); check_error(found_error);
} }

View File

@ -44,7 +44,7 @@ pub use alloc_mod::*;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std_mod::*; pub use std_mod::*;
use self::verification::{FailParams, TcStateStarted}; use self::verification::{FailParams, TcStateStarted, VerificationReportingProvider};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum PusTmWrapper<'tm> { pub enum PusTmWrapper<'tm> {
@ -347,6 +347,15 @@ pub trait PusRequestRouter<Request> {
hk_request: Request, hk_request: Request,
token: VerificationToken<TcStateAccepted>, token: VerificationToken<TcStateAccepted>,
) -> Result<(), Self::Error>; ) -> Result<(), Self::Error>;
fn handle_error(
&self,
target_id: TargetId,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
error: Self::Error,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
);
} }
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
@ -465,19 +474,6 @@ pub mod alloc_mod {
) -> Result<(TargetId, Request), Self::Error>; ) -> Result<(TargetId, Request), Self::Error>;
} }
pub trait PusRoutingErrorHandler {
type Error;
fn handle_error(
&self,
target_id: TargetId,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
error: Self::Error,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
);
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DefaultActiveRequestMap<V>(pub HashMap<RequestId, V>); pub struct DefaultActiveRequestMap<V>(pub HashMap<RequestId, V>);
@ -704,10 +700,7 @@ pub mod std_mod {
pub use cb_mod::*; pub use cb_mod::*;
use super::verification::VerificationReportingProvider; use super::verification::VerificationReportingProvider;
use super::{ use super::{AcceptedEcssTcAndToken, PusRequestRouter, PusTcToRequestConverter, TcInMemory};
AcceptedEcssTcAndToken, PusRequestRouter, PusRoutingErrorHandler, PusTcToRequestConverter,
TcInMemory,
};
impl From<mpsc::SendError<StoreAddr>> for EcssTmtcError { impl From<mpsc::SendError<StoreAddr>> for EcssTmtcError {
fn from(_: mpsc::SendError<StoreAddr>) -> Self { fn from(_: mpsc::SendError<StoreAddr>) -> Self {
@ -999,7 +992,6 @@ pub mod std_mod {
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
RequestConverter: PusTcToRequestConverter<Request>, RequestConverter: PusTcToRequestConverter<Request>,
RequestRouter: PusRequestRouter<Request, Error = RoutingError>, RequestRouter: PusRequestRouter<Request, Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
Request, Request,
RoutingError = GenericRoutingError, RoutingError = GenericRoutingError,
> { > {
@ -1007,7 +999,7 @@ pub mod std_mod {
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>, PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub request_converter: RequestConverter, pub request_converter: RequestConverter,
pub request_router: RequestRouter, pub request_router: RequestRouter,
pub routing_error_handler: RoutingErrorHandler, // pub routing_error_handler: RoutingErrorHandler,
phantom: PhantomData<Request>, phantom: PhantomData<Request>,
} }
@ -1018,7 +1010,7 @@ pub mod std_mod {
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
RequestConverter: PusTcToRequestConverter<Request, Error = PusPacketHandlingError>, RequestConverter: PusTcToRequestConverter<Request, Error = PusPacketHandlingError>,
RequestRouter: PusRequestRouter<Request, Error = RoutingError>, RequestRouter: PusRequestRouter<Request, Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>, // RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
Request, Request,
RoutingError: Clone, RoutingError: Clone,
> >
@ -1029,7 +1021,7 @@ pub mod std_mod {
VerificationReporter, VerificationReporter,
RequestConverter, RequestConverter,
RequestRouter, RequestRouter,
RoutingErrorHandler, // RoutingErrorHandler,
Request, Request,
RoutingError, RoutingError,
> >
@ -1045,13 +1037,12 @@ pub mod std_mod {
>, >,
request_converter: RequestConverter, request_converter: RequestConverter,
request_router: RequestRouter, request_router: RequestRouter,
routing_error_handler: RoutingErrorHandler,
) -> Self { ) -> Self {
Self { Self {
service_helper, service_helper,
request_converter, request_converter,
request_router, request_router,
routing_error_handler, // routing_error_handler,
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -1079,7 +1070,7 @@ pub mod std_mod {
self.request_router self.request_router
.route(target_id, action_request, ecss_tc_and_token.token) .route(target_id, action_request, ecss_tc_and_token.token)
{ {
self.routing_error_handler.handle_error( self.request_router.handle_error(
target_id, target_id,
ecss_tc_and_token.token, ecss_tc_and_token.token,
&tc, &tc,
@ -1451,8 +1442,8 @@ pub mod tests {
}; };
use super::{ use super::{
EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericRoutingError, EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericRoutingError,
MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, PusRoutingErrorHandler, MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, PusServiceHelper,
PusServiceHelper, TcInMemory, TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TcInMemory, TmAsVecSenderWithId, TmAsVecSenderWithMpsc,
TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId,
}; };
@ -1766,44 +1757,9 @@ pub mod tests {
} }
} }
#[derive(Default)]
pub struct TestRoutingErrorHandler {
pub routing_errors: RefCell<VecDeque<(TargetId, GenericRoutingError)>>,
}
impl PusRoutingErrorHandler for TestRoutingErrorHandler {
type Error = GenericRoutingError;
fn handle_error(
&self,
target_id: TargetId,
_token: VerificationToken<TcStateAccepted>,
_tc: &PusTcReader,
error: Self::Error,
_time_stamp: &[u8],
_verif_reporter: &impl VerificationReportingProvider,
) {
self.routing_errors
.borrow_mut()
.push_back((target_id, error));
}
}
impl TestRoutingErrorHandler {
pub fn is_empty(&self) -> bool {
self.routing_errors.borrow().is_empty()
}
pub fn retrieve_next_error(&mut self) -> (TargetId, GenericRoutingError) {
if self.routing_errors.borrow().is_empty() {
panic!("no routing request available");
}
self.routing_errors.borrow_mut().pop_front().unwrap()
}
}
pub struct TestRouter<REQUEST> { pub struct TestRouter<REQUEST> {
pub routing_requests: RefCell<VecDeque<(TargetId, REQUEST)>>, pub routing_requests: RefCell<VecDeque<(TargetId, REQUEST)>>,
pub routing_errors: RefCell<VecDeque<(TargetId, GenericRoutingError)>>,
pub injected_routing_failure: RefCell<Option<GenericRoutingError>>, pub injected_routing_failure: RefCell<Option<GenericRoutingError>>,
} }
@ -1811,6 +1767,7 @@ pub mod tests {
fn default() -> Self { fn default() -> Self {
Self { Self {
routing_requests: Default::default(), routing_requests: Default::default(),
routing_errors: Default::default(),
injected_routing_failure: Default::default(), injected_routing_failure: Default::default(),
} }
} }
@ -1824,6 +1781,31 @@ pub mod tests {
Ok(()) Ok(())
} }
pub fn handle_error(
&self,
target_id: TargetId,
_token: VerificationToken<TcStateAccepted>,
_tc: &PusTcReader,
error: GenericRoutingError,
_time_stamp: &[u8],
_verif_reporter: &impl VerificationReportingProvider,
) {
self.routing_errors
.borrow_mut()
.push_back((target_id, error));
}
pub fn no_routing_errors(&self) -> bool {
self.routing_errors.borrow().is_empty()
}
pub fn retrieve_next_routing_error(&mut self) -> (TargetId, GenericRoutingError) {
if self.routing_errors.borrow().is_empty() {
panic!("no routing request available");
}
self.routing_errors.borrow_mut().pop_front().unwrap()
}
pub fn inject_routing_error(&mut self, error: GenericRoutingError) { pub fn inject_routing_error(&mut self, error: GenericRoutingError) {
*self.injected_routing_failure.borrow_mut() = Some(error); *self.injected_routing_failure.borrow_mut() = Some(error);
} }

View File

@ -2,7 +2,14 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{mode::ModeReply, request::GenericMessage}; use crate::mode::ModeReply;
#[cfg(feature = "alloc")]
#[allow(unused_imports)]
pub use alloc_mod::*;
#[cfg(feature = "std")]
pub use std_mod::*;
pub const MODE_SERVICE_ID: u8 = 200; pub const MODE_SERVICE_ID: u8 = 200;
@ -19,8 +26,6 @@ pub enum Subservice {
TmWrongModeReply = 8, TmWrongModeReply = 8,
} }
pub type GenericModeReplyPus = GenericMessage<ModeReply>;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub mod alloc_mod {} pub mod alloc_mod {}
@ -33,11 +38,12 @@ pub mod std_mod {
use satrs_shared::res_code::ResultU16; use satrs_shared::res_code::ResultU16;
use spacepackets::{ use spacepackets::{
ecss::tm::{PusTmCreator, PusTmSecondaryHeader}, ecss::tm::{PusTmCreator, PusTmSecondaryHeader},
util::UnsignedEnum,
SpHeader, SpHeader,
}; };
use crate::{ use crate::{
mode::{ModeReply, ModeRequest}, mode::{GenericModeReply, ModeRequest},
pus::{ pus::{
mode::Subservice, mode::Subservice,
verification::{ verification::{
@ -55,7 +61,7 @@ pub mod std_mod {
fn can_not_reach_mode_result_code(&self) -> ResultU16; fn can_not_reach_mode_result_code(&self) -> ResultU16;
} }
use super::{GenericModeReplyPus, MODE_SERVICE_ID}; use super::{ModeReply, MODE_SERVICE_ID};
pub type PusModeServiceRequestHandler< pub type PusModeServiceRequestHandler<
TcReceiver, TcReceiver,
@ -64,7 +70,6 @@ pub mod std_mod {
VerificationReporter, VerificationReporter,
RequestConverter, RequestConverter,
RequestRouter, RequestRouter,
RoutingErrorHandler,
RoutingError = GenericRoutingError, RoutingError = GenericRoutingError,
> = PusTargetedRequestHandler< > = PusTargetedRequestHandler<
TcReceiver, TcReceiver,
@ -73,7 +78,6 @@ pub mod std_mod {
VerificationReporter, VerificationReporter,
RequestConverter, RequestConverter,
RequestRouter, RequestRouter,
RoutingErrorHandler,
ModeRequest, ModeRequest,
RoutingError, RoutingError,
>; >;
@ -124,7 +128,7 @@ pub mod std_mod {
/// Main handler function to handle all received action replies. /// Main handler function to handle all received action replies.
pub fn handle_mode_reply( pub fn handle_mode_reply(
&mut self, &mut self,
mode_reply_with_id: &GenericModeReplyPus, mode_reply_with_id: &GenericModeReply,
time_stamp: &[u8], time_stamp: &[u8],
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
let active_req = self.active_request_map.get(mode_reply_with_id.request_id); let active_req = self.active_request_map.get(mode_reply_with_id.request_id);
@ -135,6 +139,7 @@ pub mod std_mod {
let active_req = active_req.unwrap().clone(); let active_req = active_req.unwrap().clone();
let remove_entry = match mode_reply_with_id.message { let remove_entry = match mode_reply_with_id.message {
ModeReply::ModeReply(reply) => { ModeReply::ModeReply(reply) => {
reply.write_to_be_bytes(&mut self.tm_buf)?;
let req_id = verification::RequestId::from(mode_reply_with_id.request_id); let req_id = verification::RequestId::from(mode_reply_with_id.request_id);
let mut sp_header = SpHeader::tm_unseg( let mut sp_header = SpHeader::tm_unseg(
req_id.packet_id().apid(), req_id.packet_id().apid(),
@ -149,16 +154,15 @@ pub mod std_mod {
0, 0,
Some(time_stamp), Some(time_stamp),
); );
let pus_tm = let pus_tm = PusTmCreator::new(&mut sp_header, sec_header, &self.tm_buf, true);
PusTmCreator::new(&mut sp_header, sec_header, &mut self.tm_buf, true);
self.tm_sender.send_tm(PusTmWrapper::Direct(pus_tm))?; self.tm_sender.send_tm(PusTmWrapper::Direct(pus_tm))?;
self.verification_reporter self.verification_reporter
.completion_success(active_req.token, time_stamp) .completion_success(active_req.token, time_stamp)
.map_err(|e| e.0)?; .map_err(|e| e.0)?;
true true
} }
ModeReply::CantReachMode(reached_mode) => { ModeReply::CantReachMode(reason) => {
let fail_data_len = reached_mode.to_be_bytes(&mut self.tm_buf)?; let fail_data_len = reason.write_to_be_bytes(&mut self.tm_buf)?;
self.verification_reporter self.verification_reporter
.completion_failure( .completion_failure(
active_req.token, active_req.token,
@ -172,9 +176,19 @@ pub mod std_mod {
true true
} }
ModeReply::WrongMode { expected, reached } => { ModeReply::WrongMode { expected, reached } => {
// TODO: Generate completion failure with appropriate result code and reached let expected_len = expected.write_to_be_bytes(&mut self.tm_buf)?;
// mode as context information. let reached_len =
// self.verification_reporter.completion_success(active_req.token, time_stamp); reached.write_to_be_bytes(&mut self.tm_buf[expected_len..])?;
self.verification_reporter
.completion_failure(
active_req.token,
FailParams::new(
time_stamp,
&self.user_hook.can_not_reach_mode_result_code(),
&self.tm_buf[0..expected_len + reached_len],
),
)
.map_err(|e| e.0)?;
true true
} }
_ => true, _ => true,
@ -187,3 +201,122 @@ pub mod std_mod {
} }
} }
} }
#[cfg(test)]
mod tests {
use std::sync::mpsc;
use crate::{
mode::{
ModeAndSubmode, ModeReplySender, ModeRequest, ModeRequestSender,
ModeRequestorAndHandlerMpsc, ModeRequestorMpsc,
},
pus::mode::ModeReply,
request::GenericMessage,
};
const TEST_CHANNEL_ID_0: u32 = 5;
const TEST_CHANNEL_ID_1: u32 = 6;
const TEST_CHANNEL_ID_2: u32 = 7;
#[test]
fn test_simple_mode_requestor() {
let (reply_sender, reply_receiver) = mpsc::channel();
let (request_sender, request_receiver) = mpsc::channel();
let mut mode_requestor = ModeRequestorMpsc::new(TEST_CHANNEL_ID_0, reply_receiver);
mode_requestor.add_message_target(TEST_CHANNEL_ID_1, request_sender);
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_request = ModeRequest::ReadMode;
mode_requestor
.send_mode_request(request_id, TEST_CHANNEL_ID_1, sent_request)
.expect("send failed");
let request = request_receiver.recv().expect("recv failed");
assert_eq!(request.request_id, 2);
assert_eq!(request.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(request.message, sent_request);
// Send a reply and verify it arrives at the requestor.
let mode_reply = ModeReply::ModeReply(ModeAndSubmode::new(1, 5));
reply_sender
.send(GenericMessage::new(
request_id,
TEST_CHANNEL_ID_1,
mode_reply,
))
.expect("send failed");
let reply = mode_requestor.try_recv_mode_reply().expect("recv failed");
assert!(reply.is_some());
let reply = reply.unwrap();
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_1);
assert_eq!(reply.request_id, 2);
assert_eq!(reply.message, mode_reply);
}
#[test]
fn test_mode_requestor_and_request_handler_request_sending() {
let (_reply_sender_to_connector, reply_receiver_of_connector) = mpsc::channel();
let (_request_sender_to_connector, request_receiver_of_connector) = mpsc::channel();
let (request_sender_to_channel_1, request_receiver_channel_1) = mpsc::channel();
//let (reply_sender_to_channel_2, reply_receiver_channel_2) = mpsc::channel();
let mut mode_connector = ModeRequestorAndHandlerMpsc::new(
TEST_CHANNEL_ID_0,
request_receiver_of_connector,
reply_receiver_of_connector,
);
assert_eq!(
ModeRequestSender::local_channel_id(&mode_connector),
TEST_CHANNEL_ID_0
);
assert_eq!(
ModeReplySender::local_channel_id(&mode_connector),
TEST_CHANNEL_ID_0
);
assert_eq!(mode_connector.local_channel_id_generic(), TEST_CHANNEL_ID_0);
mode_connector.add_request_target(TEST_CHANNEL_ID_1, request_sender_to_channel_1);
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_request = ModeRequest::ReadMode;
mode_connector
.send_mode_request(request_id, TEST_CHANNEL_ID_1, sent_request)
.expect("send failed");
let request = request_receiver_channel_1.recv().expect("recv failed");
assert_eq!(request.request_id, 2);
assert_eq!(request.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(request.message, ModeRequest::ReadMode);
}
#[test]
fn test_mode_requestor_and_request_handler_reply_sending() {
let (_reply_sender_to_connector, reply_receiver_of_connector) = mpsc::channel();
let (_request_sender_to_connector, request_receiver_of_connector) = mpsc::channel();
let (reply_sender_to_channel_2, reply_receiver_channel_2) = mpsc::channel();
let mut mode_connector = ModeRequestorAndHandlerMpsc::new(
TEST_CHANNEL_ID_0,
request_receiver_of_connector,
reply_receiver_of_connector,
);
mode_connector.add_reply_target(TEST_CHANNEL_ID_2, reply_sender_to_channel_2);
// Send a request and verify it arrives at the receiver.
let request_id = 2;
let sent_reply = ModeReply::ModeInfo(ModeAndSubmode::new(3, 5));
mode_connector
.send_mode_reply(request_id, TEST_CHANNEL_ID_2, sent_reply)
.expect("send failed");
let reply = reply_receiver_channel_2.recv().expect("recv failed");
assert_eq!(reply.request_id, 2);
assert_eq!(reply.sender_id, TEST_CHANNEL_ID_0);
assert_eq!(reply.message, sent_reply);
}
#[test]
fn test_mode_reply_handler() {}
}