need to re-work all of this..
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
d2c4cd7428
commit
0f2a700ef1
@ -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: \
|
||||
|
@ -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<ActiveActionRequest, ActionReplyPusWithActionId> for ActionReplyHandler {
|
||||
type Error = ();
|
||||
|
||||
fn handle_unexpected_reply(
|
||||
&mut self,
|
||||
reply: &satrs::request::GenericMessage<ActionReplyPusWithActionId>,
|
||||
) {
|
||||
log::warn!("received unexpected reply for service {SERVICE}: {reply}");
|
||||
}
|
||||
|
||||
fn handle_reply(
|
||||
&mut self,
|
||||
reply: &satrs::request::GenericMessage<ActionReplyPusWithActionId>,
|
||||
verification_handler: &impl VerificationReportingProvider,
|
||||
tm_sender: &impl EcssTmSenderCore,
|
||||
) -> Result<bool, Self::Error> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +106,8 @@ impl<
|
||||
VerificationReporter: VerificationReportingProvider,
|
||||
> Pus5Wrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
|
||||
{
|
||||
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) => {
|
||||
|
@ -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<VerificationReporter: VerificationReportingProvider> PusReceiver<VerificationReporter> {
|
||||
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<RequestType>,
|
||||
ReplyHook: ReplyHandlerHook<RequestType, ReplyType>,
|
||||
ActiveRequestMap: ActiveRequestMapProvider<RequestType>,
|
||||
ActiveRequestType: ActiveRequestProvider,
|
||||
RequestType,
|
||||
ReplyType,
|
||||
> {
|
||||
pub service_helper:
|
||||
PusServiceHelper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
|
||||
pub request_router: GenericRequestRouter,
|
||||
pub request_converter: RequestConverter,
|
||||
pub active_request_map: ActiveRequestMap,
|
||||
pub reply_hook: ReplyHook,
|
||||
phantom: std::marker::PhantomData<RequestType>,
|
||||
}
|
||||
|
||||
impl<
|
||||
TcReceiver: EcssTcReceiverCore,
|
||||
TmSender: EcssTmSenderCore,
|
||||
TcInMemConverter: EcssTcInMemConverter,
|
||||
VerificationReporter: VerificationReportingProvider,
|
||||
RequestConverter: PusTcToRequestConverter<RequestType>,
|
||||
ReplyHandler: PusReplyHandler<ActiveRequestType, ReplyType>,
|
||||
ActiveRequestMap: ActiveRequestMapProvider<ActiveRequestType>,
|
||||
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<ReplyType>) {
|
||||
// self.reply_hook.insert_reply(reply, &self.active_request_map);
|
||||
}
|
||||
}
|
||||
|
||||
impl<VerificationReporter: VerificationReportingProvider> PusReceiver<VerificationReporter> {
|
||||
pub fn handle_tc_packet(
|
||||
&mut self,
|
||||
|
@ -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) => {
|
||||
|
@ -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 {
|
||||
|
@ -111,8 +111,8 @@ impl<
|
||||
VerificationReporter: VerificationReportingProvider,
|
||||
> Service17CustomWrapper<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>
|
||||
{
|
||||
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;
|
||||
|
@ -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<Box<dyn CheckTimer>>,
|
||||
current_check_timer: Option<Box<dyn CountdownProvider>>,
|
||||
}
|
||||
|
||||
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<AtomicBool>,
|
||||
}
|
||||
|
||||
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<dyn CheckTimer> {
|
||||
fn get_check_timer_provider(
|
||||
&self,
|
||||
timer_context: TimerContext,
|
||||
) -> Box<dyn CountdownProvider> {
|
||||
match timer_context {
|
||||
TimerContext::CheckLimit { .. } => {
|
||||
Box::new(TestCheckTimer::new(self.check_limit_expired_flag.clone()))
|
||||
|
@ -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<dyn CheckTimer>;
|
||||
fn get_check_timer_provider(&self, timer_context: TimerContext) -> Box<dyn CountdownProvider>;
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
|
@ -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;
|
||||
|
@ -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<ActiveActionRequest>;
|
||||
|
||||
/*
|
||||
/// Type definition for a PUS 8 action service reply handler which constrains the
|
||||
/// [PusServiceReplyHandler] active request and reply generics to the [ActiveActionRequest] and
|
||||
/// [ActionReplyPusWithIds] type.
|
||||
@ -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<TestVerificationReporter>,
|
||||
handler: PusService8ActionRequestHandler<
|
||||
pub struct PusDynRequestHandler<const SERVICE: u8, Request> {
|
||||
srv_helper: PusServiceHelper<
|
||||
MpscTcReceiver,
|
||||
TmAsVecSenderWithMpsc,
|
||||
EcssTcInVecConverter,
|
||||
TestVerificationReporter,
|
||||
TestConverter<8>,
|
||||
TestRouter<ActionRequest>,
|
||||
>,
|
||||
request_converter: TestConverter<SERVICE>,
|
||||
request_router: TestRouter<Request>,
|
||||
}
|
||||
|
||||
struct Pus8RequestTestbenchWithVec {
|
||||
common: PusServiceHandlerWithVecCommon<TestVerificationReporter>,
|
||||
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<PusPacketHandlerResult, PusPacketHandlingError>;
|
||||
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
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);
|
||||
|
@ -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<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
pub fn handle_one_tc(
|
||||
&mut self,
|
||||
time_stamp: &[u8],
|
||||
) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
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<PusPacketHandlerResult, PusPacketHandlingError>;
|
||||
}
|
||||
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap();
|
||||
self.handler.handle_one_tc(&time_stamp)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<TcStateAccepted>,
|
||||
) -> 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<HkRequest> {
|
||||
type Error = GenericRoutingError;
|
||||
|
||||
fn route(
|
||||
&self,
|
||||
target_id: TargetId,
|
||||
hk_request: HkRequest,
|
||||
_token: VerificationToken<TcStateAccepted>,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.routing_requests
|
||||
.borrow_mut()
|
||||
.push_back((target_id, hk_request));
|
||||
self.check_for_injected_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl PusTcToRequestConverter<HkRequest> for TestConverter<3> {
|
||||
type Error = PusPacketHandlingError;
|
||||
fn convert(
|
||||
&mut self,
|
||||
token: VerificationToken<TcStateAccepted>,
|
||||
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<TestVerificationReporter>,
|
||||
handler: PusService3HkRequestHandler<
|
||||
MpscTcReceiver,
|
||||
TmAsVecSenderWithMpsc,
|
||||
EcssTcInVecConverter,
|
||||
TestVerificationReporter,
|
||||
TestConverter<3>,
|
||||
TestRouter<HkRequest>,
|
||||
>,
|
||||
}
|
||||
|
||||
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<TcStateAccepted>;
|
||||
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<PusPacketHandlerResult, PusPacketHandlingError>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
}
|
@ -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<TcStateStarted>,
|
||||
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<ActiveRequestType, ReplyType> {
|
||||
fn handle_unexpected_reply(&mut self, reply: &GenericMessage<ReplyType>);
|
||||
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<Request> {
|
||||
type Error;
|
||||
|
||||
fn route(
|
||||
&self,
|
||||
target_id: TargetId,
|
||||
hk_request: Request,
|
||||
token: VerificationToken<TcStateAccepted>,
|
||||
) -> Result<(), Self::Error>;
|
||||
|
||||
fn handle_error(
|
||||
&self,
|
||||
target_id: TargetId,
|
||||
@ -358,6 +345,23 @@ pub trait PusRequestRouter<Request> {
|
||||
);
|
||||
}
|
||||
|
||||
pub trait PusReplyHandler<ActiveRequestInfo: ActiveRequestProvider, ReplyType> {
|
||||
type Error;
|
||||
|
||||
fn handle_reply(
|
||||
&mut self,
|
||||
reply: &GenericMessage<ReplyType>,
|
||||
verification_handler: &impl VerificationReportingProvider,
|
||||
tm_sender: &impl EcssTmSenderCore,
|
||||
) -> Result<bool, Self::Error>;
|
||||
|
||||
fn handle_unexpected_reply(
|
||||
&mut self,
|
||||
reply: &GenericMessage<ReplyType>,
|
||||
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<Request> {
|
||||
pub trait PusTcToRequestConverter<ActiveRequestInfo, Request> {
|
||||
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<ActiveRequestType>,
|
||||
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
|
||||
TmSender: EcssTmSenderCore,
|
||||
ReplyHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
|
||||
ActiveRequestType: ActiveRequestProvider,
|
||||
ReplyType,
|
||||
> {
|
||||
pub active_request_map: ActiveRequestMap,
|
||||
pub verification_reporter: VerificationReporter,
|
||||
pub tm_buf: alloc::vec::Vec<u8>,
|
||||
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<ActiveRequestType>,
|
||||
UserHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
|
||||
TmSender: EcssTmSenderCore,
|
||||
ReplyHook: ReplyHandlerHook<ActiveRequestType, ReplyType>,
|
||||
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<Self, std::time::SystemTimeError> {
|
||||
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<mpsc::SendError<StoreAddr>> for EcssTmtcError {
|
||||
fn from(_: mpsc::SendError<StoreAddr>) -> 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<TcReceiver, TmSender, TcInMemConverter, VerificationReporter>,
|
||||
pub request_converter: RequestConverter,
|
||||
pub request_router: RequestRouter,
|
||||
// pub routing_error_handler: RoutingErrorHandler,
|
||||
phantom: PhantomData<Request>,
|
||||
}
|
||||
|
||||
// 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<Request, Error = PusPacketHandlingError>,
|
||||
RequestRouter: PusRequestRouter<Request, Error = RoutingError>,
|
||||
// RoutingErrorHandler: PusRoutingErrorHandler<Error = RoutingError>,
|
||||
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<PartialPusHandlingError>,
|
||||
) -> [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.
|
||||
///
|
||||
|
@ -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<ActiveRequest, ModeReply> {
|
||||
pub trait ModeReplyHook: ReplyHandlerHook<ActivePusRequest, ModeReply> {
|
||||
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<ActiveRequest>,
|
||||
ActiveRequestMap: ActiveRequestMapProvider<ActivePusRequest>,
|
||||
UserHook: ModeReplyHook,
|
||||
TmSender: EcssTmSenderCore,
|
||||
> PusModeServiceReplyHandler<VerificationReporter, ActiveRequestMap, UserHook, TmSender>
|
||||
@ -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,
|
||||
|
@ -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<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
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<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
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);
|
||||
|
@ -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<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
pub fn handle_one_tc(
|
||||
&mut self,
|
||||
time_stamp: &[u8],
|
||||
) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
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<PusPacketHandlerResult, PusPacketHandlingError>;
|
||||
}
|
||||
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
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<PusPacketHandlerResult, PusPacketHandlingError>;
|
||||
}
|
||||
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
|
||||
let time_stamp = cds::TimeProvider::new_with_u16_days(0, 0).to_vec().unwrap();
|
||||
self.handler.handle_one_tc(&time_stamp)
|
||||
}
|
||||
}
|
||||
|
||||
|
7
satrs/src/time.rs
Normal file
7
satrs/src/time.rs
Normal file
@ -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);
|
||||
}
|
148
satrs/tests/pus_targeted_request.rs
Normal file
148
satrs/tests/pus_targeted_request.rs
Normal file
@ -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<DummyRequest> for DummyRequestRouter {
|
||||
type Error = ();
|
||||
|
||||
fn convert(
|
||||
&mut self,
|
||||
token: VerificationToken<TcStateAccepted>,
|
||||
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<DummyRequest>,
|
||||
dummy_2_sender: mpsc::Sender<DummyRequest>,
|
||||
}
|
||||
|
||||
impl PusRequestRouter<DummyRequest> for DummyRequestRouter {
|
||||
type Error = ();
|
||||
fn route(
|
||||
&self,
|
||||
target_id: TargetId,
|
||||
request: DummyRequest,
|
||||
token: VerificationToken<TcStateAccepted>,
|
||||
) -> 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<TcStateAccepted>,
|
||||
tc: &PusTcReader,
|
||||
error: Self::Error,
|
||||
time_stamp: &[u8],
|
||||
verif_reporter: &impl VerificationReportingProvider,
|
||||
) {
|
||||
panic!("routing error");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DummyReplyUserHook {}
|
||||
|
||||
impl ReplyHandlerHook<ActivePusRequest, DummyReply> for DummyReplyUserHook {
|
||||
fn handle_unexpected_reply(&mut self, reply: &satrs::request::GenericMessage<DummyReply>) {
|
||||
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<Vec<u8>>,
|
||||
mpsc::Sender<Vec<u8>>,
|
||||
EcssTcInVecConverter,
|
||||
VerificationReporterWithVecMpscSender,
|
||||
DummyRequestConverter,
|
||||
DummyRequestRouter,
|
||||
DummyRequest,
|
||||
>;
|
||||
pub type PusDummyReplyHandler = PusServiceReplyHandler<
|
||||
VerificationReporterWithVecMpscSender,
|
||||
DefaultActiveRequestMap<ActivePusRequest>,
|
||||
DummyReplyUserHook,
|
||||
mpsc::Sender<Vec<u8>>,
|
||||
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(),
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user