diff --git a/satrs-example/src/pus/action.rs b/satrs-example/src/pus/action.rs index 3802091..f5b779f 100644 --- a/satrs-example/src/pus/action.rs +++ b/satrs-example/src/pus/action.rs @@ -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 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, diff --git a/satrs-example/src/requests.rs b/satrs-example/src/requests.rs index 6703d93..0c27b9e 100644 --- a/satrs-example/src/requests.rs +++ b/satrs-example/src/requests.rs @@ -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 for GenericRequestRouter { type Error = GenericRoutingError; fn route( diff --git a/satrs/src/pus/action.rs b/satrs/src/pus/action.rs index ac74239..ea2f896 100644 --- a/satrs/src/pus/action.rs +++ b/satrs/src/pus/action.rs @@ -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, - ) -> 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, - 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,123 +93,38 @@ 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, - RoutingErrorHandler: PusRoutingErrorHandler, + pub type PusService8ActionRequestHandler< + TcReceiver, + TmSender, + TcInMemConverter, + VerificationReporter, + RequestConverter, + RequestRouter, + RoutingErrorHandler, RoutingError = GenericRoutingError, - > { - service_helper: - PusServiceHelper, - pub request_converter: RequestConverter, - pub request_router: RequestRouter, - pub routing_error_handler: RoutingErrorHandler, - } - - impl< - TcReceiver: EcssTcReceiverCore, - TmSender: EcssTmSenderCore, - TcInMemConverter: EcssTcInMemConverter, - VerificationReporter: VerificationReportingProvider, - RequestConverter: PusActionToRequestConverter, - RequestRouter: PusActionRequestRouter, - RoutingErrorHandler: PusRoutingErrorHandler, - RoutingError: Clone, - > - PusService8ActionHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - RoutingErrorHandler, - RoutingError, - > - where - PusPacketHandlingError: From, - { - 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, - } - } - - /// Core function to poll the next TC packet and try to handle it. - pub fn handle_one_tc(&mut self) -> Result { - 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) - } - } + > = PusTargetedRequestHandler< + TcReceiver, + TmSender, + TcInMemConverter, + VerificationReporter, + RequestConverter, + RequestRouter, + RoutingErrorHandler, + ActionRequest, + RoutingError, + >; pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap; /// 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 = + pub type PusService8ReplyHandler = PusServiceReplyHandler< VerificationReporter, ActiveRequestMap, UserHook, + TmSender, ActiveActionRequest, ActionReplyPusWithIds, >; @@ -266,7 +133,8 @@ pub mod std_mod { VerificationReporter: VerificationReportingProvider, ActiveRequestMap: ActiveRequestMapProvider, UserHook: ReplyHandlerHook, - > PusService8ReplyHandler + TmSender: EcssTmSenderCore, + > PusService8ReplyHandler { /// 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, - > PusService8ReplyHandler + 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 { 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 { + impl PusRequestRouter for TestRouter { type Error = GenericRoutingError; fn route( &self, target_id: TargetId, - action_request: ActionRequest, + request: Request, _token: VerificationToken, ) -> 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 for TestConverter<8> { type Error = PusPacketHandlingError; fn convert( &mut self, @@ -508,7 +388,7 @@ mod tests { struct Pus8RequestTestbenchWithVec { common: PusServiceHandlerWithVecCommon, - 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>, handler: PusService8ReplyHandler< TestVerificationReporter, DefaultActiveActionRequestMap, TestReplyHandlerHook, + mpsc::Sender>, >, } @@ -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, } } diff --git a/satrs/src/pus/mod.rs b/satrs/src/pus/mod.rs index ffb9008..87189a4 100644 --- a/satrs/src/pus/mod.rs +++ b/satrs/src/pus/mod.rs @@ -337,6 +337,18 @@ pub trait ReplyHandlerHook { 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 { + type Error; + fn route( + &self, + target_id: TargetId, + hk_request: Request, + token: VerificationToken, + ) -> 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 { + type Error; + fn convert( + &mut self, + token: VerificationToken, + 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, UserHook: ReplyHandlerHook, + TmSender: EcssTmSenderCore, ActiveRequestType: ActiveRequestProvider, ReplyType, > { @@ -508,6 +547,7 @@ pub mod alloc_mod { pub fail_data_buf: alloc::vec::Vec, 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, UserHook: ReplyHandlerHook, + 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 { 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> for EcssTmtcError { fn from(_: mpsc::SendError) -> 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, + RequestRouter: PusRequestRouter, + RoutingErrorHandler: PusRoutingErrorHandler, + Request, + RoutingError = GenericRoutingError, + > { + service_helper: + PusServiceHelper, + pub request_converter: RequestConverter, + pub request_router: RequestRouter, + pub routing_error_handler: RoutingErrorHandler, + phantom: PhantomData, + } + + impl< + TcReceiver: EcssTcReceiverCore, + TmSender: EcssTmSenderCore, + TcInMemConverter: EcssTcInMemConverter, + VerificationReporter: VerificationReportingProvider, + RequestConverter: PusTcToRequestConverter, + RequestRouter: PusRequestRouter, + RoutingErrorHandler: PusRoutingErrorHandler, + Request, + RoutingError: Clone, + > + PusTargetedRequestHandler< + TcReceiver, + TmSender, + TcInMemConverter, + VerificationReporter, + RequestConverter, + RequestRouter, + RoutingErrorHandler, + Request, + RoutingError, + > + where + PusPacketHandlingError: From, + { + 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 { + 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 . diff --git a/satrs/src/pus/mode.rs b/satrs/src/pus/mode.rs index 1ab46ef..4835d5f 100644 --- a/satrs/src/pus/mode.rs +++ b/satrs/src/pus/mode.rs @@ -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, + ) -> 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, + tc: &PusTcReader, + time_stamp: &[u8], + verif_reporter: &impl VerificationReportingProvider, + ) -> Result<(TargetId, ModeRequest), Self::Error>; + } +} diff --git a/satrs/tests/mode_tree.rs b/satrs/tests/mode_tree.rs index 16c5e37..60f8178 100644 --- a/satrs/tests/mode_tree.rs +++ b/satrs/tests/mode_tree.rs @@ -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");