start adding docs
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit

This commit is contained in:
Robin Müller 2024-03-12 15:49:07 +01:00
parent 1fbb400809
commit 41db3b86da
3 changed files with 229 additions and 270 deletions

View File

@ -101,40 +101,40 @@ pub trait ListenerMapProvider {
} }
pub trait SenderMapProvider< pub trait SenderMapProvider<
SP: EventSendProvider<EV, AUX>, EventSender: EventSendProvider<Ev, Data>,
EV: GenericEvent = EventU32, Ev: GenericEvent = EventU32,
AUX = Params, Data = Params,
> >
{ {
fn contains_send_event_provider(&self, id: &ChannelId) -> bool; fn contains_send_event_provider(&self, id: &ChannelId) -> bool;
fn get_send_event_provider(&self, id: &ChannelId) -> Option<&SP>; fn get_send_event_provider(&self, id: &ChannelId) -> Option<&EventSender>;
fn add_send_event_provider(&mut self, send_provider: SP) -> bool; fn add_send_event_provider(&mut self, send_provider: EventSender) -> bool;
} }
/// Generic event manager implementation. /// Generic event manager implementation.
/// ///
/// # Generics /// # Generics
/// ///
/// * `ERP`: [EventReceiveProvider] used to receive all events. /// * `EventReceiver`: [EventReceiveProvider] used to receive all events.
/// * `SMP`: [SenderMapProvider] which maps channel IDs to send providers. /// * `SenderMap`: [SenderMapProvider] which maps channel IDs to send providers.
/// * `LTR`: [ListenerMapProvider] which maps listener keys to channel IDs. /// * `ListenerMap`: [ListenerMapProvider] which maps listener keys to channel IDs.
/// * `SP`: [EventSendProvider] contained within the sender map which sends the events. /// * `EventSender`: [EventSendProvider] contained within the sender map which sends the events.
/// * `EV`: The event type. This type must implement the [GenericEvent]. Currently only [EventU32] /// * `Ev`: The event type. This type must implement the [GenericEvent]. Currently only [EventU32]
/// and [EventU16] are supported. /// and [EventU16] are supported.
/// * `AUX`: Auxiliary data which is sent with the event to provide optional context information /// * `Data`: Auxiliary data which is sent with the event to provide optional context information
pub struct EventManager< pub struct EventManager<
ERP: EventReceiveProvider<EV, AUX>, EventReceiver: EventReceiveProvider<Ev, Data>,
SMP: SenderMapProvider<SP, EV, AUX>, SenderMap: SenderMapProvider<EventSender, Ev, Data>,
LTR: ListenerMapProvider, ListenerMap: ListenerMapProvider,
SP: EventSendProvider<EV, AUX>, EventSender: EventSendProvider<Ev, Data>,
EV: GenericEvent = EventU32, Ev: GenericEvent = EventU32,
AUX = Params, Data = Params,
> { > {
event_receiver: ERP, event_receiver: EventReceiver,
sender_map: SMP, sender_map: SenderMap,
listener_map: LTR, listener_map: ListenerMap,
phantom: core::marker::PhantomData<(SP, EV, AUX)>, phantom: core::marker::PhantomData<(EventSender, Ev, Data)>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -157,26 +157,26 @@ pub enum EventRoutingError {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct EventRoutingErrorsWithResult<EV: GenericEvent, AUX> { pub struct EventRoutingErrorsWithResult<Ev: GenericEvent, Data> {
pub result: EventRoutingResult<EV, AUX>, pub result: EventRoutingResult<Ev, Data>,
pub errors: [Option<EventRoutingError>; 3], pub errors: [Option<EventRoutingError>; 3],
} }
impl< impl<
ER: EventReceiveProvider<EV, AUX>, EventReceiver: EventReceiveProvider<Ev, Data>,
S: SenderMapProvider<SP, EV, AUX>, SenderMap: SenderMapProvider<EventSender, Ev, Data>,
L: ListenerMapProvider, ListenerMap: ListenerMapProvider,
SP: EventSendProvider<EV, AUX>, EventSender: EventSendProvider<Ev, Data>,
EV: GenericEvent + Copy, Ev: GenericEvent + Copy,
AUX: Clone, Data: Clone,
> EventManager<ER, S, L, SP, EV, AUX> > EventManager<EventReceiver, SenderMap, ListenerMap, EventSender, Ev, Data>
{ {
pub fn remove_duplicates(&mut self, key: &ListenerKey) { pub fn remove_duplicates(&mut self, key: &ListenerKey) {
self.listener_map.remove_duplicates(key) self.listener_map.remove_duplicates(key)
} }
/// Subscribe for a unique event. /// Subscribe for a unique event.
pub fn subscribe_single(&mut self, event: &EV, sender_id: ChannelId) { pub fn subscribe_single(&mut self, event: &Ev, sender_id: ChannelId) {
self.update_listeners(ListenerKey::Single(event.raw_as_largest_type()), sender_id); self.update_listeners(ListenerKey::Single(event.raw_as_largest_type()), sender_id);
} }

View File

@ -129,15 +129,13 @@ pub mod std_mod {
verification::{ verification::{
self, FailParams, FailParamsWithStep, TcStateStarted, VerificationReportingProvider, self, FailParams, FailParamsWithStep, TcStateStarted, VerificationReportingProvider,
}, },
ActiveRequestMapProvider, ActiveRequestProvider, DefaultActiveRequestMap, ActiveRequestMapProvider, DefaultActiveRequestMap, EcssTcInMemConverter,
EcssTcInMemConverter, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, EcssTcReceiverCore, EcssTmSenderCore, EcssTmtcError, GenericRoutingError,
GenericRoutingError, PusPacketHandlerResult, PusPacketHandlingError, PusPacketHandlerResult, PusPacketHandlingError, PusRoutingErrorHandler,
PusRoutingErrorHandler, PusServiceHelper, PusServiceHelper, PusServiceReplyHandler, ReplyHandlerHook,
}, },
request::RequestId,
}; };
use core::{marker::PhantomData, time::Duration}; use core::time::Duration;
use delegate::delegate;
use spacepackets::time::UnixTimestamp; use spacepackets::time::UnixTimestamp;
use std::time::SystemTimeError; use std::time::SystemTimeError;
@ -252,160 +250,17 @@ pub mod std_mod {
pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap<ActiveActionRequest>; pub type DefaultActiveActionRequestMap = DefaultActiveRequestMap<ActiveActionRequest>;
pub trait ReplyHandlerHook<ActiveRequestType, Reply> { /// Type definition for a PUS 8 action service reply handler which constrains the
fn handle_unexpected_reply(&mut self, reply: &Reply); /// [PusServiceReplyHandler] active request and reply generics to the [ActiveActionRequest] and
fn timeout_callback(&self, active_request: &ActiveRequestType); /// [ActionReplyPusWithIds] type.
fn timeout_error_code(&self) -> ResultU16;
}
pub struct PusServiceReplyHandler<
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
UserHook: ReplyHandlerHook<ActiveRequestType, Reply>,
ActiveRequestType: ActiveRequestProvider,
Reply,
> {
active_request_map: ActiveRequestMap,
verification_reporter: VerificationReporter,
fail_data_buf: alloc::vec::Vec<u8>,
current_time: UnixTimestamp,
pub user_hook: UserHook,
phantom: PhantomData<(ActiveRequestType, Reply)>,
}
impl<
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
ActiveRequestType: ActiveRequestProvider,
ReplyType,
>
PusServiceReplyHandler<
VerificationReporter,
ActiveRequestMap,
UserHook,
ActiveRequestType,
ReplyType,
>
{
#[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,
) -> Result<Self, SystemTimeError> {
let current_time = UnixTimestamp::from_now()?;
Ok(Self::new(
verification_reporter,
active_request_map,
fail_data_buf_size,
user_hook,
current_time,
))
}
pub fn new(
verification_reporter: VerificationReporter,
active_request_map: ActiveRequestMap,
fail_data_buf_size: usize,
user_hook: UserHook,
init_time: UnixTimestamp,
) -> Self {
Self {
active_request_map,
verification_reporter,
fail_data_buf: alloc::vec![0; fail_data_buf_size],
current_time: init_time,
user_hook,
phantom: PhantomData,
}
}
pub fn add_routed_request(
&mut self,
request_id: verification::RequestId,
active_request_type: ActiveRequestType,
) {
self.active_request_map
.insert(&request_id.into(), active_request_type);
}
pub fn request_active(&self, request_id: RequestId) -> bool {
self.active_request_map.get(request_id).is_some()
}
/// Check for timeouts across all active requests.
///
/// It will call [Self::handle_timeout] for all active requests which have timed out.
pub fn check_for_timeouts(&mut self, time_stamp: &[u8]) -> Result<(), EcssTmtcError> {
let mut timed_out_commands = alloc::vec::Vec::new();
self.active_request_map.for_each(|request_id, active_req| {
let diff = self.current_time - active_req.start_time();
if diff.duration_absolute > active_req.timeout() {
self.handle_timeout(active_req, time_stamp);
}
timed_out_commands.push(*request_id);
});
for timed_out_command in timed_out_commands {
self.active_request_map.remove(timed_out_command);
}
Ok(())
}
/// Handle the timeout for a given active request.
///
/// This implementation will report a verification completion failure with a user-provided
/// error code. It supplies the configured request timeout in milliseconds as a [u64]
/// serialized in big-endian format as the failure data.
pub fn handle_timeout(&self, active_request: &ActiveRequestType, time_stamp: &[u8]) {
let timeout = active_request.timeout().as_millis() as u64;
let timeout_raw = timeout.to_be_bytes();
self.verification_reporter
.completion_failure(
active_request.token(),
FailParams::new(
time_stamp,
&self.user_hook.timeout_error_code(),
&timeout_raw,
),
)
.unwrap();
self.user_hook.timeout_callback(active_request);
}
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn update_time_from_now(&mut self) -> Result<(), SystemTimeError> {
self.current_time = UnixTimestamp::from_now()?;
Ok(())
}
}
pub type PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook> = pub type PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook> =
PusServiceReplyHandler< PusServiceReplyHandler<
VerificationReporter, VerificationReporter,
DefaultActiveActionRequestMap, ActiveRequestMap,
UserHook, UserHook,
ActiveActionRequest, ActiveActionRequest,
ActionReplyPusWithIds, ActionReplyPusWithIds,
>; >;
/*
pub struct PusService8ReplyHandler<
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveActionRequest>,
UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>,
> {
pub inner: PusServiceReplyHandler<
VerificationReporter,
ActiveRequestMap,
UserHook,
ActiveActionRequest,
ActionReplyPusWithIds,
>,
}
*/
impl< impl<
VerificationReporter: VerificationReportingProvider, VerificationReporter: VerificationReportingProvider,
@ -413,43 +268,8 @@ pub mod std_mod {
UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>, UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>,
> PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook> > PusService8ReplyHandler<VerificationReporter, ActiveRequestMap, UserHook>
{ {
#[cfg(feature = "std")] /// Helper method to register a recently routed action request.
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] pub fn add_routed_action_request(
pub fn new_from_now(
verification_reporter: VerificationReporter,
active_request_map: ActiveRequestMap,
fail_data_buf_size: usize,
user_hook: UserHook,
) -> Result<Self, SystemTimeError> {
let current_time = UnixTimestamp::from_now()?;
Ok(Self::new(
verification_reporter,
active_request_map,
fail_data_buf_size,
user_hook,
current_time,
))
}
pub fn new(
verification_reporter: VerificationReporter,
active_request_map: ActiveRequestMap,
fail_data_buf_size: usize,
user_hook: UserHook,
init_time: UnixTimestamp,
) -> Self {
Self {
inner: PusServiceReplyHandler::new(
verification_reporter,
active_request_map,
fail_data_buf_size,
user_hook,
init_time,
),
}
}
pub fn add_routed_request(
&mut self, &mut self,
request_id: verification::RequestId, request_id: verification::RequestId,
target_id: TargetId, target_id: TargetId,
@ -457,68 +277,45 @@ pub mod std_mod {
token: VerificationToken<TcStateStarted>, token: VerificationToken<TcStateStarted>,
timeout: Duration, timeout: Duration,
) { ) {
self.inner.active_request_map.insert( self.active_request_map.insert(
&request_id.into(), &request_id.into(),
ActiveActionRequest { ActiveActionRequest {
action_id, action_id,
common: ActiveRequest { common: ActiveRequest {
target_id, target_id,
token, token,
start_time: self.inner.current_time, start_time: self.current_time,
timeout, timeout,
}, },
}, },
); );
} }
delegate! { /// Main handler function to handle all received action replies.
to self.inner {
pub fn request_active(&self, request_id: RequestId) -> bool;
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn update_time_from_now(&mut self) -> Result<(), SystemTimeError>;
/// Check for timeouts across all active requests.
///
/// It will call [Self::handle_timeout] for all active requests which have timed out.
pub fn check_for_timeouts(&mut self, time_stamp: &[u8]) -> Result<(), EcssTmtcError>;
/// Handle the timeout for a given active request.
///
/// This implementation will report a verification completion failure with a user-provided
/// error code. It supplies the configured request timeout in milliseconds as a [u64]
/// serialized in big-endian format as the failure data.
pub fn handle_timeout(&self, active_request: &ActiveActionRequest, time_stamp: &[u8]);
}
}
pub fn handle_action_reply( pub fn handle_action_reply(
&mut self, &mut self,
action_reply_with_ids: ActionReplyPusWithIds, action_reply_with_ids: ActionReplyPusWithIds,
time_stamp: &[u8], time_stamp: &[u8],
) -> Result<(), EcssTmtcError> { ) -> Result<(), EcssTmtcError> {
let active_req = self let active_req = self
.inner
.active_request_map .active_request_map
.get(action_reply_with_ids.request_id); .get(action_reply_with_ids.request_id);
if active_req.is_none() { if active_req.is_none() {
self.inner self.user_hook
.user_hook
.handle_unexpected_reply(&action_reply_with_ids); .handle_unexpected_reply(&action_reply_with_ids);
return Ok(()); return Ok(());
} }
let active_req = active_req.unwrap().clone(); let active_req = active_req.unwrap().clone();
let remove_entry = match action_reply_with_ids.reply { let remove_entry = match action_reply_with_ids.reply {
ActionReplyPus::CompletionFailed { error_code, params } => { ActionReplyPus::CompletionFailed { error_code, params } => {
let fail_data_len = params.write_to_be_bytes(&mut self.inner.fail_data_buf)?; let fail_data_len = params.write_to_be_bytes(&mut self.fail_data_buf)?;
self.inner self.verification_reporter
.verification_reporter
.completion_failure( .completion_failure(
active_req.common.token, active_req.common.token,
FailParams::new( FailParams::new(
time_stamp, time_stamp,
&error_code, &error_code,
&self.inner.fail_data_buf[..fail_data_len], &self.fail_data_buf[..fail_data_len],
), ),
) )
.map_err(|e| e.0)?; .map_err(|e| e.0)?;
@ -529,30 +326,28 @@ pub mod std_mod {
step, step,
params, params,
} => { } => {
let fail_data_len = params.write_to_be_bytes(&mut self.inner.fail_data_buf)?; let fail_data_len = params.write_to_be_bytes(&mut self.fail_data_buf)?;
self.inner self.verification_reporter
.verification_reporter
.step_failure( .step_failure(
active_req.common.token, active_req.common.token,
FailParamsWithStep::new( FailParamsWithStep::new(
time_stamp, time_stamp,
&EcssEnumU16::new(step), &EcssEnumU16::new(step),
&error_code, &error_code,
&self.inner.fail_data_buf[..fail_data_len], &self.fail_data_buf[..fail_data_len],
), ),
) )
.map_err(|e| e.0)?; .map_err(|e| e.0)?;
true true
} }
ActionReplyPus::Completed => { ActionReplyPus::Completed => {
self.inner self.verification_reporter
.verification_reporter
.completion_success(active_req.common.token, time_stamp) .completion_success(active_req.common.token, time_stamp)
.map_err(|e| e.0)?; .map_err(|e| e.0)?;
true true
} }
ActionReplyPus::StepSuccess { step } => { ActionReplyPus::StepSuccess { step } => {
self.inner.verification_reporter.step_success( self.verification_reporter.step_success(
&active_req.common.token, &active_req.common.token,
time_stamp, time_stamp,
EcssEnumU16::new(step), EcssEnumU16::new(step),
@ -561,8 +356,7 @@ pub mod std_mod {
} }
}; };
if remove_entry { if remove_entry {
self.inner self.active_request_map
.active_request_map
.remove(action_reply_with_ids.request_id); .remove(action_reply_with_ids.request_id);
} }
Ok(()) Ok(())
@ -574,6 +368,9 @@ pub mod std_mod {
UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>, UserHook: ReplyHandlerHook<ActiveActionRequest, ActionReplyPusWithIds>,
> PusService8ReplyHandler<VerificationReporter, DefaultActiveActionRequestMap, UserHook> > PusService8ReplyHandler<VerificationReporter, DefaultActiveActionRequestMap, UserHook>
{ {
/// Create a new PUS Service 8 reply handler with the [ActiveRequestMap] generic
/// constrained to the [DefaultActiveActionRequestMap] object and with the current time
/// set to the OS time.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn new_from_now_with_default_map( pub fn new_from_now_with_default_map(
@ -590,6 +387,8 @@ pub mod std_mod {
)) ))
} }
/// Create a new PUS Service 8 reply handler with the [ActiveRequestMap] generic
/// constrained to the [DefaultActiveActionRequestMap] object.
pub fn new_with_default_map( pub fn new_with_default_map(
verification_reporter: VerificationReporter, verification_reporter: VerificationReporter,
fail_data_buf_size: usize, fail_data_buf_size: usize,
@ -638,7 +437,8 @@ mod tests {
FailParams, TcStateNone, TcStateStarted, VerificationReportingProvider, FailParams, TcStateNone, TcStateStarted, VerificationReportingProvider,
}, },
EcssTcInVecConverter, EcssTmtcError, GenericRoutingError, MpscTcReceiver, EcssTcInVecConverter, EcssTmtcError, GenericRoutingError, MpscTcReceiver,
PusPacketHandlerResult, PusPacketHandlingError, TmAsVecSenderWithMpsc, PusPacketHandlerResult, PusPacketHandlingError, ReplyHandlerHook,
TmAsVecSenderWithMpsc,
}, },
}; };
@ -859,12 +659,7 @@ mod tests {
} }
pub fn next_unrequested_reply(&self) -> Option<ActionReplyPusWithIds> { pub fn next_unrequested_reply(&self) -> Option<ActionReplyPusWithIds> {
self.handler self.handler.user_hook.unexpected_replies.front().cloned()
.inner
.user_hook
.unexpected_replies
.front()
.cloned()
} }
pub fn assert_request_completion_success(&self, step: Option<u16>, request_id: RequestId) { pub fn assert_request_completion_success(&self, step: Option<u16>, request_id: RequestId) {
@ -931,7 +726,7 @@ mod tests {
panic!("request already present"); panic!("request already present");
} }
self.handler self.handler
.add_routed_request(request_id, target_id, action_id, token, timeout); .add_routed_action_request(request_id, target_id, action_id, token, timeout);
if !self.handler.request_active(request_id.into()) { if !self.handler.request_active(request_id.into()) {
panic!("request should be active now"); panic!("request should be active now");
} }

View File

@ -8,11 +8,13 @@ use crate::queue::{GenericReceiveError, GenericSendError};
use crate::request::RequestId; use crate::request::RequestId;
use crate::{ChannelId, TargetId}; use crate::{ChannelId, TargetId};
use core::fmt::{Display, Formatter}; use core::fmt::{Display, Formatter};
use core::marker::PhantomData;
use core::time::Duration; use core::time::Duration;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use downcast_rs::{impl_downcast, Downcast}; use downcast_rs::{impl_downcast, Downcast};
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use dyn_clone::DynClone; use dyn_clone::DynClone;
use satrs_shared::res_code::ResultU16;
use spacepackets::time::UnixTimestamp; use spacepackets::time::UnixTimestamp;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::error::Error; use std::error::Error;
@ -42,7 +44,7 @@ pub use alloc_mod::*;
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub use std_mod::*; pub use std_mod::*;
use self::verification::TcStateStarted; use self::verification::{FailParams, TcStateStarted, VerificationReportingProvider};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum PusTmWrapper<'tm> { pub enum PusTmWrapper<'tm> {
@ -464,6 +466,168 @@ mod alloc_mod {
} }
} }
/// 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<ActiveRequestType, ReplyType> {
fn handle_unexpected_reply(&mut self, reply: &ReplyType);
fn timeout_callback(&self, active_request: &ActiveRequestType);
fn timeout_error_code(&self) -> ResultU16;
}
/// 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.
/// The reply handler performs boilerplate tasks like performing the verification handling and
/// timeout handling.
///
/// This object is not useful by itself but serves as a common building block for high-level
/// 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.
///
/// 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.
pub struct PusServiceReplyHandler<
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
ActiveRequestType: ActiveRequestProvider,
ReplyType,
> {
active_request_map: ActiveRequestMap,
verification_reporter: VerificationReporter,
fail_data_buf: alloc::vec::Vec<u8>,
current_time: UnixTimestamp,
pub user_hook: UserHook,
phantom: PhantomData<(ActiveRequestType, ReplyType)>,
}
impl<
VerificationReporter: VerificationReportingProvider,
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
ActiveRequestType: ActiveRequestProvider,
ReplyType,
>
PusServiceReplyHandler<
VerificationReporter,
ActiveRequestMap,
UserHook,
ActiveRequestType,
ReplyType,
>
{
#[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,
) -> Result<Self, std::time::SystemTimeError> {
let current_time = UnixTimestamp::from_now()?;
Ok(Self::new(
verification_reporter,
active_request_map,
fail_data_buf_size,
user_hook,
current_time,
))
}
pub fn new(
verification_reporter: VerificationReporter,
active_request_map: ActiveRequestMap,
fail_data_buf_size: usize,
user_hook: UserHook,
init_time: UnixTimestamp,
) -> Self {
Self {
active_request_map,
verification_reporter,
fail_data_buf: alloc::vec![0; fail_data_buf_size],
current_time: init_time,
user_hook,
phantom: PhantomData,
}
}
pub fn add_routed_request(
&mut self,
request_id: verification::RequestId,
active_request_type: ActiveRequestType,
) {
self.active_request_map
.insert(&request_id.into(), active_request_type);
}
pub fn request_active(&self, request_id: RequestId) -> bool {
self.active_request_map.get(request_id).is_some()
}
/// Check for timeouts across all active requests.
///
/// It will call [Self::handle_timeout] for all active requests which have timed out.
pub fn check_for_timeouts(&mut self, time_stamp: &[u8]) -> Result<(), EcssTmtcError> {
let mut timed_out_commands = alloc::vec::Vec::new();
self.active_request_map.for_each(|request_id, active_req| {
let diff = self.current_time - active_req.start_time();
if diff.duration_absolute > active_req.timeout() {
self.handle_timeout(active_req, time_stamp);
}
timed_out_commands.push(*request_id);
});
for timed_out_command in timed_out_commands {
self.active_request_map.remove(timed_out_command);
}
Ok(())
}
/// Handle the timeout for a given active request.
///
/// This implementation will report a verification completion failure with a user-provided
/// error code. It supplies the configured request timeout in milliseconds as a [u64]
/// serialized in big-endian format as the failure data.
pub fn handle_timeout(&self, active_request: &ActiveRequestType, time_stamp: &[u8]) {
let timeout = active_request.timeout().as_millis() as u64;
let timeout_raw = timeout.to_be_bytes();
self.verification_reporter
.completion_failure(
active_request.token(),
FailParams::new(
time_stamp,
&self.user_hook.timeout_error_code(),
&timeout_raw,
),
)
.unwrap();
self.user_hook.timeout_callback(active_request);
}
/// Update the current time used for timeout checks based on the current OS time.
#[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub fn update_time_from_now(&mut self) -> Result<(), std::time::SystemTimeError> {
self.current_time = UnixTimestamp::from_now()?;
Ok(())
}
/// Update the current time used for timeout checks.
pub fn update_time(&mut self, time: UnixTimestamp) {
self.current_time = time;
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))]
pub mod std_mod { pub mod std_mod {