introduce new writable PDU packet abstraction
All checks were successful
Rust/spacepackets/pipeline/head This commit looks good

This commit is contained in:
Robin Müller 2023-11-11 18:17:41 +01:00
parent 016e0d8673
commit 18d650316c
Signed by: muellerr
GPG Key ID: A649FB78196E3849
5 changed files with 155 additions and 138 deletions

View File

@ -8,6 +8,8 @@ use crate::ByteConversionError;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket;
/// Finished PDU abstraction. /// Finished PDU abstraction.
/// ///
/// For more information, refer to CFDP chapter 5.2.2. /// For more information, refer to CFDP chapter 5.2.2.
@ -68,36 +70,6 @@ impl EofPdu {
len len
} }
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len();
if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: expected_len,
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::EofPdu as u8;
current_idx += 1;
buf[current_idx] = (self.condition_code as u8) << 4;
current_idx += 1;
buf[current_idx..current_idx + 4].copy_from_slice(&self.file_checksum.to_be_bytes());
current_idx += 4;
current_idx += write_fss_field(
self.pdu_header.pdu_conf.file_flag,
self.file_size,
&mut buf[current_idx..],
)?;
if let Some(fault_location) = self.fault_location {
current_idx += fault_location.write_to_be_bytes(buf)?;
}
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
pub fn from_bytes(buf: &[u8]) -> Result<EofPdu, PduError> { pub fn from_bytes(buf: &[u8]) -> Result<EofPdu, PduError> {
let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?; let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?;
let full_len_without_crc = pdu_header.verify_length_and_checksum(buf)?; let full_len_without_crc = pdu_header.verify_length_and_checksum(buf)?;
@ -143,9 +115,41 @@ impl EofPdu {
} }
} }
impl WritablePduPacket for EofPdu {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len();
if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: expected_len,
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::EofPdu as u8;
current_idx += 1;
buf[current_idx] = (self.condition_code as u8) << 4;
current_idx += 1;
buf[current_idx..current_idx + 4].copy_from_slice(&self.file_checksum.to_be_bytes());
current_idx += 4;
current_idx += write_fss_field(
self.pdu_header.pdu_conf.file_flag,
self.file_size,
&mut buf[current_idx..],
)?;
if let Some(fault_location) = self.fault_location {
current_idx += fault_location.write_to_be_bytes(buf)?;
}
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::cfdp::pdu::eof::EofPdu; use super::*;
use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header}; use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header};
use crate::cfdp::pdu::{FileDirectiveType, PduHeader}; use crate::cfdp::pdu::{FileDirectiveType, PduHeader};
use crate::cfdp::{ConditionCode, CrcFlag, LargeFileFlag}; use crate::cfdp::{ConditionCode, CrcFlag, LargeFileFlag};

View File

