start adding docs
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
This commit is contained in:
parent
1fbb400809
commit
41db3b86da
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user