From 0f2a700ef1e2b63ad3c390735ad23d13f62120d6 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 18 Mar 2024 19:57:37 +0100 Subject: [PATCH] need to re-work all of this.. --- satrs-example/src/config.rs | 2 + satrs-example/src/pus/action.rs | 85 +++++---- satrs-example/src/pus/event.rs | 4 +- satrs-example/src/pus/mod.rs | 145 +++++++++++++- satrs-example/src/pus/scheduler.rs | 7 +- satrs-example/src/pus/stack.rs | 19 +- satrs-example/src/pus/test.rs | 4 +- satrs/src/cfdp/dest.rs | 17 +- satrs/src/cfdp/mod.rs | 29 ++- satrs/src/lib.rs | 1 + satrs/src/pus/action.rs | 163 ++++++---------- satrs/src/pus/event_srv.rs | 28 ++- satrs/src/pus/hk.rs | 280 ---------------------------- satrs/src/pus/mod.rs | 126 +++++-------- satrs/src/pus/mode.rs | 34 +--- satrs/src/pus/scheduler_srv.rs | 46 +++-- satrs/src/pus/test.rs | 34 ++-- satrs/src/time.rs | 7 + satrs/tests/pus_targeted_request.rs | 148 +++++++++++++++ 19 files changed, 561 insertions(+), 618 deletions(-) delete mode 100644 satrs/src/pus/hk.rs create mode 100644 satrs/src/time.rs create mode 100644 satrs/tests/pus_targeted_request.rs diff --git a/satrs-example/src/config.rs b/satrs-example/src/config.rs index 9d04403..dda4105 100644 --- a/satrs-example/src/config.rs +++ b/satrs-example/src/config.rs @@ -53,6 +53,8 @@ pub mod tmtc_err { pub const UNKNOWN_TARGET_ID: ResultU16 = ResultU16::new(GroupId::Tmtc as u8, 4); #[resultcode] pub const ROUTING_ERROR: ResultU16 = ResultU16::new(GroupId::Tmtc as u8, 5); + #[resultcode(info = "Request timeout for targeted PUS request. P1: Request ID. P2: Target ID")] + pub const REQUEST_TIMEOUT: ResultU16 = ResultU16::new(GroupId::Tmtc as u8, 6); #[resultcode( info = "Not enough data inside the TC application data field. Optionally includes: \ diff --git a/satrs-example/src/pus/action.rs b/satrs-example/src/pus/action.rs index 66c2918..282b033 100644 --- a/satrs-example/src/pus/action.rs +++ b/satrs-example/src/pus/action.rs @@ -2,8 +2,8 @@ use log::{error, warn}; use satrs::action::{ActionRequest, ActionRequestVariant}; use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pus::action::{ - ActionReplyPusWithActionId, ActiveActionRequest, DefaultActiveActionRequestMap, - PusService8ActionRequestHandler, PusService8ReplyHandler, + ActionReplyPus, ActionReplyPusWithActionId, ActiveActionRequest, DefaultActiveActionRequestMap, + PusService8ReplyHandler, }; use satrs::pus::verification::{ FailParams, TcStateAccepted, VerificationReporterWithSharedPoolMpscBoundedSender, @@ -12,20 +12,56 @@ use satrs::pus::verification::{ use satrs::pus::{ EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, - PusPacketHandlingError, PusServiceHelper, PusTcToRequestConverter, ReplyHandlerHook, - TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, - TmInSharedPoolSenderWithId, + PusPacketHandlingError, PusReplyHandler, PusServiceHelper, PusTcToRequestConverter, + ReplyHandlerHook, TmAsVecSenderWithId, TmAsVecSenderWithMpsc, + TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId, }; use satrs::request::TargetAndApidId; use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::PusPacket; use satrs::tmtc::tm_helper::SharedTmPool; use satrs::{ChannelId, TargetId}; +use satrs_example::config::tmtc_err::REQUEST_TIMEOUT; use satrs_example::config::{tmtc_err, TcReceiverId, TmSenderId, PUS_APID}; use std::sync::mpsc::{self}; use crate::requests::GenericRequestRouter; +use super::PusTargetedRequestService; + +#[derive(Default)] +pub struct ActionReplyHandler {} + +impl PusReplyHandler for ActionReplyHandler { + type Error = (); + + fn handle_unexpected_reply( + &mut self, + reply: &satrs::request::GenericMessage, + ) { + log::warn!("received unexpected reply for service {SERVICE}: {reply}"); + } + + fn handle_reply( + &mut self, + reply: &satrs::request::GenericMessage, + verification_handler: &impl VerificationReportingProvider, + tm_sender: &impl EcssTmSenderCore, + ) -> Result { + todo!() + } + + /* + fn timeout_callback(&self, active_request: &ActiveRequestType) { + log::warn!("timeout for active request {active_request} on service {SERVICE}"); + } + + fn timeout_error_code(&self) -> satrs::res_code::ResultU16 { + REQUEST_TIMEOUT + } + */ +} + #[derive(Default)] pub struct ExampleActionRequestConverter {} @@ -99,7 +135,7 @@ pub fn create_action_service_static( "PUS_8_TC_RECV", pus_action_rx, ); - let action_request_handler = PusService8ActionRequestHandler::new( + let action_request_handler = PusTargetedRequestService::new( PusServiceHelper::new( action_srv_receiver, action_srv_tm_sender.clone(), @@ -109,18 +145,13 @@ pub fn create_action_service_static( ), ExampleActionRequestConverter::default(), action_router, - ); - let action_reply_handler = PusService8ReplyHandler::new_from_now( - verif_reporter.clone(), + // TODO: Implementation which does not use run-time allocation? Maybe something like + // a bounded wrapper which pre-allocates using [HashMap::with_capacity].. DefaultActiveActionRequestMap::default(), - 1024, - PusActionReplyHook::default(), - action_srv_tm_sender, - ) - .expect("Failed to create PUS 8 reply handler"); + ActionReplyHandler::<8>::default(), + ); Pus8Wrapper { action_request_handler, - action_reply_handler, } } @@ -145,7 +176,7 @@ pub fn create_action_service_dynamic( "PUS_8_TC_RECV", pus_action_rx, ); - let action_request_handler = PusService8ActionRequestHandler::new( + let action_request_handler = PusTargetedRequestService::new( PusServiceHelper::new( action_srv_receiver, action_srv_tm_sender.clone(), @@ -155,18 +186,11 @@ pub fn create_action_service_dynamic( ), ExampleActionRequestConverter::default(), action_router, - ); - 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"); + ActionReplyHandler::<8>::default(), + ); Pus8Wrapper { action_request_handler, - action_reply_handler, } } @@ -195,19 +219,13 @@ pub struct Pus8Wrapper< TcInMemConverter: EcssTcInMemConverter, VerificationReporter: VerificationReportingProvider, > { - pub(crate) action_request_handler: PusService8ActionRequestHandler< + pub(crate) action_request_handler: PusTargetedRequestService< TcReceiver, TmSender, TcInMemConverter, VerificationReporter, ExampleActionRequestConverter, - GenericRequestRouter, - >, - pub(crate) action_reply_handler: PusService8ReplyHandler< - VerificationReporter, - DefaultActiveActionRequestMap, - PusActionReplyHook, - TmSender, + ActionRequest, >, } @@ -239,7 +257,6 @@ impl< error!("PUS packet handling error: {error:?}") } } - // self.action_reply_handler.handle_replies(); false } } diff --git a/satrs-example/src/pus/event.rs b/satrs-example/src/pus/event.rs index 1d16f5c..8ef19af 100644 --- a/satrs-example/src/pus/event.rs +++ b/satrs-example/src/pus/event.rs @@ -106,8 +106,8 @@ impl< VerificationReporter: VerificationReportingProvider, > Pus5Wrapper { - pub fn handle_next_packet(&mut self) -> bool { - match self.pus_5_handler.handle_one_tc() { + pub fn handle_next_packet(&mut self, time_stamp: &[u8]) -> bool { + match self.pus_5_handler.handle_one_tc(time_stamp) { Ok(result) => match result { PusPacketHandlerResult::RequestHandled => {} PusPacketHandlerResult::RequestHandledPartialSuccess(e) => { diff --git a/satrs-example/src/pus/mod.rs b/satrs-example/src/pus/mod.rs index 60a4644..0f933c6 100644 --- a/satrs-example/src/pus/mod.rs +++ b/satrs-example/src/pus/mod.rs @@ -1,7 +1,18 @@ +use crate::requests::GenericRequestRouter; use crate::tmtc::MpscStoreAndSendError; use log::warn; -use satrs::pus::verification::{FailParams, VerificationReportingProvider}; -use satrs::pus::{EcssTcAndToken, PusPacketHandlerResult, TcInMemory}; +use satrs::pus::verification::{ + self, FailParams, VerificationReporter, VerificationReporterWithSharedPoolMpscBoundedSender, + VerificationReporterWithVecMpscSender, VerificationReportingProvider, +}; +use satrs::pus::{ + ActiveRequestMapProvider, ActiveRequestProvider, DefaultActiveRequestMap, EcssTcAndToken, + EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, + EcssTmSenderCore, GenericRoutingError, MpscTcReceiver, PusPacketHandlerResult, PusReplyHandler, + PusServiceHelper, PusServiceReplyHandler, PusTcToRequestConverter, ReplyHandlerHook, + TcInMemory, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, +}; +use satrs::request::GenericMessage; use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::PusServiceId; use satrs::spacepackets::time::cds::TimeProvider; @@ -36,13 +47,6 @@ struct TimeStampHelper { } impl TimeStampHelper { - pub fn new() -> Self { - Self { - stamper: TimeProvider::new_with_u16_days(0, 0), - time_stamp: [0; 7], - } - } - pub fn stamp(&self) -> &[u8] { &self.time_stamp } @@ -57,16 +61,137 @@ impl TimeStampHelper { } } +impl Default for TimeStampHelper { + fn default() -> Self { + Self { + stamper: TimeProvider::from_now_with_u16_days().expect("creating time stamper failed"), + time_stamp: Default::default(), + } + } +} + impl PusReceiver { pub fn new(verif_reporter: VerificationReporter, pus_router: PusTcMpscRouter) -> Self { Self { verif_reporter, pus_router, - stamp_helper: TimeStampHelper::new(), + stamp_helper: TimeStampHelper::default(), } } } +pub struct PusTargetedRequestService< + TcReceiver: EcssTcReceiverCore, + TmSender: EcssTmSenderCore, + TcInMemConverter: EcssTcInMemConverter, + VerificationReporter: VerificationReportingProvider, + RequestConverter: PusTcToRequestConverter, + ReplyHook: ReplyHandlerHook, + ActiveRequestMap: ActiveRequestMapProvider, + ActiveRequestType: ActiveRequestProvider, + RequestType, + ReplyType, +> { + pub service_helper: + PusServiceHelper, + pub request_router: GenericRequestRouter, + pub request_converter: RequestConverter, + pub active_request_map: ActiveRequestMap, + pub reply_hook: ReplyHook, + phantom: std::marker::PhantomData, +} + +impl< + TcReceiver: EcssTcReceiverCore, + TmSender: EcssTmSenderCore, + TcInMemConverter: EcssTcInMemConverter, + VerificationReporter: VerificationReportingProvider, + RequestConverter: PusTcToRequestConverter, + ReplyHandler: PusReplyHandler, + ActiveRequestMap: ActiveRequestMapProvider, + ActiveRequestType: ActiveRequestProvider, + RequestType, + ReplyType, + > + PusTargetedRequestService< + TcReceiver, + TmSender, + TcInMemConverter, + VerificationReporter, + RequestConverter, + ReplyHandler, + ActiveRequestMap, + ActiveRequestType, + RequestType, + ReplyType, + > +{ + pub fn new( + service_helper: PusServiceHelper< + TcReceiver, + TmSender, + TcInMemConverter, + VerificationReporter, + >, + request_converter: RequestConverter, + request_router: GenericRequestRouter, + active_request_map: ActiveRequestMap, + reply_hook: ReplyHandler, + ) -> Self { + Self { + service_helper, + request_router, + request_converter, + active_request_map, + reply_hook, + phantom: std::marker::PhantomData, + } + } + + pub fn handle_one_tc(&mut self) { + 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 (active_request, 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( + active_request.target_id(), + action_request, + ecss_tc_and_token.token, + ) { + let verif_request_id = verification::RequestId::new(&tc); + self.active_request_map + .insert(verif_request_id.into(), active_request); + self.request_router.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) + } + + pub fn insert_reply(&mut self, reply: &GenericMessage) { + // self.reply_hook.insert_reply(reply, &self.active_request_map); + } +} + impl PusReceiver { pub fn handle_tc_packet( &mut self, diff --git a/satrs-example/src/pus/scheduler.rs b/satrs-example/src/pus/scheduler.rs index c5d2c06..1c99a83 100644 --- a/satrs-example/src/pus/scheduler.rs +++ b/satrs-example/src/pus/scheduler.rs @@ -103,8 +103,11 @@ impl< } } - pub fn handle_next_packet(&mut self) -> bool { - match self.pus_11_handler.handle_one_tc(&mut self.sched_tc_pool) { + pub fn handle_next_packet(&mut self, time_stamp: &[u8]) -> bool { + match self + .pus_11_handler + .handle_one_tc(time_stamp, &mut self.sched_tc_pool) + { Ok(result) => match result { PusPacketHandlerResult::RequestHandled => {} PusPacketHandlerResult::RequestHandledPartialSuccess(e) => { diff --git a/satrs-example/src/pus/stack.rs b/satrs-example/src/pus/stack.rs index ed06e08..679f54a 100644 --- a/satrs-example/src/pus/stack.rs +++ b/satrs-example/src/pus/stack.rs @@ -1,6 +1,9 @@ -use satrs::pus::{ - verification::VerificationReportingProvider, EcssTcInMemConverter, EcssTcReceiverCore, - EcssTmSenderCore, +use satrs::{ + pus::{ + verification::VerificationReportingProvider, EcssTcInMemConverter, EcssTcReceiverCore, + EcssTmSenderCore, + }, + spacepackets::time::{cds, TimeWriter}, }; use super::{ @@ -51,6 +54,10 @@ impl< pub fn periodic_operation(&mut self) { self.schedule_srv.release_tcs(); + let time_stamp = cds::TimeProvider::from_now_with_u16_days() + .expect("time stamp generation error") + .to_vec() + .unwrap(); loop { let mut all_queues_empty = true; let mut is_srv_finished = |srv_handler_finished: bool| { @@ -58,9 +65,9 @@ impl< all_queues_empty = false; } }; - is_srv_finished(self.test_srv.handle_next_packet()); - is_srv_finished(self.schedule_srv.handle_next_packet()); - is_srv_finished(self.event_srv.handle_next_packet()); + is_srv_finished(self.test_srv.handle_next_packet(&time_stamp)); + is_srv_finished(self.schedule_srv.handle_next_packet(&time_stamp)); + is_srv_finished(self.event_srv.handle_next_packet(&time_stamp)); is_srv_finished(self.action_srv.handle_next_packet()); is_srv_finished(self.hk_srv.handle_next_packet()); if all_queues_empty { diff --git a/satrs-example/src/pus/test.rs b/satrs-example/src/pus/test.rs index 17822a3..efb202c 100644 --- a/satrs-example/src/pus/test.rs +++ b/satrs-example/src/pus/test.rs @@ -111,8 +111,8 @@ impl< VerificationReporter: VerificationReportingProvider, > Service17CustomWrapper { - pub fn handle_next_packet(&mut self) -> bool { - let res = self.pus17_handler.handle_one_tc(); + pub fn handle_next_packet(&mut self, time_stamp: &[u8]) -> bool { + let res = self.pus17_handler.handle_one_tc(time_stamp); if res.is_err() { warn!("PUS17 handler failed with error {:?}", res.unwrap_err()); return true; diff --git a/satrs/src/cfdp/dest.rs b/satrs/src/cfdp/dest.rs index b42df3a..4a87ce6 100644 --- a/satrs/src/cfdp/dest.rs +++ b/satrs/src/cfdp/dest.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use super::{ filestore::{FilestoreError, VirtualFilestore}, user::{CfdpUser, FileSegmentRecvdParams, MetadataReceivedParams}, - CheckTimer, CheckTimerCreator, EntityType, LocalEntityConfig, PacketInfo, PacketTarget, + CheckTimerCreator, CountdownProvider, EntityType, LocalEntityConfig, PacketInfo, PacketTarget, RemoteEntityConfig, RemoteEntityConfigProvider, State, TimerContext, TransactionId, TransactionStep, }; @@ -54,7 +54,7 @@ struct TransferState { completion_disposition: CompletionDisposition, checksum: u32, current_check_count: u32, - current_check_timer: Option>, + current_check_timer: Option>, } impl Default for TransferState { @@ -799,9 +799,9 @@ mod tests { }; use crate::cfdp::{ - filestore::NativeFilestore, user::OwnedMetadataRecvdParams, CheckTimer, CheckTimerCreator, - DefaultFaultHandler, IndicationConfig, RemoteEntityConfig, StdRemoteEntityConfigProvider, - UserFaultHandler, CRC_32, + filestore::NativeFilestore, user::OwnedMetadataRecvdParams, CheckTimerCreator, + CountdownProvider, DefaultFaultHandler, IndicationConfig, RemoteEntityConfig, + StdRemoteEntityConfigProvider, UserFaultHandler, CRC_32, }; use super::*; @@ -1057,7 +1057,7 @@ mod tests { expired: Arc, } - impl CheckTimer for TestCheckTimer { + impl CountdownProvider for TestCheckTimer { fn has_expired(&self) -> bool { self.expired.load(core::sync::atomic::Ordering::Relaxed) } @@ -1088,7 +1088,10 @@ mod tests { } impl CheckTimerCreator for TestCheckTimerCreator { - fn get_check_timer_provider(&self, timer_context: TimerContext) -> Box { + fn get_check_timer_provider( + &self, + timer_context: TimerContext, + ) -> Box { match timer_context { TimerContext::CheckLimit { .. } => { Box::new(TestCheckTimer::new(self.check_limit_expired_flag.clone())) diff --git a/satrs/src/cfdp/mod.rs b/satrs/src/cfdp/mod.rs index 8c88fda..c2f6d01 100644 --- a/satrs/src/cfdp/mod.rs +++ b/satrs/src/cfdp/mod.rs @@ -17,6 +17,8 @@ use alloc::boxed::Box; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +use crate::time::CountdownProvider; + #[cfg(feature = "std")] pub mod dest; #[cfg(feature = "alloc")] @@ -45,7 +47,15 @@ pub enum TimerContext { }, } -/// Generic abstraction for a check timer which is used by 3 mechanisms of the CFDP protocol. +/// A generic trait which allows CFDP entities to create check timers which are required to +/// implement special procedures in unacknowledged transmission mode, as specified in 4.6.3.2 +/// and 4.6.3.3. +/// +/// This trait also allows the creation of different check timers depending on context and purpose +/// of the timer, the runtime environment (e.g. standard clock timer vs. timer using a RTC) or +/// other factors. +/// +/// The countdown timer is used by 3 mechanisms of the CFDP protocol. /// /// ## 1. Check limit handling /// @@ -74,22 +84,9 @@ pub enum TimerContext { /// The timer will be used to perform the Positive Acknowledgement Procedures as specified in /// 4.7. 1of the CFDP standard. The expiration period will be provided by the Positive ACK timer /// interval of the remote entity configuration. -pub trait CheckTimer: Debug { - fn has_expired(&self) -> bool; - fn reset(&mut self); -} - -/// A generic trait which allows CFDP entities to create check timers which are required to -/// implement special procedures in unacknowledged transmission mode, as specified in 4.6.3.2 -/// and 4.6.3.3. The [CheckTimer] documentation provides more information about the purpose of the -/// check timer in the context of CFDP. -/// -/// This trait also allows the creation of different check timers depending on context and purpose -/// of the timer, the runtime environment (e.g. standard clock timer vs. timer using a RTC) or -/// other factors. #[cfg(feature = "alloc")] pub trait CheckTimerCreator { - fn get_check_timer_provider(&self, timer_context: TimerContext) -> Box; + fn get_check_timer_provider(&self, timer_context: TimerContext) -> Box; } /// Simple implementation of the [CheckTimerCreator] trait assuming a standard runtime. @@ -112,7 +109,7 @@ impl StdCheckTimer { } #[cfg(feature = "std")] -impl CheckTimer for StdCheckTimer { +impl CountdownProvider for StdCheckTimer { fn has_expired(&self) -> bool { let elapsed_time = self.start_time.elapsed(); if elapsed_time.as_secs() > self.expiry_time_seconds { diff --git a/satrs/src/lib.rs b/satrs/src/lib.rs index b3374f9..405b2e3 100644 --- a/satrs/src/lib.rs +++ b/satrs/src/lib.rs @@ -43,6 +43,7 @@ pub mod queue; pub mod request; pub mod res_code; pub mod seq_count; +pub mod time; pub mod tmtc; pub mod action; diff --git a/satrs/src/pus/action.rs b/satrs/src/pus/action.rs index 881274c..afcfd28 100644 --- a/satrs/src/pus/action.rs +++ b/satrs/src/pus/action.rs @@ -105,7 +105,6 @@ pub mod std_mod { self, FailParams, FailParamsWithStep, TcStateStarted, VerificationReportingProvider, }, ActiveRequestMapProvider, DefaultActiveRequestMap, EcssTmSenderCore, EcssTmtcError, - GenericRoutingError, PusServiceReplyHandler, PusTargetedRequestHandler, ReplyHandlerHook, }, }; @@ -115,27 +114,9 @@ pub mod std_mod { use super::*; - pub type PusService8ActionRequestHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - RoutingError = GenericRoutingError, - > = PusTargetedRequestHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - 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. @@ -299,6 +280,7 @@ pub mod std_mod { ) } } + */ } #[cfg(test)] @@ -311,11 +293,12 @@ mod tests { use spacepackets::{ ecss::{ - tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}, + tc::{PusTcCreator, PusTcReader}, tm::PusTmReader, PusPacket, }, - CcsdsPacket, SequenceFlags, SpHeader, + time::{cds, TimeWriter}, + CcsdsPacket, }; use crate::{ @@ -324,7 +307,7 @@ mod tests { pus::{ tests::{ PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, - TestConverter, TestRouter, APP_DATA_TOO_SHORT, TEST_APID, + TestConverter, TestRouter, APP_DATA_TOO_SHORT, }, verification::{ self, @@ -332,9 +315,9 @@ mod tests { FailParams, TcStateAccepted, TcStateNone, TcStateStarted, VerificationReportingProvider, }, - EcssTcInVecConverter, EcssTmtcError, GenericRoutingError, MpscTcReceiver, - PusPacketHandlerResult, PusPacketHandlingError, PusRequestRouter, - PusTcToRequestConverter, ReplyHandlerHook, TmAsVecSenderWithMpsc, + EcssTcInMemConverter, EcssTcInVecConverter, EcssTmtcError, GenericRoutingError, + MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, PusRequestRouter, + PusServiceHelper, PusTcToRequestConverter, ReplyHandlerHook, TmAsVecSenderWithMpsc, }, }; @@ -416,29 +399,32 @@ mod tests { } } - struct Pus8RequestTestbenchWithVec { - common: PusServiceHandlerWithVecCommon, - handler: PusService8ActionRequestHandler< + pub struct PusDynRequestHandler { + srv_helper: PusServiceHelper< MpscTcReceiver, TmAsVecSenderWithMpsc, EcssTcInVecConverter, TestVerificationReporter, - TestConverter<8>, - TestRouter, >, + request_converter: TestConverter, + request_router: TestRouter, + } + + struct Pus8RequestTestbenchWithVec { + common: PusServiceHandlerWithVecCommon, + handler: PusDynRequestHandler<8, ActionRequest>, } impl Pus8RequestTestbenchWithVec { pub fn new() -> Self { - let (common, srv_handler) = - PusServiceHandlerWithVecCommon::new_with_test_verif_sender(); + let (common, srv_helper) = PusServiceHandlerWithVecCommon::new_with_test_verif_sender(); Self { common, - handler: PusService8ActionRequestHandler::new( - srv_handler, - TestConverter::default(), - TestRouter::default(), - ), + handler: PusDynRequestHandler { + srv_helper, + request_converter: TestConverter::default(), + request_router: TestRouter::default(), + }, } } @@ -474,10 +460,43 @@ mod tests { } } impl SimplePusPacketHandler for Pus8RequestTestbenchWithVec { - delegate! { - to self.handler { - fn handle_one_tc(&mut self) -> Result; + fn handle_one_tc(&mut self) -> Result { + let possible_packet = self.handler.srv_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 + .handler + .srv_helper + .tc_in_mem_converter + .convert_ecss_tc_in_memory_to_reader(&ecss_tc_and_token.tc_in_memory)?; + let time_stamp = cds::TimeProvider::from_now_with_u16_days() + .expect("timestamp generation failed") + .to_vec() + .unwrap(); + let (target_id, action_request) = self.handler.request_converter.convert( + ecss_tc_and_token.token, + &tc, + &time_stamp, + &self.handler.srv_helper.common.verification_handler, + )?; + if let Err(e) = self.handler.request_router.route( + target_id, + action_request, + ecss_tc_and_token.token, + ) { + self.handler.request_router.handle_error( + target_id, + ecss_tc_and_token.token, + &tc, + e.clone(), + &time_stamp, + &self.handler.srv_helper.common.verification_handler, + ); + return Err(e.into()); + } + Ok(PusPacketHandlerResult::RequestHandled) } } @@ -667,68 +686,6 @@ mod tests { } } - #[test] - fn basic_test() { - let mut action_handler = Pus8RequestTestbenchWithVec::new(); - let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); - let sec_header = PusTcSecondaryHeader::new_simple(8, 1); - let action_id: u32 = 1; - let action_id_raw = action_id.to_be_bytes(); - let tc = PusTcCreator::new(&mut sp_header, sec_header, action_id_raw.as_ref(), true); - action_handler.send_tc(&tc); - let result = action_handler.handle_one_tc(); - assert!(result.is_ok()); - action_handler.check_next_conversion(&tc); - let (target_id, action_req) = action_handler.retrieve_next_request(); - assert_eq!(target_id, TEST_APID.into()); - assert_eq!(action_req.action_id, 1); - if let ActionRequestVariant::VecData(data) = action_req.variant { - assert_eq!(data, &[]); - } - } - - #[test] - fn test_routing_error() { - let mut action_handler = Pus8RequestTestbenchWithVec::new(); - let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); - let sec_header = PusTcSecondaryHeader::new_simple(8, 1); - let action_id: u32 = 1; - let action_id_raw = action_id.to_be_bytes(); - let tc = PusTcCreator::new(&mut sp_header, sec_header, action_id_raw.as_ref(), true); - let error = GenericRoutingError::UnknownTargetId(25); - action_handler - .handler - .request_router - .inject_routing_error(error); - action_handler.send_tc(&tc); - let result = action_handler.handle_one_tc(); - assert!(result.is_err()); - let check_error = |routing_error: GenericRoutingError| { - if let GenericRoutingError::UnknownTargetId(id) = routing_error { - assert_eq!(id, 25); - } else { - panic!("unexpected error type"); - } - }; - if let PusPacketHandlingError::RequestRoutingError(routing_error) = result.unwrap_err() { - check_error(routing_error); - } else { - panic!("unexpected error type"); - } - - action_handler.check_next_conversion(&tc); - let (target_id, action_req) = action_handler.retrieve_next_request(); - assert_eq!(target_id, TEST_APID.into()); - assert_eq!(action_req.action_id, 1); - if let ActionRequestVariant::VecData(data) = action_req.variant { - assert_eq!(data, &[]); - } - - let (target_id, found_error) = action_handler.retrieve_next_routing_error(); - assert_eq!(target_id, TEST_APID.into()); - check_error(found_error); - } - #[test] fn test_reply_handler_completion_success() { let mut reply_testbench = Pus8ReplyTestbench::new(true); diff --git a/satrs/src/pus/event_srv.rs b/satrs/src/pus/event_srv.rs index 64c1ba0..df0ebe3 100644 --- a/satrs/src/pus/event_srv.rs +++ b/satrs/src/pus/event_srv.rs @@ -7,10 +7,7 @@ use spacepackets::ecss::PusPacket; use std::sync::mpsc::Sender; use super::verification::VerificationReportingProvider; -use super::{ - get_current_cds_short_timestamp, EcssTcInMemConverter, EcssTcReceiverCore, EcssTmSenderCore, - PusServiceHelper, -}; +use super::{EcssTcInMemConverter, EcssTcReceiverCore, EcssTmSenderCore, PusServiceHelper}; pub struct PusService5EventHandler< TcReceiver: EcssTcReceiverCore, @@ -45,7 +42,10 @@ impl< } } - pub fn handle_one_tc(&mut self) -> Result { + pub fn handle_one_tc( + &mut self, + time_stamp: &[u8], + ) -> Result { let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?; if possible_packet.is_none() { return Ok(PusPacketHandlerResult::Empty); @@ -63,7 +63,7 @@ impl< ecss_tc_and_token.token, )); } - let handle_enable_disable_request = |enable: bool, stamp: [u8; 7]| { + let handle_enable_disable_request = |enable: bool| { if tc.user_data().len() < 4 { return Err(PusPacketHandlingError::NotEnoughAppData { expected: 4, @@ -76,7 +76,7 @@ impl< .service_helper .common .verification_handler - .start_success(ecss_tc_and_token.token, &stamp) + .start_success(ecss_tc_and_token.token, time_stamp) .map_err(|_| PartialPusHandlingError::Verification); let partial_error = start_token.clone().err(); let mut token: TcStateToken = ecss_tc_and_token.token.into(); @@ -106,8 +106,6 @@ impl< } Ok(PusPacketHandlerResult::RequestHandled) }; - let mut partial_error = None; - let time_stamp = get_current_cds_short_timestamp(&mut partial_error); match srv.unwrap() { Subservice::TmInfoReport | Subservice::TmLowSeverityReport @@ -116,10 +114,10 @@ impl< return Err(PusPacketHandlingError::InvalidSubservice(tc.subservice())) } Subservice::TcEnableEventGeneration => { - handle_enable_disable_request(true, time_stamp)?; + handle_enable_disable_request(true)?; } Subservice::TcDisableEventGeneration => { - handle_enable_disable_request(false, time_stamp)?; + handle_enable_disable_request(false)?; } Subservice::TcReportDisabledList | Subservice::TmDisabledEventsReport => { return Ok(PusPacketHandlerResult::SubserviceNotImplemented( @@ -137,6 +135,7 @@ impl< mod tests { use delegate::delegate; use spacepackets::ecss::event::Subservice; + use spacepackets::time::{cds, TimeWriter}; use spacepackets::util::UnsignedEnum; use spacepackets::{ ecss::{ @@ -200,10 +199,9 @@ mod tests { } impl SimplePusPacketHandler for Pus5HandlerWithStoreTester { - delegate! { - to self.handler { - fn handle_one_tc(&mut self) -> Result; - } + fn handle_one_tc(&mut self) -> Result { + let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); + self.handler.handle_one_tc(&time_stamp) } } diff --git a/satrs/src/pus/hk.rs b/satrs/src/pus/hk.rs deleted file mode 100644 index b44c3d2..0000000 --- a/satrs/src/pus/hk.rs +++ /dev/null @@ -1,280 +0,0 @@ -pub use spacepackets::ecss::hk::*; - -#[cfg(feature = "std")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] -pub use std_mod::*; - -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -#[allow(unused_imports)] -pub use alloc_mod::*; - -use crate::{hk::HkRequest, TargetId}; - -use super::verification::{TcStateAccepted, VerificationToken}; - -/// This trait is an abstraction for the routing of PUS service 3 housekeeping requests to a -/// dedicated recipient using the generic [TargetId]. -pub trait PusHkRequestRouter { - type Error; - fn route( - &self, - target_id: TargetId, - hk_request: HkRequest, - token: VerificationToken, - ) -> Result<(), Self::Error>; -} - -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -pub mod alloc_mod {} - -#[cfg(feature = "std")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] -pub mod std_mod { - use crate::pus::{GenericRoutingError, PusTargetedRequestHandler}; - - use super::*; - - pub type PusService3HkRequestHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - RoutingError = GenericRoutingError, - > = PusTargetedRequestHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - HkRequest, - RoutingError, - >; -} - -#[cfg(test)] -mod tests { - use delegate::delegate; - use spacepackets::ecss::hk::Subservice; - - use spacepackets::{ - ecss::{ - tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}, - tm::PusTmReader, - PusPacket, - }, - CcsdsPacket, SequenceFlags, SpHeader, - }; - - use crate::pus::{MpscTcReceiver, PusTcToRequestConverter, TmAsVecSenderWithMpsc}; - use crate::{ - hk::HkRequest, - pus::{ - tests::{ - PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, - TestConverter, TestRouter, APP_DATA_TOO_SHORT, TEST_APID, - }, - verification::{ - tests::TestVerificationReporter, FailParams, RequestId, TcStateAccepted, - VerificationReportingProvider, VerificationToken, - }, - EcssTcInVecConverter, GenericRoutingError, PusPacketHandlerResult, - PusPacketHandlingError, - }, - TargetId, - }; - - use super::{PusHkRequestRouter, PusService3HkRequestHandler}; - - impl PusHkRequestRouter for TestRouter { - type Error = GenericRoutingError; - - fn route( - &self, - target_id: TargetId, - hk_request: HkRequest, - _token: VerificationToken, - ) -> Result<(), Self::Error> { - self.routing_requests - .borrow_mut() - .push_back((target_id, hk_request)); - self.check_for_injected_error() - } - } - - impl PusTcToRequestConverter for TestConverter<3> { - type Error = PusPacketHandlingError; - fn convert( - &mut self, - token: VerificationToken, - tc: &PusTcReader, - time_stamp: &[u8], - verif_reporter: &impl VerificationReportingProvider, - ) -> Result<(TargetId, HkRequest), Self::Error> { - self.conversion_request.push_back(tc.raw_data().to_vec()); - self.check_service(tc)?; - let target_id = tc.apid(); - if tc.user_data().len() < 4 { - verif_reporter - .start_failure( - token, - FailParams::new( - time_stamp, - &APP_DATA_TOO_SHORT, - (tc.user_data().len() as u32).to_be_bytes().as_ref(), - ), - ) - .expect("start success failure"); - return Err(PusPacketHandlingError::NotEnoughAppData { - expected: 4, - found: tc.user_data().len(), - }); - } - if tc.subservice() == Subservice::TcGenerateOneShotHk as u8 { - verif_reporter - .start_success(token, time_stamp) - .expect("start success failure"); - return Ok(( - target_id.into(), - HkRequest::OneShot(u32::from_be_bytes( - tc.user_data()[0..4].try_into().unwrap(), - )), - )); - } - Err(PusPacketHandlingError::InvalidAppData( - "unexpected app data".into(), - )) - } - } - - struct Pus3HandlerWithVecTester { - common: PusServiceHandlerWithVecCommon, - handler: PusService3HkRequestHandler< - MpscTcReceiver, - TmAsVecSenderWithMpsc, - EcssTcInVecConverter, - TestVerificationReporter, - TestConverter<3>, - TestRouter, - >, - } - - impl Pus3HandlerWithVecTester { - pub fn new() -> Self { - let (common, srv_handler) = - PusServiceHandlerWithVecCommon::new_with_test_verif_sender(); - Self { - common, - handler: PusService3HkRequestHandler::new( - srv_handler, - TestConverter::default(), - TestRouter::default(), - ), - } - } - - delegate! { - to self.handler.request_converter { - pub fn check_next_conversion(&mut self, tc: &PusTcCreator); - } - } - delegate! { - to self.handler.request_router { - pub fn retrieve_next_request(&mut self) -> (TargetId, HkRequest); - } - } - delegate! { - to self.handler.request_router { - pub fn retrieve_next_routing_error(&mut self) -> (TargetId, GenericRoutingError); - } - } - } - - impl PusTestHarness for Pus3HandlerWithVecTester { - delegate! { - to self.common { - fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken; - fn read_next_tm(&mut self) -> PusTmReader<'_>; - fn check_no_tm_available(&self) -> bool; - fn check_next_verification_tm( - &self, - subservice: u8, - expected_request_id: RequestId, - ); - } - } - } - impl SimplePusPacketHandler for Pus3HandlerWithVecTester { - delegate! { - to self.handler { - fn handle_one_tc(&mut self) -> Result; - } - } - } - - #[test] - fn basic_test() { - let mut hk_handler = Pus3HandlerWithVecTester::new(); - let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); - let sec_header = PusTcSecondaryHeader::new_simple(3, Subservice::TcGenerateOneShotHk as u8); - let unique_id: u32 = 1; - let unique_id_raw = unique_id.to_be_bytes(); - let tc = PusTcCreator::new(&mut sp_header, sec_header, unique_id_raw.as_ref(), true); - hk_handler.send_tc(&tc); - let result = hk_handler.handle_one_tc(); - assert!(result.is_ok()); - hk_handler.check_next_conversion(&tc); - let (target_id, hk_request) = hk_handler.retrieve_next_request(); - assert_eq!(target_id, TEST_APID.into()); - if let HkRequest::OneShot(id) = hk_request { - assert_eq!(id, unique_id); - } else { - panic!("unexpected request"); - } - } - - #[test] - fn test_routing_error() { - let mut hk_handler = Pus3HandlerWithVecTester::new(); - let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); - let sec_header = PusTcSecondaryHeader::new_simple(3, Subservice::TcGenerateOneShotHk as u8); - let unique_id: u32 = 1; - let unique_id_raw = unique_id.to_be_bytes(); - let tc = PusTcCreator::new(&mut sp_header, sec_header, unique_id_raw.as_ref(), true); - let error = GenericRoutingError::UnknownTargetId(25); - hk_handler - .handler - .request_router - .inject_routing_error(error); - hk_handler.send_tc(&tc); - let result = hk_handler.handle_one_tc(); - assert!(result.is_err()); - let check_error = |routing_error: GenericRoutingError| { - if let GenericRoutingError::UnknownTargetId(id) = routing_error { - assert_eq!(id, 25); - } else { - panic!("unexpected error type"); - } - }; - if let PusPacketHandlingError::RequestRoutingError(routing_error) = result.unwrap_err() { - check_error(routing_error); - } else { - panic!("unexpected error type"); - } - - hk_handler.check_next_conversion(&tc); - let (target_id, hk_req) = hk_handler.retrieve_next_request(); - assert_eq!(target_id, TEST_APID.into()); - if let HkRequest::OneShot(unique_id) = hk_req { - assert_eq!(unique_id, 1); - } - - let (target_id, found_error) = hk_handler.retrieve_next_routing_error(); - assert_eq!(target_id, TEST_APID.into()); - check_error(found_error); - } -} diff --git a/satrs/src/pus/mod.rs b/satrs/src/pus/mod.rs index 5479951..fa9a809 100644 --- a/satrs/src/pus/mod.rs +++ b/satrs/src/pus/mod.rs @@ -29,7 +29,6 @@ pub mod event; pub mod event_man; #[cfg(feature = "std")] pub mod event_srv; -pub mod hk; pub mod mode; pub mod scheduler; #[cfg(feature = "std")] @@ -44,7 +43,7 @@ pub use alloc_mod::*; #[cfg(feature = "std")] pub use std_mod::*; -use self::verification::{FailParams, TcStateStarted, VerificationReportingProvider}; +use self::verification::{TcStateStarted, VerificationReportingProvider}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum PusTmWrapper<'tm> { @@ -298,14 +297,14 @@ pub trait ActiveRequestProvider { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ActiveRequest { +pub struct ActivePusRequest { target_id: TargetId, token: VerificationToken, start_time: UnixTimestamp, timeout: Duration, } -impl ActiveRequestProvider for ActiveRequest { +impl ActiveRequestProvider for ActivePusRequest { fn target_id(&self) -> TargetId { self.target_id } @@ -323,30 +322,18 @@ impl ActiveRequestProvider for ActiveRequest { } } -/// Generic user hook method. -/// -/// This hook method currently serves the following tasks: -/// -/// 1. Pass specific information to the reply handlers which can not be kept inside the -/// framework. This includes information like the error codes used for packet verification. -/// 2. It exposes callback methods which can be useful to perform custom user operations like -/// logging. -pub trait ReplyHandlerHook { - fn handle_unexpected_reply(&mut self, reply: &GenericMessage); - fn timeout_callback(&self, active_request: &ActiveRequestType); - 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>; + fn handle_error( &self, target_id: TargetId, @@ -358,6 +345,23 @@ pub trait PusRequestRouter { ); } +pub trait PusReplyHandler { + type Error; + + fn handle_reply( + &mut self, + reply: &GenericMessage, + verification_handler: &impl VerificationReportingProvider, + tm_sender: &impl EcssTmSenderCore, + ) -> Result; + + fn handle_unexpected_reply( + &mut self, + reply: &GenericMessage, + tm_sender: &impl EcssTmSenderCore, + ); +} + #[cfg(feature = "alloc")] pub mod alloc_mod { use hashbrown::HashMap; @@ -463,7 +467,7 @@ pub mod alloc_mod { /// /// 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 { + pub trait PusTcToRequestConverter { type Error; fn convert( &mut self, @@ -471,7 +475,7 @@ pub mod alloc_mod { tc: &PusTcReader, time_stamp: &[u8], verif_reporter: &impl VerificationReportingProvider, - ) -> Result<(TargetId, Request), Self::Error>; + ) -> Result<(ActiveRequestInfo, Request), Self::Error>; } #[derive(Clone, Debug)] @@ -513,7 +517,9 @@ pub mod alloc_mod { } } - /// Generic reply handler structure which can be used to handle replies for a specific PUS service. + /* + /// Generic reply handler structure which can be used to handle replies for a specific PUS + /// service. /// /// This is done by keeping track of active requests using an internal map structure. An API /// to register new active requests is exposed as well. @@ -524,42 +530,35 @@ pub mod alloc_mod { /// PUS reply handlers. Concrete PUS handlers should constrain the [ActiveRequestProvider] and /// the `ReplyType` generics to specific types tailored towards PUS services in addition to /// providing an API which can process received replies and convert them into verification - /// completions or other operation like user hook calls. The framework also provides some concrete - /// PUS handlers for common PUS services like the mode, action and housekeeping service. + /// completions or other operation like user hook calls. The framework also provides some + /// concrete PUS handlers for common PUS services like the mode, action and housekeeping + /// service. /// /// This object does not automatically update its internal time information used to check for - /// timeouts. The user should call the [Self::update_time] and [Self::update_time_from_now] methods - /// to do this. + /// timeouts. The user should call the [Self::update_time] and [Self::update_time_from_now] + /// methods to do this. pub struct PusServiceReplyHandler< - VerificationReporter: VerificationReportingProvider, ActiveRequestMap: ActiveRequestMapProvider, - UserHook: ReplyHandlerHook, - TmSender: EcssTmSenderCore, + ReplyHook: ReplyHandlerHook, ActiveRequestType: ActiveRequestProvider, ReplyType, > { pub active_request_map: ActiveRequestMap, - pub verification_reporter: VerificationReporter, pub tm_buf: alloc::vec::Vec, pub current_time: UnixTimestamp, - pub user_hook: UserHook, - pub tm_sender: TmSender, + pub user_hook: ReplyHook, phantom: PhantomData<(ActiveRequestType, ReplyType)>, } impl< - VerificationReporter: VerificationReportingProvider, ActiveRequestMap: ActiveRequestMapProvider, - UserHook: ReplyHandlerHook, - TmSender: EcssTmSenderCore, + ReplyHook: ReplyHandlerHook, ActiveRequestType: ActiveRequestProvider, ReplyType, > PusServiceReplyHandler< - VerificationReporter, ActiveRequestMap, - UserHook, - TmSender, + ReplyHook, ActiveRequestType, ReplyType, > @@ -567,15 +566,12 @@ pub mod alloc_mod { #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] pub fn new_from_now( - verification_reporter: VerificationReporter, active_request_map: ActiveRequestMap, fail_data_buf_size: usize, - user_hook: UserHook, - tm_sender: TmSender, + user_hook: ReplyHook, ) -> Result { let current_time = UnixTimestamp::from_now()?; Ok(Self::new( - verification_reporter, active_request_map, fail_data_buf_size, user_hook, @@ -585,16 +581,14 @@ pub mod alloc_mod { } pub fn new( - verification_reporter: VerificationReporter, active_request_map: ActiveRequestMap, fail_data_buf_size: usize, - user_hook: UserHook, + user_hook: ReplyHook, tm_sender: TmSender, init_time: UnixTimestamp, ) -> Self { Self { active_request_map, - verification_reporter, tm_buf: alloc::vec![0; fail_data_buf_size], current_time: init_time, user_hook, @@ -668,6 +662,7 @@ pub mod alloc_mod { self.current_time = time; } } + */ } #[cfg(feature = "std")] @@ -684,13 +679,10 @@ 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}; - use spacepackets::time::cds::TimeProvider; use spacepackets::time::StdTimestampError; - use spacepackets::time::TimeWriter; use std::string::String; use std::sync::mpsc; use std::sync::mpsc::TryRecvError; @@ -700,7 +692,7 @@ pub mod std_mod { pub use cb_mod::*; use super::verification::VerificationReportingProvider; - use super::{AcceptedEcssTcAndToken, PusRequestRouter, PusTcToRequestConverter, TcInMemory}; + use super::{AcceptedEcssTcAndToken, TcInMemory}; impl From> for EcssTmtcError { fn from(_: mpsc::SendError) -> Self { @@ -974,17 +966,18 @@ pub mod std_mod { } } - /// This is a high-level handler for the PUS service 8 action service. + /// This is a high-level handler for the generic PUS services which need to convert PUS + /// commands into a request/reply pattern. /// /// 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 + /// [PusTcToRequestConverter]. 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]. + /// 3. Route the action request using the provided [PusRequestRouter]. + /* pub struct PusTargetedRequestHandler< TcReceiver: EcssTcReceiverCore, TmSender: EcssTmSenderCore, @@ -999,10 +992,12 @@ pub mod std_mod { PusServiceHelper, pub request_converter: RequestConverter, pub request_router: RequestRouter, - // pub routing_error_handler: RoutingErrorHandler, phantom: PhantomData, } + // pub trait PusReplyHandlerProvider { + // fn add_routed_request(&mut self, request_id: RequestId, active_request: ActiveRequest); + // } impl< TcReceiver: EcssTcReceiverCore, TmSender: EcssTmSenderCore, @@ -1010,7 +1005,6 @@ pub mod std_mod { VerificationReporter: VerificationReportingProvider, RequestConverter: PusTcToRequestConverter, RequestRouter: PusRequestRouter, - // RoutingErrorHandler: PusRoutingErrorHandler, Request, RoutingError: Clone, > @@ -1021,7 +1015,6 @@ pub mod std_mod { VerificationReporter, RequestConverter, RequestRouter, - // RoutingErrorHandler, Request, RoutingError, > @@ -1042,7 +1035,6 @@ pub mod std_mod { service_helper, request_converter, request_router, - // routing_error_handler, phantom: PhantomData, } } @@ -1083,7 +1075,7 @@ pub mod std_mod { 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 . @@ -1272,26 +1264,6 @@ pub mod std_mod { pub tm_apid: u16, pub verification_handler: VerificationReporter, } - #[cfg(feature = "std")] - pub fn get_current_cds_short_timestamp( - partial_error: &mut Option, - ) -> [u8; 7] { - let mut time_stamp: [u8; 7] = [0; 7]; - let time_provider = - TimeProvider::from_now_with_u16_days().map_err(PartialPusHandlingError::Time); - if let Ok(time_provider) = time_provider { - // Can't fail, we have a buffer with the exact required size. - time_provider.write_to_bytes(&mut time_stamp).unwrap(); - } else { - *partial_error = Some(time_provider.unwrap_err()); - } - time_stamp - } - #[cfg(feature = "std")] - pub fn get_current_timestamp_ignore_error() -> [u8; 7] { - let mut dummy = None; - get_current_cds_short_timestamp(&mut dummy) - } /// This is a high-level PUS packet handler helper. /// diff --git a/satrs/src/pus/mode.rs b/satrs/src/pus/mode.rs index b5bbb85..acc28d9 100644 --- a/satrs/src/pus/mode.rs +++ b/satrs/src/pus/mode.rs @@ -43,45 +43,25 @@ pub mod std_mod { }; use crate::{ - mode::{GenericModeReply, ModeRequest}, + mode::GenericModeReply, pus::{ mode::Subservice, verification::{ self, FailParams, TcStateStarted, VerificationReportingProvider, VerificationToken, }, - ActiveRequest, ActiveRequestMapProvider, EcssTmSenderCore, EcssTmtcError, - GenericRoutingError, PusServiceReplyHandler, PusTargetedRequestHandler, PusTmWrapper, - ReplyHandlerHook, + ActivePusRequest, ActiveRequestMapProvider, EcssTmSenderCore, EcssTmtcError, + PusServiceReplyHandler, PusTmWrapper, ReplyHandlerHook, }, TargetId, }; - pub trait ModeReplyHook: ReplyHandlerHook { + pub trait ModeReplyHook: ReplyHandlerHook { fn wrong_mode_result_code(&self) -> ResultU16; fn can_not_reach_mode_result_code(&self) -> ResultU16; } use super::{ModeReply, MODE_SERVICE_ID}; - pub type PusModeServiceRequestHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - RoutingError = GenericRoutingError, - > = PusTargetedRequestHandler< - TcReceiver, - TmSender, - TcInMemConverter, - VerificationReporter, - RequestConverter, - RequestRouter, - ModeRequest, - RoutingError, - >; - /// Type definition for a PUS mode servicd reply handler which constrains the /// [PusServiceReplyHandler] active request and reply generics to the [ActiveActionRequest] and /// [ActionReplyPusWithIds] type. @@ -95,13 +75,13 @@ pub mod std_mod { ActiveRequestMap, UserHook, TmSender, - ActiveRequest, + ActivePusRequest, ModeReply, >; impl< VerificationReporter: VerificationReportingProvider, - ActiveRequestMap: ActiveRequestMapProvider, + ActiveRequestMap: ActiveRequestMapProvider, UserHook: ModeReplyHook, TmSender: EcssTmSenderCore, > PusModeServiceReplyHandler @@ -116,7 +96,7 @@ pub mod std_mod { ) { self.active_request_map.insert( &request_id.into(), - ActiveRequest { + ActivePusRequest { target_id, token, start_time: self.current_time, diff --git a/satrs/src/pus/scheduler_srv.rs b/satrs/src/pus/scheduler_srv.rs index 9cfb920..a1e74c7 100644 --- a/satrs/src/pus/scheduler_srv.rs +++ b/satrs/src/pus/scheduler_srv.rs @@ -5,10 +5,9 @@ use super::verification::{ VerificationReporterWithVecMpscSender, VerificationReportingProvider, }; use super::{ - get_current_cds_short_timestamp, EcssTcInMemConverter, EcssTcInSharedStoreConverter, - EcssTcInVecConverter, EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, - TmAsVecSenderWithBoundedMpsc, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, - TmInSharedPoolSenderWithMpsc, + EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, + EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, TmAsVecSenderWithBoundedMpsc, + TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithMpsc, }; use crate::pool::PoolProvider; use crate::pus::{PusPacketHandlerResult, PusPacketHandlingError}; @@ -76,6 +75,7 @@ impl< pub fn handle_one_tc( &mut self, + time_stamp: &[u8], sched_tc_pool: &mut (impl PoolProvider + ?Sized), ) -> Result { let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?; @@ -95,15 +95,14 @@ impl< ecss_tc_and_token.token, )); } - let mut partial_error = None; - let time_stamp = get_current_cds_short_timestamp(&mut partial_error); + let partial_error = None; match standard_subservice.unwrap() { scheduling::Subservice::TcEnableScheduling => { let start_token = self .service_helper .common .verification_handler - .start_success(ecss_tc_and_token.token, &time_stamp) + .start_success(ecss_tc_and_token.token, time_stamp) .expect("Error sending start success"); self.scheduler.enable(); @@ -111,7 +110,7 @@ impl< self.service_helper .common .verification_handler - .completion_success(start_token, &time_stamp) + .completion_success(start_token, time_stamp) .expect("Error sending completion success"); } else { return Err(PusPacketHandlingError::Other( @@ -124,7 +123,7 @@ impl< .service_helper .common .verification_handler - .start_success(ecss_tc_and_token.token, &time_stamp) + .start_success(ecss_tc_and_token.token, time_stamp) .expect("Error sending start success"); self.scheduler.disable(); @@ -132,7 +131,7 @@ impl< self.service_helper .common .verification_handler - .completion_success(start_token, &time_stamp) + .completion_success(start_token, time_stamp) .expect("Error sending completion success"); } else { return Err(PusPacketHandlingError::Other( @@ -145,7 +144,7 @@ impl< .service_helper .common .verification_handler - .start_success(ecss_tc_and_token.token, &time_stamp) + .start_success(ecss_tc_and_token.token, time_stamp) .expect("Error sending start success"); self.scheduler @@ -155,7 +154,7 @@ impl< self.service_helper .common .verification_handler - .completion_success(start_token, &time_stamp) + .completion_success(start_token, time_stamp) .expect("Error sending completion success"); } scheduling::Subservice::TcInsertActivity => { @@ -163,7 +162,7 @@ impl< .service_helper .common .verification_handler - .start_success(ecss_tc_and_token.token, &time_stamp) + .start_success(ecss_tc_and_token.token, time_stamp) .expect("error sending start success"); // let mut pool = self.sched_tc_pool.write().expect("locking pool failed"); @@ -174,7 +173,7 @@ impl< self.service_helper .common .verification_handler - .completion_success(start_token, &time_stamp) + .completion_success(start_token, time_stamp) .expect("sending completion success failed"); } _ => { @@ -241,7 +240,10 @@ mod tests { verification::{RequestId, TcStateAccepted, VerificationToken}, EcssTcInSharedStoreConverter, }; - use crate::pus::{MpscTcReceiver, TmInSharedPoolSenderWithBoundedMpsc}; + use crate::pus::{ + MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, + TmInSharedPoolSenderWithBoundedMpsc, + }; use alloc::collections::VecDeque; use delegate::delegate; use spacepackets::ecss::scheduling::Subservice; @@ -280,6 +282,12 @@ mod tests { sched_tc_pool, } } + + pub fn handle_one_tc(&mut self) -> Result { + let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); + self.handler + .handle_one_tc(&time_stamp, &mut self.sched_tc_pool) + } } impl PusTestHarness for Pus11HandlerWithStoreTester { @@ -347,9 +355,10 @@ mod tests { let token = test_harness.send_tc(&enable_scheduling); let request_id = token.req_id(); + let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); test_harness .handler - .handle_one_tc(&mut test_harness.sched_tc_pool) + .handle_one_tc(&time_stamp, &mut test_harness.sched_tc_pool) .unwrap(); test_harness.check_next_verification_tm(1, request_id); test_harness.check_next_verification_tm(3, request_id); @@ -407,10 +416,7 @@ mod tests { let token = test_harness.send_tc(&enable_scheduling); let request_id = token.req_id(); - test_harness - .handler - .handle_one_tc(&mut test_harness.sched_tc_pool) - .unwrap(); + test_harness.handle_one_tc().unwrap(); test_harness.check_next_verification_tm(1, request_id); test_harness.check_next_verification_tm(3, request_id); test_harness.check_next_verification_tm(7, request_id); diff --git a/satrs/src/pus/test.rs b/satrs/src/pus/test.rs index ea5a720..3828d3d 100644 --- a/satrs/src/pus/test.rs +++ b/satrs/src/pus/test.rs @@ -11,10 +11,9 @@ use super::verification::{ VerificationReporterWithVecMpscSender, VerificationReportingProvider, }; use super::{ - get_current_cds_short_timestamp, EcssTcInMemConverter, EcssTcInSharedStoreConverter, - EcssTcInVecConverter, EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, - TmAsVecSenderWithBoundedMpsc, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, - TmInSharedPoolSenderWithMpsc, + EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, + EcssTmSenderCore, MpscTcReceiver, PusServiceHelper, TmAsVecSenderWithBoundedMpsc, + TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithMpsc, }; /// This is a helper class for [std] environments to handle generic PUS 17 (test service) packets. @@ -47,7 +46,10 @@ impl< Self { service_helper } } - pub fn handle_one_tc(&mut self) -> Result { + pub fn handle_one_tc( + &mut self, + time_stamp: &[u8], + ) -> Result { let possible_packet = self.service_helper.retrieve_and_accept_next_packet()?; if possible_packet.is_none() { return Ok(PusPacketHandlerResult::Empty); @@ -62,12 +64,11 @@ impl< } if tc.subservice() == 1 { let mut partial_error = None; - let time_stamp = get_current_cds_short_timestamp(&mut partial_error); let result = self .service_helper .common .verification_handler - .start_success(ecss_tc_and_token.token, &time_stamp) + .start_success(ecss_tc_and_token.token, time_stamp) .map_err(|_| PartialPusHandlingError::Verification); let start_token = if let Ok(result) = result { Some(result) @@ -78,7 +79,7 @@ impl< // Sequence count will be handled centrally in TM funnel. let mut reply_header = SpHeader::tm_unseg(self.service_helper.common.tm_apid, 0, 0).unwrap(); - let tc_header = PusTmSecondaryHeader::new_simple(17, 2, &time_stamp); + let tc_header = PusTmSecondaryHeader::new_simple(17, 2, time_stamp); let ping_reply = PusTmCreator::new(&mut reply_header, tc_header, &[], true); let result = self .service_helper @@ -95,7 +96,7 @@ impl< .service_helper .common .verification_handler - .completion_success(start_token, &time_stamp) + .completion_success(start_token, time_stamp) .is_err() { partial_error = Some(PartialPusHandlingError::Verification) @@ -168,6 +169,7 @@ mod tests { use spacepackets::ecss::tc::{PusTcCreator, PusTcSecondaryHeader}; use spacepackets::ecss::tm::PusTmReader; use spacepackets::ecss::PusPacket; + use spacepackets::time::{cds, TimeWriter}; use spacepackets::{SequenceFlags, SpHeader}; use super::PusService17TestHandler; @@ -208,10 +210,9 @@ mod tests { } } impl SimplePusPacketHandler for Pus17HandlerWithStoreTester { - delegate! { - to self.handler { - fn handle_one_tc(&mut self) -> Result; - } + fn handle_one_tc(&mut self) -> Result { + let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); + self.handler.handle_one_tc(&time_stamp) } } @@ -251,10 +252,9 @@ mod tests { } } impl SimplePusPacketHandler for Pus17HandlerWithVecTester { - delegate! { - to self.handler { - fn handle_one_tc(&mut self) -> Result; - } + fn handle_one_tc(&mut self) -> Result { + let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap(); + self.handler.handle_one_tc(&time_stamp) } } diff --git a/satrs/src/time.rs b/satrs/src/time.rs new file mode 100644 index 0000000..abd3fac --- /dev/null +++ b/satrs/src/time.rs @@ -0,0 +1,7 @@ +use core::fmt::Debug; + +/// Generic abstraction for a check/countdown timer. +pub trait CountdownProvider: Debug { + fn has_expired(&self) -> bool; + fn reset(&mut self); +} diff --git a/satrs/tests/pus_targeted_request.rs b/satrs/tests/pus_targeted_request.rs new file mode 100644 index 0000000..eabc1f4 --- /dev/null +++ b/satrs/tests/pus_targeted_request.rs @@ -0,0 +1,148 @@ +use std::sync::mpsc; + +use satrs::{ + pus::{ + verification::{ + TcStateAccepted, VerificationReporterCfg, VerificationReporterWithVecMpscSender, + VerificationReportingProvider, VerificationToken, + }, + ActivePusRequest, DefaultActiveRequestMap, EcssTcInVecConverter, PusRequestRouter, + PusServiceReplyHandler, PusTargetedRequestHandler, PusTcToRequestConverter, + ReplyHandlerHook, TmAsVecSenderWithId, + }, + TargetId, +}; +use spacepackets::{ + ecss::{tc::PusTcReader, PusPacket}, + CcsdsPacket, +}; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum DummyRequest { + Ping, + WithParam(u32), +} + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum DummyReply { + Pong, +} + +pub struct DummyRequestConverter {} + +impl PusTcToRequestConverter for DummyRequestRouter { + type Error = (); + + fn convert( + &mut self, + token: VerificationToken, + tc: &PusTcReader, + time_stamp: &[u8], + verif_reporter: &impl VerificationReportingProvider, + ) -> Result<(TargetId, DummyRequest), Self::Error> { + if tc.service() == 205 && tc.subservice() == 1 { + return Ok((tc.apid().into(), DummyRequest::Ping)); + } + Err(()) + } +} + +pub struct DummyRequestRouter { + dummy_1_sender: mpsc::Sender, + dummy_2_sender: mpsc::Sender, +} + +impl PusRequestRouter for DummyRequestRouter { + type Error = (); + fn route( + &self, + target_id: TargetId, + request: DummyRequest, + token: VerificationToken, + ) -> Result<(), Self::Error> { + if target_id == DummyTargetId::Object1 as u64 { + self.dummy_1_sender.send(request).ok(); + } else { + self.dummy_2_sender.send(request).ok(); + } + Ok(()) + } + + fn handle_error( + &self, + target_id: TargetId, + token: VerificationToken, + tc: &PusTcReader, + error: Self::Error, + time_stamp: &[u8], + verif_reporter: &impl VerificationReportingProvider, + ) { + panic!("routing error"); + } +} + +#[derive(Default)] +pub struct DummyReplyUserHook {} + +impl ReplyHandlerHook for DummyReplyUserHook { + fn handle_unexpected_reply(&mut self, reply: &satrs::request::GenericMessage) { + todo!() + } + + fn timeout_callback(&self, active_request: &ActivePusRequest) { + todo!() + } + + fn timeout_error_code(&self) -> satrs_shared::res_code::ResultU16 { + todo!() + } +} + +pub type PusDummyRequestHandler = PusTargetedRequestHandler< + mpsc::Sender>, + mpsc::Sender>, + EcssTcInVecConverter, + VerificationReporterWithVecMpscSender, + DummyRequestConverter, + DummyRequestRouter, + DummyRequest, +>; +pub type PusDummyReplyHandler = PusServiceReplyHandler< + VerificationReporterWithVecMpscSender, + DefaultActiveRequestMap, + DummyReplyUserHook, + mpsc::Sender>, + ActivePusRequest, + DummyReply, +>; +const TEST_APID: u16 = 5; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum DummyTargetId { + Object1 = 1, + Object2 = 2, +} + +pub enum DummyChannelId { + Router = 1, + Object1 = 2, + Object2 = 3, +} + +fn main() { + let reporter_cfg = VerificationReporterCfg::new(TEST_APID, 2, 2, 256).unwrap(); + let (tm_sender, tm_receiver) = mpsc::channel(); + let tm_sender_with_wrapper = + TmAsVecSenderWithId::new(DummyChannelId::Router as u32, "ROUTER", tm_sender.clone()); + let verification_handler = + VerificationReporterWithVecMpscSender::new(&reporter_cfg, tm_sender_with_wrapper); + + // let dummy_request_handler = PusDummyRequestHandler::new() + let dummy_reply_handler = PusDummyReplyHandler::new_from_now( + verification_handler, + DefaultActiveRequestMap::default(), + 256, + DummyReplyUserHook::default(), + tm_sender.clone(), + ); +}