@ -8,6 +8,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket;
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)] #[repr(u8)]
@ -163,35 +165,6 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> {
self.segment_metadata.as_ref() self.segment_metadata.as_ref()
} }
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
if buf.len() < self.written_len() {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: self.written_len(),
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
if self.segment_metadata.is_some() {
current_idx += self
.segment_metadata
.as_ref()
.unwrap()
.write_to_bytes(&mut buf[current_idx..])?;
}
current_idx += write_fss_field(
self.pdu_header.common_pdu_conf().file_flag,
self.offset,
&mut buf[current_idx..],
)?;
buf[current_idx..current_idx + self.file_data.len()].copy_from_slice(self.file_data);
current_idx += self.file_data.len();
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
pub fn from_bytes<'longest: 'seg_meta + 'file_data>( pub fn from_bytes<'longest: 'seg_meta + 'file_data>(
buf: &'longest [u8], buf: &'longest [u8],
) -> Result<Self, PduError> { ) -> Result<Self, PduError> {
@ -222,9 +195,40 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> {
} }
} }
impl WritablePduPacket for FileDataPdu<'_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
if buf.len() < self.written_len() {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: self.written_len(),
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
if self.segment_metadata.is_some() {
current_idx += self
.segment_metadata
.as_ref()
.unwrap()
.write_to_bytes(&mut buf[current_idx..])?;
}
current_idx += write_fss_field(
self.pdu_header.common_pdu_conf().file_flag,
self.offset,
&mut buf[current_idx..],
)?;
buf[current_idx..current_idx + self.file_data.len()].copy_from_slice(self.file_data);
current_idx += self.file_data.len();
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::cfdp::pdu::file_data::{FileDataPdu, RecordContinuationState, SegmentMetadata}; use super::*;
use crate::cfdp::pdu::{CommonPduConfig, PduHeader}; use crate::cfdp::pdu::{CommonPduConfig, PduHeader};
use crate::cfdp::{SegmentMetadataFlag, SegmentationControl}; use crate::cfdp::{SegmentMetadataFlag, SegmentationControl};
use crate::util::UbfU8; use crate::util::UbfU8;

View File

@ -8,6 +8,8 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket;
#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[repr(u8)] #[repr(u8)]
@ -135,36 +137,6 @@ impl<'fs_responses> FinishedPdu<'fs_responses> {
base_len base_len
} }
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len();
if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: expected_len,
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::FinishedPdu as u8;
current_idx += 1;
buf[current_idx] = ((self.condition_code as u8) << 4)
| ((self.delivery_code as u8) << 2)
| self.file_status as u8;
current_idx += 1;
if let Some(fs_responses) = self.fs_responses {
buf[current_idx..current_idx + fs_responses.len()].copy_from_slice(fs_responses);
current_idx += fs_responses.len();
}
if let Some(fault_location) = self.fault_location {
current_idx += fault_location.write_to_be_bytes(&mut buf[current_idx..])?;
}
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
/// Generates [Self] from a raw bytestream. /// Generates [Self] from a raw bytestream.
pub fn from_bytes(buf: &'fs_responses [u8]) -> Result<Self, PduError> { pub fn from_bytes(buf: &'fs_responses [u8]) -> Result<Self, PduError> {
let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?; let (pdu_header, mut current_idx) = PduHeader::from_bytes(buf)?;
@ -246,9 +218,41 @@ impl<'fs_responses> FinishedPdu<'fs_responses> {
} }
} }
impl WritablePduPacket for FinishedPdu<'_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len();
if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: expected_len,
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::FinishedPdu as u8;
current_idx += 1;
buf[current_idx] = ((self.condition_code as u8) << 4)
| ((self.delivery_code as u8) << 2)
| self.file_status as u8;
current_idx += 1;
if let Some(fs_responses) = self.fs_responses {
buf[current_idx..current_idx + fs_responses.len()].copy_from_slice(fs_responses);
current_idx += fs_responses.len();
}
if let Some(fault_location) = self.fault_location {
current_idx += fault_location.write_to_be_bytes(&mut buf[current_idx..])?;
}
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::cfdp::pdu::finished::{DeliveryCode, FileStatus, FinishedPdu}; use super::*;
use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header}; use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header};
use crate::cfdp::pdu::{FileDirectiveType, PduHeader}; use crate::cfdp::pdu::{FileDirectiveType, PduHeader};
use crate::cfdp::{ConditionCode, CrcFlag, Direction, LargeFileFlag}; use crate::cfdp::{ConditionCode, CrcFlag, Direction, LargeFileFlag};

View File

