made request handler more generic
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good

This commit is contained in:
Robin Müller 2024-03-13 16:06:12 +01:00
parent 41e57a7942
commit 8bdc9686fb
Signed by: muellerr
GPG Key ID: A649FB78196E3849
6 changed files with 290 additions and 188 deletions

View File

@ -1,18 +1,16 @@
use log::{error, warn};
use satrs::action::{ActionRequest, ActionRequestVariant};
use satrs::pool::{SharedStaticMemoryPool, StoreAddr};
use satrs::pus::action::{PusActionToRequestConverter, PusService8ActionHandler};
use satrs::pus::verification::std_mod::{
VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender,
};
use satrs::pus::action::PusService8ActionRequestHandler;
use satrs::pus::verification::{
FailParams, TcStateAccepted, VerificationReportingProvider, VerificationToken,
FailParams, TcStateAccepted, VerificationReporterWithSharedPoolMpscBoundedSender,
VerificationReporterWithVecMpscSender, VerificationReportingProvider, VerificationToken,
};
use satrs::pus::{
EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter,
EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult,
PusPacketHandlingError, PusServiceHelper, TmAsVecSenderWithId, TmAsVecSenderWithMpsc,
TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId,
PusPacketHandlingError, PusServiceHelper, PusTcToRequestConverter, TmAsVecSenderWithId,
TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId,
};
use satrs::request::TargetAndApidId;
use satrs::spacepackets::ecss::tc::PusTcReader;
@ -29,7 +27,7 @@ use super::GenericRoutingErrorHandler;
#[derive(Default)]
pub struct ExampleActionRequestConverter {}
impl PusActionToRequestConverter for ExampleActionRequestConverter {
impl PusTcToRequestConverter<ActionRequest> for ExampleActionRequestConverter {
type Error = PusPacketHandlingError;
fn convert(
@ -99,7 +97,7 @@ pub fn create_action_service_static(
"PUS_8_TC_RECV",
pus_action_rx,
);
let pus_8_handler = PusService8ActionHandler::new(
let pus_8_handler = PusService8ActionRequestHandler::new(
PusServiceHelper::new(
action_srv_receiver,
action_srv_tm_sender,
@ -135,7 +133,7 @@ pub fn create_action_service_dynamic(
"PUS_8_TC_RECV",
pus_action_rx,
);
let pus_8_handler = PusService8ActionHandler::new(
let pus_8_handler = PusService8ActionRequestHandler::new(
PusServiceHelper::new(
action_srv_receiver,
action_srv_tm_sender,
@ -156,7 +154,7 @@ pub struct Pus8Wrapper<
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
> {
pub(crate) pus_8_handler: PusService8ActionHandler<
pub(crate) pus_8_handler: PusService8ActionRequestHandler<
TcReceiver,
TmSender,
TcInMemConverter,

View File

@ -5,10 +5,9 @@ use derive_new::new;
use satrs::action::ActionRequest;
use satrs::hk::HkRequest;
use satrs::mode::ModeRequest;
use satrs::pus::action::PusActionRequestRouter;
use satrs::pus::hk::PusHkRequestRouter;
use satrs::pus::verification::{TcStateAccepted, VerificationToken};
use satrs::pus::GenericRoutingError;
use satrs::pus::{GenericRoutingError, PusRequestRouter};
use satrs::queue::GenericSendError;
use satrs::TargetId;
@ -71,7 +70,7 @@ impl PusHkRequestRouter for GenericRequestRouter {
}
}
impl PusActionRequestRouter for GenericRequestRouter {
impl PusRequestRouter<ActionRequest> for GenericRequestRouter {
type Error = GenericRoutingError;
fn route(

View File

@ -5,10 +5,7 @@ use crate::{
TargetId,
};
use super::{
verification::{TcStateAccepted, VerificationToken},
ActiveRequest, ActiveRequestProvider,
};
use super::{verification::VerificationToken, ActiveRequest, ActiveRequestProvider};
use delegate::delegate;
use satrs_shared::res_code::ResultU16;
@ -20,6 +17,7 @@ pub use std_mod::*;
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[allow(unused_imports)]
pub use alloc_mod::*;
#[derive(Clone, Debug)]
@ -54,18 +52,6 @@ pub enum ActionReplyPus {
},
}
/// This trait is an abstraction for the routing of PUS service 8 action requests to a dedicated
/// recipient using the generic [TargetId].
pub trait PusActionRequestRouter {
type Error;
fn route(
&self,
target_id: TargetId,
hk_request: ActionRequest,
token: VerificationToken<TcStateAccepted>,
) -> Result<(), Self::Error>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ActiveActionRequest {
pub action_id: ActionId,
@ -85,39 +71,7 @@ impl ActiveRequestProvider for ActiveActionRequest {
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
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
/// an [ActionRequest].
///
/// Having a dedicated trait for this allows maximum flexiblity and tailoring of the standard.
/// The only requirement is that a valid [TargetId] and an [ActionRequest] 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] instance is passed to the user to also allow handling
/// of the verification process as part of the PUS standard requirements.
pub trait PusActionToRequestConverter {
type Error;
fn convert(
&mut self,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) -> Result<(TargetId, ActionRequest), Self::Error>;
}
}
pub mod alloc_mod {}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
@ -125,14 +79,12 @@ pub mod std_mod {
use crate::{
params::WritableToBeBytes,
pus::{
get_current_cds_short_timestamp,
verification::{
self, FailParams, FailParamsWithStep, TcStateStarted, VerificationReportingProvider,
},
ActiveRequestMapProvider, DefaultActiveRequestMap, EcssTcInMemConverter,
EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, GenericRoutingError,
PusPacketHandlerResult, PusPacketHandlingError, PusRoutingErrorHandler,
PusServiceHelper, PusServiceReplyHandler, ReplyHandlerHook,
ActiveRequestMapProvider, DefaultActiveRequestMap, EcssTmSenderCore, EcssTmtcError,
GenericRoutingError, PusServiceReplyHandler, PusTargetedRequestHandler,
ReplyHandlerHook,
},
};
use core::time::Duration;
@ -141,45 +93,7 @@ pub mod std_mod {
use super::*;
/// This is a high-level handler for the PUS service 8 action service.
///
/// 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
/// [PusActionToRequestConverter]. The generic error type is constrained to the
/// [PusPacketHandlingError] for the concrete implementation which offers a packet handler.
/// 3. Route the action request using the provided [PusActionRequestRouter].
/// 4. Handle all routing errors using the provided [PusRoutingErrorHandler].
pub struct PusService8ActionHandler<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
RequestConverter: PusActionToRequestConverter,
RequestRouter: PusActionRequestRouter<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: PusActionToRequestConverter<Error = PusPacketHandlingError>,
RequestRouter: PusActionRequestRouter<Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
RoutingError: Clone,
>
PusService8ActionHandler<
pub type PusService8ActionRequestHandler<
TcReceiver,
TmSender,
TcInMemConverter,
@ -187,77 +101,30 @@ pub mod std_mod {
RequestConverter,
RequestRouter,
RoutingErrorHandler,
RoutingError,
>
where
PusPacketHandlingError: From<RoutingError>,
{
pub fn new(
service_helper: PusServiceHelper<
RoutingError = GenericRoutingError,
> = PusTargetedRequestHandler<
TcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
>,
request_converter: RequestConverter,
request_router: RequestRouter,
routing_error_handler: RoutingErrorHandler,
) -> Self {
Self {
service_helper,
request_converter,
request_router,
routing_error_handler,
}
}
/// Core function to poll the next TC packet and try to handle it.
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, action_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, action_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)
}
}
RequestConverter,
RequestRouter,
RoutingErrorHandler,
ActionRequest,
RoutingError,
>;
pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap<ActiveActionRequest>;
/// Type definition for a PUS 8 action service reply handler which constrains the
/// [PusServiceReplyHandler] active request and reply generics to the [ActiveActionRequest] and
/// [ActionReplyPusWithIds] type.
pub type PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook> =
pub type PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook, TmSender> =
PusServiceReplyHandler<
VerificationReporter,
ActiveRequestMap,
UserHook,
TmSender,
ActiveActionRequest,
ActionReplyPusWithIds,
>;
@ -266,7 +133,8 @@ pub mod std_mod {
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveActionRequest>,
UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>,
> PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook>
TmSender: EcssTmSenderCore,
> PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook, TmSender>
{
/// Helper method to register a recently routed action request.
pub fn add_routed_action_request(
@ -366,7 +234,14 @@ pub mod std_mod {
impl<
VerificationReporter: VerificationReportingProvider,
UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>,
> PusService8ReplyHandler<VerificationReporter, DefaultActiveActionRequestMap, UserHook>
TmSender: EcssTmSenderCore,
>
PusService8ReplyHandler<
VerificationReporter,
DefaultActiveActionRequestMap,
UserHook,
TmSender,
>
{
/// Create a new PUS Service 8 reply handler with the [ActiveRequestMap] generic
/// constrained to the [DefaultActiveActionRequestMap] object and with the current time
@ -377,12 +252,14 @@ pub mod std_mod {
verification_reporter: VerificationReporter,
fail_data_buf_size: usize,
user_hook: UserHook,
tm_sender: TmSender,
) -> Result<Self, SystemTimeError> {
let current_time = UnixTimestamp::from_now()?;
Ok(Self::new_with_default_map(
verification_reporter,
fail_data_buf_size,
user_hook,
tm_sender,
current_time,
))
}
@ -393,6 +270,7 @@ pub mod std_mod {
verification_reporter: VerificationReporter,
fail_data_buf_size: usize,
user_hook: UserHook,
tm_sender: TmSender,
init_time: UnixTimestamp,
) -> Self {
Self::new(
@ -400,6 +278,7 @@ pub mod std_mod {
DefaultActiveActionRequestMap::default(),
fail_data_buf_size,
user_hook,
tm_sender,
init_time,
)
}
@ -409,9 +288,9 @@ pub mod std_mod {
#[cfg(test)]
mod tests {
use core::{cell::RefCell, time::Duration};
use std::time::SystemTimeError;
use std::{sync::mpsc, time::SystemTimeError};
use alloc::collections::VecDeque;
use alloc::{collections::VecDeque, vec::Vec};
use delegate::delegate;
use spacepackets::{
@ -434,33 +313,34 @@ mod tests {
verification::{
self,
tests::{SharedVerificationMap, TestVerificationReporter, VerificationStatus},
FailParams, TcStateNone, TcStateStarted, VerificationReportingProvider,
FailParams, TcStateAccepted, TcStateNone, TcStateStarted,
VerificationReportingProvider,
},
EcssTcInVecConverter, EcssTmtcError, GenericRoutingError, MpscTcReceiver,
PusPacketHandlerResult, PusPacketHandlingError, ReplyHandlerHook,
TmAsVecSenderWithMpsc,
PusPacketHandlerResult, PusPacketHandlingError, PusRequestRouter,
PusTcToRequestConverter, ReplyHandlerHook, TmAsVecSenderWithMpsc,
},
};
use super::*;
impl PusActionRequestRouter for TestRouter<ActionRequest> {
impl<Request> PusRequestRouter<Request> for TestRouter<Request> {
type Error = GenericRoutingError;
fn route(
&self,
target_id: TargetId,
action_request: ActionRequest,
request: Request,
_token: VerificationToken<TcStateAccepted>,
) -> Result<(), Self::Error> {
self.routing_requests
.borrow_mut()
.push_back((target_id, action_request));
.push_back((target_id, request));
self.check_for_injected_error()
}
}
impl PusActionToRequestConverter for TestConverter<8> {
impl PusTcToRequestConverter<ActionRequest> for TestConverter<8> {
type Error = PusPacketHandlingError;
fn convert(
&mut self,
@ -508,7 +388,7 @@ mod tests {
struct Pus8RequestTestbenchWithVec {
common: PusServiceHandlerWithVecCommon<TestVerificationReporter>,
handler: PusService8ActionHandler<
handler: PusService8ActionRequestHandler<
MpscTcReceiver,
TmAsVecSenderWithMpsc,
EcssTcInVecConverter,
@ -525,7 +405,7 @@ mod tests {
PusServiceHandlerWithVecCommon::new_with_test_verif_sender();
Self {
common,
handler: PusService8ActionHandler::new(
handler: PusService8ActionRequestHandler::new(
srv_handler,
TestConverter::default(),
TestRouter::default(),
@ -599,10 +479,13 @@ mod tests {
pub struct Pus8ReplyTestbench {
verif_reporter: TestVerificationReporter,
#[allow(dead_code)]
ecss_tm_receiver: mpsc::Receiver<Vec<u8>>,
handler: PusService8ReplyHandler<
TestVerificationReporter,
DefaultActiveActionRequestMap,
TestReplyHandlerHook,
mpsc::Sender<Vec<u8>>,
>,
}
@ -611,11 +494,13 @@ mod tests {
let reply_handler_hook = TestReplyHandlerHook::default();
let shared_verif_map = SharedVerificationMap::default();
let test_verif_reporter = TestVerificationReporter::new(shared_verif_map.clone());
let (ecss_tm_sender, ecss_tm_receiver) = mpsc::channel();
let reply_handler = if normal_ctor {
PusService8ReplyHandler::new_from_now_with_default_map(
test_verif_reporter.clone(),
128,
reply_handler_hook,
ecss_tm_sender,
)
.expect("creating reply handler failed")
} else {
@ -624,11 +509,13 @@ mod tests {
DefaultActiveActionRequestMap::default(),
128,
reply_handler_hook,
ecss_tm_sender,
)
.expect("creating reply handler failed")
};
Self {
verif_reporter: test_verif_reporter,
ecss_tm_receiver,
handler: reply_handler,
}
}

View File

@ -337,6 +337,18 @@ pub trait ReplyHandlerHook<ActiveRequestType, ReplyType> {
fn timeout_error_code(&self) -> ResultU16;
}
/// This trait is an abstraction for the routing of PUS request to a dedicated
/// recipient using the generic [TargetId].
pub trait PusRequestRouter<Request> {
type Error;
fn route(
&self,
target_id: TargetId,
hk_request: Request,
token: VerificationToken<TcStateAccepted>,
) -> Result<(), Self::Error>;
}
#[cfg(feature = "alloc")]
pub mod alloc_mod {
use hashbrown::HashMap;
@ -427,6 +439,32 @@ pub mod alloc_mod {
impl_downcast!(EcssTcReceiver);
/// This trait is an abstraction for the conversion of a PUS telecommand into a generic request
/// type.
///
/// Having a dedicated trait for this allows maximum flexiblity and tailoring of the standard.
/// The only requirement is that a valid [TargetId] and a request instance 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] instance is passed to the user to also allow handling
/// of the verification process as part of the PUS standard requirements.
pub trait PusTcToRequestConverter<Request> {
type Error;
fn convert(
&mut self,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) -> Result<(TargetId, Request), Self::Error>;
}
pub trait PusRoutingErrorHandler {
type Error;
fn handle_error(
@ -500,6 +538,7 @@ pub mod alloc_mod {
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
TmSender: EcssTmSenderCore,
ActiveRequestType: ActiveRequestProvider,
ReplyType,
> {
@ -508,6 +547,7 @@ pub mod alloc_mod {
pub fail_data_buf: alloc::vec::Vec<u8>,
pub current_time: UnixTimestamp,
pub user_hook: UserHook,
pub tm_sender: TmSender,
phantom: PhantomData<(ActiveRequestType, ReplyType)>,
}
@ -515,6 +555,7 @@ pub mod alloc_mod {
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
TmSender: EcssTmSenderCore,
ActiveRequestType: ActiveRequestProvider,
ReplyType,
>
@ -522,6 +563,7 @@ pub mod alloc_mod {
VerificationReporter,
ActiveRequestMap,
UserHook,
TmSender,
ActiveRequestType,
ReplyType,
>
@ -533,6 +575,7 @@ pub mod alloc_mod {
active_request_map: ActiveRequestMap,
fail_data_buf_size: usize,
user_hook: UserHook,
tm_sender: TmSender,
) -> Result<Self, std::time::SystemTimeError> {
let current_time = UnixTimestamp::from_now()?;
Ok(Self::new(
@ -540,6 +583,7 @@ pub mod alloc_mod {
active_request_map,
fail_data_buf_size,
user_hook,
tm_sender,
current_time,
))
}
@ -549,6 +593,7 @@ pub mod alloc_mod {
active_request_map: ActiveRequestMap,
fail_data_buf_size: usize,
user_hook: UserHook,
tm_sender: TmSender,
init_time: UnixTimestamp,
) -> Self {
Self {
@ -557,6 +602,7 @@ pub mod alloc_mod {
fail_data_buf: alloc::vec![0; fail_data_buf_size],
current_time: init_time,
user_hook,
tm_sender,
phantom: PhantomData,
}
}
@ -642,6 +688,7 @@ pub mod std_mod {
use crate::tmtc::tm_helper::SharedTmPool;
use crate::{ChannelId, TargetId};
use alloc::vec::Vec;
use core::marker::PhantomData;
use spacepackets::ecss::tc::PusTcReader;
use spacepackets::ecss::tm::PusTmCreator;
use spacepackets::ecss::{PusError, WritablePusPacket};
@ -657,7 +704,10 @@ pub mod std_mod {
pub use cb_mod::*;
use super::verification::VerificationReportingProvider;
use super::{AcceptedEcssTcAndToken, TcInMemory};
use super::{
AcceptedEcssTcAndToken, PusRequestRouter, PusRoutingErrorHandler, PusTcToRequestConverter,
TcInMemory,
};
impl From<mpsc::SendError<StoreAddr>> for EcssTmtcError {
fn from(_: mpsc::SendError<StoreAddr>) -> Self {
@ -931,6 +981,118 @@ pub mod std_mod {
}
}
/// This is a high-level handler for the PUS service 8 action service.
///
/// 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
/// [PusActionToRequestConverter]. The generic error type is constrained to the
/// [PusPacketHandlingError] for the concrete implementation which offers a packet handler.
/// 3. Route the action request using the provided [PusActionRequestRouter].
/// 4. Handle all routing errors using the provided [PusRoutingErrorHandler].
pub struct PusTargetedRequestHandler<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
RequestConverter: PusTcToRequestConverter<Request>,
RequestRouter: PusRequestRouter<Request, Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
Request,
RoutingError = GenericRoutingError,
> {
service_helper:
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
pub request_converter: RequestConverter,
pub request_router: RequestRouter,
pub routing_error_handler: RoutingErrorHandler,
phantom: PhantomData<Request>,
}
impl<
TcReceiver: EcssTcReceiverCore,
TmSender: EcssTmSenderCore,
TcInMemConverter: EcssTcInMemConverter,
VerificationReporter: VerificationReportingProvider,
RequestConverter: PusTcToRequestConverter<Request, Error = PusPacketHandlingError>,
RequestRouter: PusRequestRouter<Request, Error = RoutingError>,
RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
Request,
RoutingError: Clone,
>
PusTargetedRequestHandler<
TcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
RequestConverter,
RequestRouter,
RoutingErrorHandler,
Request,
RoutingError,
>
where
PusPacketHandlingError: From<RoutingError>,
{
pub fn new(
service_helper: PusServiceHelper<
TcReceiver,
TmSender,
TcInMemConverter,
VerificationReporter,
>,
request_converter: RequestConverter,
request_router: RequestRouter,
routing_error_handler: RoutingErrorHandler,
) -> Self {
Self {
service_helper,
request_converter,
request_router,
routing_error_handler,
phantom: PhantomData,
}
}
/// Core function to poll the next TC packet and try to handle it.
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, action_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, action_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)
}
}
// TODO: All these types could probably be no_std if we implemented error handling ourselves..
// but thiserror is really nice, so keep it like this for simplicity for now. Maybe thiserror
// will be no_std soon, see https://github.com/rust-lang/rust/issues/103765 .

View File

@ -2,6 +2,10 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::{mode::ModeRequest, TargetId};
use super::verification::{TcStateAccepted, VerificationToken};
#[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)]
@ -14,3 +18,51 @@ pub enum Subservice {
TmCantReachMode = 7,
TmWrongModeReply = 8,
}
/// This trait is an abstraction for the routing of PUS service 8 action requests to a dedicated
/// recipient using the generic [TargetId].
pub trait PusModeRequestRouter {
type Error;
fn route(
&self,
target_id: TargetId,
mode_request: ModeRequest,
token: VerificationToken<TcStateAccepted>,
) -> Result<(), Self::Error>;
}
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
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 mode service telecommand into
/// an [ModeRequest].
///
/// Having a dedicated trait for this allows maximum flexiblity and tailoring of the standard.
/// The only requirement is that a valid [TargetId] and an [ActionRequest] 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] instance is passed to the user to also allow handling
/// of the verification process as part of the PUS standard requirements.
pub trait PusModeToRequestConverter {
type Error;
fn convert(
&mut self,
token: VerificationToken<TcStateAccepted>,
tc: &PusTcReader,
time_stamp: &[u8],
verif_reporter: &impl VerificationReportingProvider,
) -> Result<(TargetId, ModeRequest), Self::Error>;
}
}

View File

@ -48,6 +48,10 @@ struct TestDevice {
pub mode_requestor_info: Option<(RequestId, ChannelId)>,
}
pub struct ModeLeafDeviceHelper {
// pub
}
impl TestDevice {
pub fn run(&mut self) {
self.check_mode_requests().expect("mode messaging error");