use log::{error, warn}; use satrs::hk::{CollectionIntervalFactor, HkRequest}; use satrs::pool::{SharedStaticMemoryPool, StoreAddr}; use satrs::pus::verification::{ FailParams, TcStateAccepted, VerificationReporterWithSharedPoolMpscBoundedSender, VerificationReporterWithVecMpscSender, VerificationReportingProvider, VerificationToken, }; use satrs::pus::{ ActivePusRequest, ActiveRequestProvider, DefaultActiveRequestMap, EcssTcAndToken, EcssTcInMemConverter, EcssTcInSharedStoreConverter, EcssTcInVecConverter, EcssTcReceiverCore, EcssTmSenderCore, MpscTcReceiver, PusPacketHandlerResult, PusPacketHandlingError, PusReplyHandler, PusServiceHelper, PusTcToRequestConverter, TmAsVecSenderWithId, TmAsVecSenderWithMpsc, TmInSharedPoolSenderWithBoundedMpsc, TmInSharedPoolSenderWithId, }; use satrs::request::TargetAndApidId; use satrs::spacepackets::ecss::tc::PusTcReader; use satrs::spacepackets::ecss::{hk, PusPacket}; use satrs::spacepackets::time::UnixTimestamp; use satrs::tmtc::tm_helper::SharedTmPool; use satrs::{ChannelId, TargetId}; use satrs_example::config::{hk_err, tmtc_err, TcReceiverId, TmSenderId, PUS_APID}; use std::sync::mpsc::{self}; use std::time::Duration; use crate::requests::GenericRequestRouter; use super::PusTargetedRequestService; #[derive(Clone, PartialEq, Debug)] pub enum HkReply { Ack, } pub struct HkReplyHandler { fail_data_buf: [u8; 128], } impl Default for HkReplyHandler { fn default() -> Self { Self { fail_data_buf: [0; 128], } } } impl PusReplyHandler for HkReplyHandler { type Error = (); fn handle_unexpected_reply( &mut self, reply: &satrs::request::GenericMessage, tm_sender: &impl EcssTmSenderCore, ) { log::warn!("received unexpected reply for service 3: {reply:?}"); } fn handle_reply( &mut self, reply: &satrs::request::GenericMessage, active_request: &ActivePusRequest, verification_handler: &impl VerificationReportingProvider, time_stamp: &[u8], tm_sender: &impl EcssTmSenderCore, ) -> Result { let remove_entry = match reply.message { HkReply::Ack => { verification_handler .completion_success(active_request.token(), time_stamp) .expect("Sending end success TM failed"); true } }; Ok(remove_entry) } } #[derive(Default)] pub struct ExampleHkRequestConverter {} impl PusTcToRequestConverter for ExampleHkRequestConverter { type Error = PusPacketHandlingError; fn convert( &mut self, token: VerificationToken, tc: &PusTcReader, time_stamp: &[u8], verif_reporter: &impl VerificationReportingProvider, ) -> Result<(ActivePusRequest, HkRequest), Self::Error> { let user_data = tc.user_data(); if user_data.is_empty() { let user_data_len = user_data.len() as u32; let user_data_len_raw = user_data_len.to_be_bytes(); verif_reporter .start_failure( token, FailParams::new( time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, &user_data_len_raw, ), ) .expect("Sending start failure TM failed"); return Err(PusPacketHandlingError::NotEnoughAppData { expected: 4, found: 0, }); } if user_data.len() < 8 { let err = if user_data.len() < 4 { &hk_err::TARGET_ID_MISSING } else { &hk_err::UNIQUE_ID_MISSING }; let user_data_len = user_data.len() as u32; let user_data_len_raw = user_data_len.to_be_bytes(); verif_reporter .start_failure(token, FailParams::new(time_stamp, err, &user_data_len_raw)) .expect("Sending start failure TM failed"); return Err(PusPacketHandlingError::NotEnoughAppData { expected: 8, found: 4, }); } let subservice = tc.subservice(); let target_id_and_apid = TargetAndApidId::from_pus_tc(tc).expect("invalid tc format"); let unique_id = u32::from_be_bytes(tc.user_data()[4..8].try_into().unwrap()); let standard_subservice = hk::Subservice::try_from(subservice); if standard_subservice.is_err() { verif_reporter .start_failure( token, FailParams::new(time_stamp, &tmtc_err::INVALID_PUS_SUBSERVICE, &[subservice]), ) .expect("Sending start failure TM failed"); return Err(PusPacketHandlingError::InvalidSubservice(subservice)); } let request = match standard_subservice.unwrap() { hk::Subservice::TcEnableHkGeneration | hk::Subservice::TcEnableDiagGeneration => { HkRequest::Enable(unique_id) } hk::Subservice::TcDisableHkGeneration | hk::Subservice::TcDisableDiagGeneration => { HkRequest::Disable(unique_id) } hk::Subservice::TcReportHkReportStructures => todo!(), hk::Subservice::TmHkPacket => todo!(), hk::Subservice::TcGenerateOneShotHk | hk::Subservice::TcGenerateOneShotDiag => { HkRequest::OneShot(unique_id) } hk::Subservice::TcModifyDiagCollectionInterval | hk::Subservice::TcModifyHkCollectionInterval => { if user_data.len() < 12 { verif_reporter .start_failure( token, FailParams::new_no_fail_data( time_stamp, &tmtc_err::NOT_ENOUGH_APP_DATA, ), ) .expect("Sending start failure TM failed"); return Err(PusPacketHandlingError::NotEnoughAppData { expected: 12, found: user_data.len(), }); } HkRequest::ModifyCollectionInterval( unique_id, CollectionIntervalFactor::from_be_bytes(user_data[8..12].try_into().unwrap()), ) } _ => { verif_reporter .start_failure( token, FailParams::new( time_stamp, &tmtc_err::PUS_SUBSERVICE_NOT_IMPLEMENTED, &[subservice], ), ) .expect("Sending start failure TM failed"); return Err(PusPacketHandlingError::InvalidSubservice(subservice)); } }; let token = verif_reporter .start_success(token, time_stamp) .map_err(|e| e.0)?; Ok(( ActivePusRequest::new( target_id_and_apid.into(), token, UnixTimestamp::from_now().unwrap(), Duration::from_secs(60), ) .into(), request, )) } } pub fn create_hk_service_static( shared_tm_store: SharedTmPool, tm_funnel_tx: mpsc::SyncSender, verif_reporter: VerificationReporterWithSharedPoolMpscBoundedSender, tc_pool: SharedStaticMemoryPool, pus_hk_rx: mpsc::Receiver, request_router: GenericRequestRouter, ) -> Pus3Wrapper< MpscTcReceiver, TmInSharedPoolSenderWithBoundedMpsc, EcssTcInSharedStoreConverter, VerificationReporterWithSharedPoolMpscBoundedSender, > { let hk_srv_tm_sender = TmInSharedPoolSenderWithId::new( TmSenderId::PusHk as ChannelId, "PUS_3_TM_SENDER", shared_tm_store.clone(), tm_funnel_tx.clone(), ); let hk_srv_receiver = MpscTcReceiver::new(TcReceiverId::PusHk as ChannelId, "PUS_8_TC_RECV", pus_hk_rx); let pus_3_handler = PusTargetedRequestService::new( PusServiceHelper::new( hk_srv_receiver, hk_srv_tm_sender, PUS_APID, verif_reporter.clone(), EcssTcInSharedStoreConverter::new(tc_pool, 2048), ), ExampleHkRequestConverter::default(), request_router, DefaultActiveRequestMap::default(), HkReplyHandler::default(), ); Pus3Wrapper { pus_3_handler } } pub fn create_hk_service_dynamic( tm_funnel_tx: mpsc::Sender>, verif_reporter: VerificationReporterWithVecMpscSender, pus_hk_rx: mpsc::Receiver, request_router: GenericRequestRouter, ) -> Pus3Wrapper< MpscTcReceiver, TmAsVecSenderWithMpsc, EcssTcInVecConverter, VerificationReporterWithVecMpscSender, > { let hk_srv_tm_sender = TmAsVecSenderWithId::new( TmSenderId::PusHk as ChannelId, "PUS_3_TM_SENDER", tm_funnel_tx.clone(), ); let hk_srv_receiver = MpscTcReceiver::new(TcReceiverId::PusHk as ChannelId, "PUS_8_TC_RECV", pus_hk_rx); let pus_3_handler = PusTargetedRequestService::new( PusServiceHelper::new( hk_srv_receiver, hk_srv_tm_sender, PUS_APID, verif_reporter.clone(), EcssTcInVecConverter::default(), ), ExampleHkRequestConverter::default(), request_router, DefaultActiveRequestMap::default(), HkReplyHandler::default(), ); Pus3Wrapper { pus_3_handler } } pub struct Pus3Wrapper< TcReceiver: EcssTcReceiverCore, TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter, VerificationReporter: VerificationReportingProvider, > { pub(crate) pus_3_handler: PusTargetedRequestService< TcReceiver, TmSender, TcInMemConverter, VerificationReporter, ExampleHkRequestConverter, HkReplyHandler, DefaultActiveRequestMap, ActivePusRequest, HkRequest, HkReply, >, } impl< TcReceiver: EcssTcReceiverCore, TmSender: EcssTmSenderCore, TcInMemConverter: EcssTcInMemConverter, VerificationReporter: VerificationReportingProvider, > Pus3Wrapper { pub fn handle_next_packet(&mut self, time_stamp: &[u8]) -> bool { match self.pus_3_handler.handle_one_tc(time_stamp) { Ok(result) => match result { PusPacketHandlerResult::RequestHandled => {} PusPacketHandlerResult::RequestHandledPartialSuccess(e) => { warn!("PUS 3 partial packet handling success: {e:?}") } PusPacketHandlerResult::CustomSubservice(invalid, _) => { warn!("PUS 3 invalid subservice {invalid}"); } PusPacketHandlerResult::SubserviceNotImplemented(subservice, _) => { warn!("PUS 3 subservice {subservice} not implemented"); } PusPacketHandlerResult::Empty => { return true; } }, Err(error) => { error!("PUS packet handling error: {error:?}") } } false } }