@ -11,6 +11,8 @@ use alloc::vec::Vec;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MetadataGenericParams { pub struct MetadataGenericParams {
@ -199,43 +201,6 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
&self.pdu_header &self.pdu_header
} }
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len();
if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: expected_len,
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::MetadataPdu as u8;
current_idx += 1;
buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7)
| (self.metadata_params.checksum_type as u8);
current_idx += 1;
current_idx += write_fss_field(
self.pdu_header.common_pdu_conf().file_flag,
self.metadata_params.file_size,
&mut buf[current_idx..],
)?;
current_idx += self
.src_file_name
.write_to_be_bytes(&mut buf[current_idx..])?;
current_idx += self
.dest_file_name
.write_to_be_bytes(&mut buf[current_idx..])?;
if let Some(opts) = self.options {
buf[current_idx..current_idx + opts.len()].copy_from_slice(opts);
current_idx += opts.len();
}
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
pub fn from_bytes<'longest: 'src_name + 'dest_name + 'opts>( pub fn from_bytes<'longest: 'src_name + 'dest_name + 'opts>(
buf: &'longest [u8], buf: &'longest [u8],
) -> Result<Self, PduError> { ) -> Result<Self, PduError> {
@ -289,8 +254,48 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
} }
} }
impl WritablePduPacket for MetadataPdu<'_, '_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.written_len();
if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(),
expected: expected_len,
}
.into());
}
let mut current_idx = self.pdu_header.write_to_bytes(buf)?;
buf[current_idx] = FileDirectiveType::MetadataPdu as u8;
current_idx += 1;
buf[current_idx] = ((self.metadata_params.closure_requested as u8) << 7)
| (self.metadata_params.checksum_type as u8);
current_idx += 1;
current_idx += write_fss_field(
self.pdu_header.common_pdu_conf().file_flag,
self.metadata_params.file_size,
&mut buf[current_idx..],
)?;
current_idx += self
.src_file_name
.write_to_be_bytes(&mut buf[current_idx..])?;
current_idx += self
.dest_file_name
.write_to_be_bytes(&mut buf[current_idx..])?;
if let Some(opts) = self.options {
buf[current_idx..current_idx + opts.len()].copy_from_slice(opts);
current_idx += opts.len();
}
if self.pdu_header.pdu_conf.crc_flag == CrcFlag::WithCrc {
current_idx = add_pdu_crc(buf, current_idx);
}
Ok(current_idx)
}
}
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use super::*;
use crate::cfdp::lv::Lv; use crate::cfdp::lv::Lv;
use crate::cfdp::pdu::metadata::{ use crate::cfdp::pdu::metadata::{
build_metadata_opts_from_slice, build_metadata_opts_from_vec, MetadataGenericParams, build_metadata_opts_from_slice, build_metadata_opts_from_vec, MetadataGenericParams,
@ -304,18 +309,14 @@ pub mod tests {
}; };
use std::vec; use std::vec;
const SRC_FILENAME: &'static str = "hello-world.txt"; const SRC_FILENAME: &str = "hello-world.txt";
const DEST_FILENAME: &'static str = "hello-world2.txt"; const DEST_FILENAME: &str = "hello-world2.txt";
fn generic_metadata_pdu<'opts>( fn generic_metadata_pdu(
crc_flag: CrcFlag, crc_flag: CrcFlag,
fss: LargeFileFlag, fss: LargeFileFlag,
opts: Option<&'opts [u8]>, opts: Option<&[u8]>,
) -> ( ) -> (Lv<'static>, Lv<'static>, MetadataPdu<'static, 'static, '_>) {
Lv<'static>,
Lv<'static>,
MetadataPdu<'static, 'static, 'opts>,
) {
let pdu_header = PduHeader::new_no_file_data(common_pdu_conf(crc_flag, fss), 0); let pdu_header = PduHeader::new_no_file_data(common_pdu_conf(crc_flag, fss), 0);
let metadata_params = MetadataGenericParams::new(false, ChecksumType::Crc32, 0x1010); let metadata_params = MetadataGenericParams::new(false, ChecksumType::Crc32, 0x1010);
let src_filename = Lv::new_from_str(SRC_FILENAME).expect("Generating string LV failed"); let src_filename = Lv::new_from_str(SRC_FILENAME).expect("Generating string LV failed");

View File

@ -149,6 +149,10 @@ impl From<TlvLvError> for PduError {
} }
} }
trait WritablePduPacket {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError>;
}
/// Common configuration fields for a PDU. /// Common configuration fields for a PDU.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]