diff --git a/src/dest.rs b/src/dest.rs index f780c50..33b897a 100644 --- a/src/dest.rs +++ b/src/dest.rs @@ -30,36 +30,36 @@ //! 4. A Finished PDU has been sent back to the remote side. //! 5. A Finished PDU ACK was received. use crate::{ - DummyPduProvider, GenericSendError, IndicationConfig, PduProvider, PositiveAckParams, lost_segments::{LostSegmentError, LostSegmentStore}, user::TransactionFinishedParams, + DummyPduProvider, GenericSendError, IndicationConfig, PduProvider, PositiveAckParams, }; use core::{ cell::{Cell, RefCell}, - str::{Utf8Error, from_utf8, from_utf8_unchecked}, + str::{from_utf8, from_utf8_unchecked, Utf8Error}, }; use super::{ - Countdown, EntityType, LocalEntityConfig, PacketTarget, PduSendProvider, RemoteConfigStore, - RemoteEntityConfig, State, TimerContext, TimerCreator, TransactionId, UserFaultHook, filestore::{FilestoreError, VirtualFilestore}, user::{CfdpUser, FileSegmentRecvdParams, MetadataReceivedParams}, + Countdown, EntityType, LocalEntityConfig, PacketTarget, PduSender, RemoteConfigStore, + RemoteEntityConfig, State, TimerContext, TimerCreator, TransactionId, UserFaultHook, }; use smallvec::SmallVec; use spacepackets::{ cfdp::{ - ChecksumType, ConditionCode, FaultHandlerCode, LargeFileFlag, PduType, TransactionStatus, - TransmissionMode, pdu::{ - CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, ack::AckPdu, eof::EofPdu, file_data::FileDataPdu, finished::{DeliveryCode, FileStatus, FinishedPduCreator}, metadata::{MetadataGenericParams, MetadataPduReader}, nak::NakPduCreatorWithReservedSeqReqsBuf, + CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, }, - tlv::{EntityIdTlv, GenericTlv, ReadableTlv, TlvType, msg_to_user::MsgToUserTlv}, + tlv::{msg_to_user::MsgToUserTlv, EntityIdTlv, GenericTlv, ReadableTlv, TlvType}, + ChecksumType, ConditionCode, FaultHandlerCode, LargeFileFlag, PduType, TransactionStatus, + TransmissionMode, }, util::{UnsignedByteField, UnsignedEnum}, }; @@ -334,9 +334,9 @@ pub enum DestError { /// in different concurrent contexts. For example, you can dynamically create new handlers and /// run them inside a thread pool, or move the newly created handler to a new thread.""" pub struct DestinationHandler< - PduSender: PduSendProvider, + PduSenderInstance: PduSender, UserFaultHookInstance: UserFaultHook, - Vfs: VirtualFilestore, + VirtualFileStoreInstance: VirtualFilestore, RemoteConfigStoreInstance: RemoteConfigStore, TimerCreatorInstance: TimerCreator, CountdownInstance: Countdown, @@ -347,8 +347,8 @@ pub struct DestinationHandler< state: State, transaction_params: TransactionParams, pdu_and_cksum_buffer: RefCell>, - pub pdu_sender: PduSender, - pub vfs: Vfs, + pub pdu_sender: PduSenderInstance, + pub vfs: VirtualFileStoreInstance, pub remote_cfg_table: RemoteConfigStoreInstance, pub check_timer_creator: TimerCreatorInstance, lost_segment_tracker: LostSegmentTracker, @@ -366,14 +366,14 @@ pub type StdDestinationHandler = DestinationHandler< >; #[cfg(feature = "std")] -impl - StdDestinationHandler +impl + StdDestinationHandler { #[cfg(feature = "std")] pub fn new_std( local_cfg: LocalEntityConfig, pdu_and_cksum_buf_size: usize, - pdu_sender: PduSender, + pdu_sender: PduSenderInstance, ) -> Self { Self::new( local_cfg, @@ -388,18 +388,18 @@ impl } impl< - PduSender: PduSendProvider, - UserFaultHookInstance: UserFaultHook, - Vfs: VirtualFilestore, - RemoteConfigStoreInstance: RemoteConfigStore, - TimerCreatorInstance: TimerCreator, - CountdownInstance: Countdown, - LostSegmentTracker: LostSegmentStore, -> + PduSenderInstance: PduSender, + UserFaultHookInstance: UserFaultHook, + VirtualFilestoreInstance: VirtualFilestore, + RemoteConfigStoreInstance: RemoteConfigStore, + TimerCreatorInstance: TimerCreator, + CountdownInstance: Countdown, + LostSegmentTracker: LostSegmentStore, + > DestinationHandler< - PduSender, + PduSenderInstance, UserFaultHookInstance, - Vfs, + VirtualFilestoreInstance, RemoteConfigStoreInstance, TimerCreatorInstance, CountdownInstance, @@ -429,8 +429,8 @@ impl< pub fn new( local_cfg: LocalEntityConfig, pdu_and_cksum_buf_size: usize, - pdu_sender: PduSender, - vfs: Vfs, + pdu_sender: PduSenderInstance, + vfs: VirtualFilestoreInstance, remote_cfg_table: RemoteConfigStoreInstance, timer_creator: TimerCreatorInstance, lost_segment_tracker: LostSegmentTracker, @@ -987,20 +987,110 @@ impl< }) } } - self.transaction_params.deferred_procedure_timer = Some( - self.check_timer_creator - .create_countdown(TimerContext::NakActivity { - expiry_time: self - .transaction_params - .remote_cfg - .as_ref() - .unwrap() - .nak_timer_interval, - }), - ); } fn deferred_lost_segment_handling(&mut self) { + assert!( + self.transaction_params.acked_params.is_some(), + "acknowledged parameters unexpectedly None" + ); + let acked_params = self.transaction_params.acked_params.as_mut().unwrap(); + if self.lost_segment_tracker.is_empty() && !acked_params.metadata_missing { + // We are done and have received everything. + match self.checksum_verify( + self.transaction_params.progress, + self.transaction_params.checksum, + ) { + true => { + self.transaction_params + .finished_params + .condition_code + .set(ConditionCode::NoError); + self.transaction_params + .finished_params + .delivery_code + .set(DeliveryCode::Complete); + } + false => { + self.transaction_params + .finished_params + .condition_code + .set(ConditionCode::FileChecksumFailure); + self.transaction_params + .finished_params + .delivery_code + .set(DeliveryCode::Incomplete); + } + } + self.set_step(TransactionStep::TransferCompletion); + acked_params.deferred_procedure_active = false; + return; + } + + let mut first_nak_issuance = self.transaction_params.deferred_procedure_timer.is_none(); + if first_nak_issuance { + self.transaction_params.deferred_procedure_timer = Some( + self.check_timer_creator + .create_countdown(TimerContext::NakActivity { + expiry_time: self + .transaction_params + .remote_cfg + .as_ref() + .unwrap() + .nak_timer_interval, + }), + ); + } else if !self + .transaction_params + .deferred_procedure_timer + .as_ref() + .unwrap() + .has_expired() + { + return; + } + if !first_nak_issuance + && acked_params.nak_activity_counter + 1 + == self + .transaction_params + .remote_cfg + .as_ref() + .unwrap() + .nak_timer_expiration_limit + { + self.transaction_params.finished_params.delivery_code = DeliveryCode::Incomplete; + if self.declare_fault(ConditionCode::NakLimitReached) + == FaultHandlerCode::AbandonTransaction + { + self.abandon_transaction(); + } + return; + } + let pdu_header = PduHeader::new_no_file_data(self.transaction_params.pdu_conf, 0); + let max_segment_reqs = NakPduCreatorWithReservedSeqReqsBuf::calculate_max_segment_requests( + self.transaction_params + .remote_cfg + .as_ref() + .unwrap() + .max_packet_len, + &pdu_header, + ); + let mut segments_to_send = self.lost_segment_tracker.number_of_segments(); + if acked_params.metadata_missing { + segments_to_send += 1; + } + if segments_to_send <= max_segment_reqs { + + } + + let mut nak_pdu_creator = NakPduCreatorWithReservedSeqReqsBuf::new( + self.pdu_and_cksum_buffer.get_mut(), + pdu_header, + core::cmp::min(segments_to_send as usize, max_segment_reqs), + ) + for index in 0..segments_to_send { + + } // TODO. } @@ -1511,21 +1601,21 @@ mod tests { use rand::Rng; use spacepackets::{ cfdp::{ - ChecksumType, TransmissionMode, lv::Lv, - pdu::{WritablePduPacket, finished::FinishedPduReader, metadata::MetadataPduCreator}, + pdu::{finished::FinishedPduReader, metadata::MetadataPduCreator, WritablePduPacket}, + ChecksumType, TransmissionMode, }, util::{UbfU16, UnsignedByteFieldU8}, }; use crate::{ - CRC_32, FaultHandler, IndicationConfig, PduRawWithInfo, RemoteConfigStoreStd, filestore::NativeFilestore, lost_segments::LostSegmentsList, tests::{ - LOCAL_ID, REMOTE_ID, SentPdu, TestCfdpSender, TestCfdpUser, TestCheckTimer, - TestCheckTimerCreator, TestFaultHandler, TimerExpiryControl, basic_remote_cfg_table, + basic_remote_cfg_table, SentPdu, TestCfdpSender, TestCfdpUser, TestCheckTimer, + TestCheckTimerCreator, TestFaultHandler, TimerExpiryControl, LOCAL_ID, REMOTE_ID, }, + FaultHandler, IndicationConfig, PduRawWithInfo, RemoteConfigStoreStd, CRC_32, }; use super::*; @@ -1842,14 +1932,12 @@ mod tests { let dest_handler = default_dest_handler(fault_handler, test_sender, &TimerExpiryControl::default()); assert!(dest_handler.transmission_mode().is_none()); - assert!( - dest_handler - .local_cfg - .fault_handler - .user_hook - .borrow() - .all_queues_empty() - ); + assert!(dest_handler + .local_cfg + .fault_handler + .user_hook + .borrow() + .all_queues_empty()); assert!(dest_handler.pdu_sender.queue_empty()); assert_eq!(dest_handler.state(), State::Idle); assert_eq!(dest_handler.step(), TransactionStep::Idle); diff --git a/src/lib.rs b/src/lib.rs index 2f8cb66..457e6fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -693,7 +693,7 @@ pub enum GenericSendError { Other, } -pub trait PduSendProvider { +pub trait PduSender { fn send_pdu( &self, pdu_type: PduType, @@ -716,7 +716,7 @@ pub mod std_mod { use super::*; - impl PduSendProvider for mpsc::Sender { + impl PduSender for mpsc::Sender { fn send_pdu( &self, pdu_type: PduType, @@ -1471,7 +1471,7 @@ pub(crate) mod tests { pub packet_queue: RefCell>, } - impl PduSendProvider for TestCfdpSender { + impl PduSender for TestCfdpSender { fn send_pdu( &self, pdu_type: PduType, diff --git a/src/source.rs b/src/source.rs index b0660f6..255583b 100644 --- a/src/source.rs +++ b/src/source.rs @@ -72,7 +72,7 @@ use crate::{ }; use super::{ - LocalEntityConfig, PacketTarget, PduSendProvider, RemoteConfigStore, RemoteEntityConfig, State, + LocalEntityConfig, PacketTarget, PduSender, RemoteConfigStore, RemoteEntityConfig, State, TransactionId, UserFaultHook, filestore::{FilestoreError, VirtualFilestore}, request::{ReadablePutRequest, StaticPutRequestCacher}, @@ -242,7 +242,7 @@ pub enum FsmContext { /// is required, it is recommended to create a new handler and run all active handlers inside a /// thread pool, or move the newly created handler to a new thread. pub struct SourceHandler< - PduSender: PduSendProvider, + PduSenderInstance: PduSender, UserFaultHookInstance: UserFaultHook, Vfs: VirtualFilestore, RemoteConfigStoreInstance: RemoteConfigStore, @@ -251,7 +251,7 @@ pub struct SourceHandler< SequenceCounterInstance: SequenceCounter, > { local_cfg: LocalEntityConfig, - pdu_sender: PduSender, + pdu_sender: PduSenderInstance, pdu_and_cksum_buffer: RefCell>, put_request_cacher: StaticPutRequestCacher, remote_cfg_table: RemoteConfigStoreInstance, @@ -271,7 +271,7 @@ pub struct SourceHandler< } impl< - PduSender: PduSendProvider, + PduSenderInstance: PduSender, UserFaultHookInstance: UserFaultHook, Vfs: VirtualFilestore, RemoteConfigStoreInstance: RemoteConfigStore, @@ -280,7 +280,7 @@ impl< SequenceCounterInstance: SequenceCounter, > SourceHandler< - PduSender, + PduSenderInstance, UserFaultHookInstance, Vfs, RemoteConfigStoreInstance, @@ -314,7 +314,7 @@ impl< #[allow(clippy::too_many_arguments)] pub fn new( cfg: LocalEntityConfig, - pdu_sender: PduSender, + pdu_sender: PduSenderInstance, vfs: Vfs, put_request_cacher: StaticPutRequestCacher, pdu_and_cksum_buf_size: usize,