impl file data send handling
Some checks failed
Rust/sat-rs/pipeline/head There was a failure building this commit

This commit is contained in:
Robin Müller 2024-07-19 11:35:33 -07:00
parent 0aa3030bf3
commit b77252d16b
2 changed files with 122 additions and 8 deletions

View File

@ -31,7 +31,7 @@ default-features = false
version = "0.12"
default-features = false
git = "https://egit.irs.uni-stuttgart.de/rust/spacepackets"
branch = "main"
branch = "file-data-pdu-update"
[dependencies.cobs]
git = "https://github.com/robamu/cobs.rs.git"

View File

@ -1,13 +1,14 @@
use core::{cell::RefCell, str::Utf8Error};
use core::{cell::RefCell, ops::ControlFlow, str::Utf8Error};
use spacepackets::{
cfdp::{
lv::Lv,
pdu::{
file_data::FileDataPduCreatorWithReservedDatafield,
metadata::{MetadataGenericParams, MetadataPduCreator},
CfdpPdu, CommonPduConfig, FileDirectiveType, PduError, PduHeader, WritablePduPacket,
},
Direction, LargeFileFlag, PduType,
Direction, LargeFileFlag, PduType, SegmentMetadataFlag, SegmentationControl,
},
util::{UnsignedByteField, UnsignedEnum},
ByteConversionError,
@ -41,12 +42,12 @@ pub enum TransactionStep {
#[derive(Default)]
pub struct FileParams {
pub progress: usize,
pub segment_len: usize,
pub progress: u64,
pub segment_len: u64,
//pub crc32: Option<[u8; 4]>,
pub metadata_only: bool,
pub file_size: u64,
pub no_eof: bool,
pub empty_file: bool,
}
pub struct StateHelper {
@ -275,6 +276,7 @@ impl<
Ok(())
}
#[inline]
pub fn transmission_mode(&self) -> Option<super::TransmissionMode> {
self.tstate.map(|v| v.transmission_mode)
}
@ -289,6 +291,13 @@ impl<
}
if self.state_helper.step == TransactionStep::SendingMetadata {
self.prepare_and_send_metadata_pdu()?;
self.state_helper.step = TransactionStep::SendingFileData;
return Ok(1);
}
if self.state_helper.step == TransactionStep::SendingFileData {
if let ControlFlow::Break(result) = self.file_data_fsm()? {
return Ok(result);
}
}
Ok(0)
}
@ -300,7 +309,7 @@ impl<
let tstate = &self.tstate.expect("transfer state unexpectedly empty");
if !self.put_request_cacher.has_source_file() {
self.fparams.metadata_only = true;
self.fparams.no_eof = true;
self.fparams.empty_file = true;
} else {
let source_file = self
.put_request_cacher
@ -351,7 +360,7 @@ impl<
Ok(())
}
fn prepare_and_send_metadata_pdu(&self) -> Result<(), PduError> {
fn prepare_and_send_metadata_pdu(&mut self) -> Result<(), PduError> {
let tstate = &self.tstate.expect("transfer state unexpectedly empty");
let metadata_params = MetadataGenericParams::new(
tstate.closure_requested,
@ -378,6 +387,111 @@ impl<
self.pdu_send_helper(metadata_pdu)
}
fn file_data_fsm(&mut self) -> Result<ControlFlow<u32>, SourceError> {
if self.transmission_mode().unwrap() == super::TransmissionMode::Acknowledged {
// TODO: Handle re-transmission
}
if !self.fparams.metadata_only
&& self.fparams.progress < self.fparams.file_size
&& self.send_progressing_file_data_pdu()?
{
return Ok(ControlFlow::Break(1));
}
if self.fparams.empty_file {
// EOF is still expected.
self.state_helper.step = TransactionStep::SendingEof;
} else if self.fparams.metadata_only {
// Special case: Metadata Only, no EOF required.
if self.tstate.as_ref().unwrap().closure_requested {
self.state_helper.step = TransactionStep::WaitingForFinished;
} else {
self.state_helper.step = TransactionStep::NoticeOfCompletion;
}
}
Ok(ControlFlow::Continue(()))
}
fn send_progressing_file_data_pdu(&mut self) -> Result<bool, SourceError> {
// Should never be called, but use defensive programming here.
if self.fparams.progress >= self.fparams.file_size {
return Ok(false);
}
let read_len = if self.fparams.file_size < self.fparams.segment_len {
self.fparams.file_size
} else if self.fparams.progress + self.fparams.segment_len > self.fparams.file_size {
self.fparams.file_size - self.fparams.progress
} else {
self.fparams.segment_len
};
// TODO: Send File Data PDU.
let pdu_creator = FileDataPduCreatorWithReservedDatafield::new_no_seg_metadata(
PduHeader::new_for_file_data(
self.pdu_conf,
0,
SegmentMetadataFlag::NotPresent,
SegmentationControl::NoRecordBoundaryPreservation,
),
self.fparams.progress,
read_len,
);
let mut unwritten_pdu = pdu_creator.write_to_bytes_partially(self.pdu_buffer.get_mut())?;
self.vfs.read_data(
self.put_request_cacher.source_file().unwrap(),
self.fparams.progress,
read_len,
unwritten_pdu.file_data_field_mut(),
)?;
let written_len = unwritten_pdu.finish();
self.pdu_sender.send_pdu(
PduType::FileData,
None,
&self.pdu_buffer.borrow()[0..written_len],
)?;
self.fparams.progress += read_len;
/*
"""Generic function to prepare a file data PDU. This function can also be used to
re-transmit file data PDUs of segments which were already sent."""
assert self._put_req is not None
assert self._put_req.source_file is not None
with open(self._put_req.source_file, "rb") as of:
file_data = self.user.vfs.read_from_opened_file(of, offset, read_len)
# TODO: Support for record continuation state not implemented yet. Segment metadata
# flag is therefore always set to False. Segment metadata support also omitted
# for now. Implementing those generically could be done in form of a callback,
# e.g. abstractmethod of this handler as a first way, another one being
# to expect the user to supply some helper class to split up a file
fd_params = FileDataParams(
file_data=file_data, offset=offset, segment_metadata=None
)
file_data_pdu = FileDataPdu(
pdu_conf=self._params.pdu_conf, params=fd_params
)
self._add_packet_to_be_sent(file_data_pdu)
*/
/*
"""Prepare the next file data PDU, which also progresses the file copy operation.
:return: True if a packet was prepared, False if PDU handling is done and the next steps
in the Copy File procedure can be performed
"""
# This function should only be called if file segments still need to be sent.
assert self._params.fp.progress < self._params.fp.file_size
if self._params.fp.file_size < self._params.fp.segment_len:
read_len = self._params.fp.file_size
else:
if (
self._params.fp.progress + self._params.fp.segment_len
> self._params.fp.file_size
):
read_len = self._params.fp.file_size - self._params.fp.progress
else:
read_len = self._params.fp.segment_len
self._prepare_file_data_pdu(self._params.fp.progress, read_len)
self._params.fp.progress += read_len
*/
Ok(true)
}
fn pdu_send_helper(&self, pdu: impl WritablePduPacket + CfdpPdu) -> Result<(), PduError> {
let mut pdu_buffer_mut = self.pdu_buffer.borrow_mut();
let written_len = pdu.write_to_bytes(&mut pdu_buffer_mut)?;