From c68e71a25ea4c169ed648f3c09adc2e666f03dbf Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 11 Sep 2025 09:09:41 +0200 Subject: [PATCH] improve CFDP module --- src/cfdp/lv.rs | 2 + src/cfdp/pdu/ack.rs | 44 +++++++++++------ src/cfdp/pdu/eof.rs | 43 +++++++++++------ src/cfdp/pdu/file_data.rs | 73 ++++++++++++++++++++-------- src/cfdp/pdu/finished.rs | 64 +++++++++++++++++++------ src/cfdp/pdu/metadata.rs | 60 +++++++++++++++++------ src/cfdp/pdu/mod.rs | 3 ++ src/cfdp/pdu/nak.rs | 44 ++++++++++++----- src/cfdp/tlv/mod.rs | 96 ++++++++++++++++++++++++++++++++----- src/cfdp/tlv/msg_to_user.rs | 26 +++++++--- src/ecss/tc.rs | 8 ++-- src/ecss/tm.rs | 14 +++--- src/lib.rs | 36 +++++--------- 13 files changed, 368 insertions(+), 145 deletions(-) diff --git a/src/cfdp/lv.rs b/src/cfdp/lv.rs index 9c14cfc..b3bb74a 100644 --- a/src/cfdp/lv.rs +++ b/src/cfdp/lv.rs @@ -63,6 +63,8 @@ pub(crate) fn generic_len_check_deserialization( } impl<'data> Lv<'data> { + pub const MIN_LEN: usize = MIN_LV_LEN; + #[inline] pub fn new(data: &[u8]) -> Result, TlvLvDataTooLargeError> { if data.len() > u8::MAX as usize { diff --git a/src/cfdp/pdu/ack.rs b/src/cfdp/pdu/ack.rs index 0947724..656bad7 100644 --- a/src/cfdp/pdu/ack.rs +++ b/src/cfdp/pdu/ack.rs @@ -81,22 +81,27 @@ impl AckPdu { .unwrap() } + #[inline] pub fn pdu_header(&self) -> &PduHeader { &self.pdu_header } + #[inline] pub fn directive_code_of_acked_pdu(&self) -> FileDirectiveType { self.directive_code_of_acked_pdu } + #[inline] pub fn condition_code(&self) -> ConditionCode { self.condition_code } + #[inline] pub fn transaction_status(&self) -> TransactionStatus { self.transaction_status } + #[inline] fn calc_pdu_datafield_len(&self) -> usize { if self.crc_flag() == CrcFlag::WithCrc { return 5; @@ -147,20 +152,9 @@ impl AckPdu { transaction_status, ) } -} -impl CfdpPdu for AckPdu { - fn pdu_header(&self) -> &PduHeader { - &self.pdu_header - } - - fn file_directive_type(&self) -> Option { - Some(FileDirectiveType::AckPdu) - } -} - -impl WritablePduPacket for AckPdu { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + /// Write [Self] to the provided buffer and returns the written size. + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { let expected_len = self.len_written(); if buf.len() < expected_len { return Err(ByteConversionError::ToSliceTooSmall { @@ -188,11 +182,33 @@ impl WritablePduPacket for AckPdu { Ok(current_idx) } - fn len_written(&self) -> usize { + pub fn len_written(&self) -> usize { self.pdu_header.header_len() + self.calc_pdu_datafield_len() } } +impl CfdpPdu for AckPdu { + #[inline] + fn pdu_header(&self) -> &PduHeader { + self.pdu_header() + } + + #[inline] + fn file_directive_type(&self) -> Option { + Some(FileDirectiveType::AckPdu) + } +} + +impl WritablePduPacket for AckPdu { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + fn len_written(&self) -> usize { + self.len_written() + } +} + #[cfg(test)] mod tests { use crate::cfdp::{ diff --git a/src/cfdp/pdu/eof.rs b/src/cfdp/pdu/eof.rs index 2461255..f2865cb 100644 --- a/src/cfdp/pdu/eof.rs +++ b/src/cfdp/pdu/eof.rs @@ -55,18 +55,22 @@ impl EofPdu { ) } + #[inline] pub fn pdu_header(&self) -> &PduHeader { &self.pdu_header } + #[inline] pub fn condition_code(&self) -> ConditionCode { self.condition_code } + #[inline] pub fn file_checksum(&self) -> u32 { self.file_checksum } + #[inline] pub fn file_size(&self) -> u64 { self.file_size } @@ -129,20 +133,9 @@ impl EofPdu { fault_location, }) } -} -impl CfdpPdu for EofPdu { - fn pdu_header(&self) -> &PduHeader { - &self.pdu_header - } - - fn file_directive_type(&self) -> Option { - Some(FileDirectiveType::EofPdu) - } -} - -impl WritablePduPacket for EofPdu { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + /// Write [Self] to the provided buffer and returns the written size. + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { let expected_len = self.len_written(); if buf.len() < expected_len { return Err(ByteConversionError::ToSliceTooSmall { @@ -172,11 +165,33 @@ impl WritablePduPacket for EofPdu { Ok(current_idx) } - fn len_written(&self) -> usize { + pub fn len_written(&self) -> usize { self.pdu_header.header_len() + self.calc_pdu_datafield_len() } } +impl CfdpPdu for EofPdu { + #[inline] + fn pdu_header(&self) -> &PduHeader { + self.pdu_header() + } + + #[inline] + fn file_directive_type(&self) -> Option { + Some(FileDirectiveType::EofPdu) + } +} + +impl WritablePduPacket for EofPdu { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + fn len_written(&self) -> usize { + self.len_written() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/cfdp/pdu/file_data.rs b/src/cfdp/pdu/file_data.rs index 686a523..e7a3f7c 100644 --- a/src/cfdp/pdu/file_data.rs +++ b/src/cfdp/pdu/file_data.rs @@ -10,8 +10,10 @@ use serde::{Deserialize, Serialize}; use super::{CfdpPdu, FileDirectiveType, WritablePduPacket}; -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u2, exhaustive = true)] #[repr(u8)] pub enum RecordContinuationState { NoStartNoEnd = 0b00, @@ -43,24 +45,27 @@ impl<'seg_meta> SegmentMetadata<'seg_meta> { }) } + #[inline] pub fn record_continuation_state(&self) -> RecordContinuationState { self.record_continuation_state } + #[inline] pub fn metadata(&self) -> Option<&'seg_meta [u8]> { self.metadata } - pub fn written_len(&self) -> usize { + #[inline] + pub fn len_written(&self) -> usize { // Map empty metadata to 0 and slice to its length. 1 + self.metadata.map_or(0, |meta| meta.len()) } pub(crate) fn write_to_bytes(&self, buf: &mut [u8]) -> Result { - if buf.len() < self.written_len() { + if buf.len() < self.len_written() { return Err(ByteConversionError::ToSliceTooSmall { found: buf.len(), - expected: self.written_len(), + expected: self.len_written(), }); } buf[0] = ((self.record_continuation_state as u8) << 6) @@ -68,7 +73,7 @@ impl<'seg_meta> SegmentMetadata<'seg_meta> { if let Some(metadata) = self.metadata { buf[1..1 + metadata.len()].copy_from_slice(metadata) } - Ok(self.written_len()) + Ok(self.len_written()) } pub(crate) fn from_bytes(buf: &'seg_meta [u8]) -> Result { @@ -102,10 +107,12 @@ struct FdPduBase<'seg_meta> { } impl CfdpPdu for FdPduBase<'_> { + #[inline] fn pdu_header(&self) -> &PduHeader { - &self.pdu_header + self.pdu_header() } + #[inline] fn file_directive_type(&self) -> Option { None } @@ -118,7 +125,7 @@ impl FdPduBase<'_> { len += 4; } if self.segment_metadata.is_some() { - len += self.segment_metadata.as_ref().unwrap().written_len() + len += self.segment_metadata.as_ref().unwrap().len_written() } len += file_data_len as usize; if self.crc_flag() == CrcFlag::WithCrc { @@ -143,6 +150,11 @@ impl FdPduBase<'_> { )?; Ok(current_idx) } + + #[inline] + pub fn pdu_header(&self) -> &PduHeader { + &self.pdu_header + } } /// File Data PDU abstraction. @@ -201,14 +213,22 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> { .calc_pdu_datafield_len(self.file_data.len() as u64) } + #[inline] pub fn segment_metadata(&self) -> Option<&SegmentMetadata<'_>> { self.common.segment_metadata.as_ref() } + #[inline] + pub fn pdu_header(&self) -> &PduHeader { + self.common.pdu_header() + } + + #[inline] pub fn offset(&self) -> u64 { self.common.offset } + #[inline] pub fn file_data(&self) -> &'file_data [u8] { self.file_data } @@ -221,7 +241,7 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> { let mut segment_metadata = None; if pdu_header.seg_metadata_flag == SegmentMetadataFlag::Present { segment_metadata = Some(SegmentMetadata::from_bytes(&buf[current_idx..])?); - current_idx += segment_metadata.as_ref().unwrap().written_len(); + current_idx += segment_metadata.as_ref().unwrap().len_written(); } let (fss, offset) = read_fss_field(pdu_header.pdu_conf.file_flag, &buf[current_idx..]); current_idx += fss; @@ -241,19 +261,9 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> { file_data: &buf[current_idx..full_len_without_crc], }) } -} -impl CfdpPdu for FileDataPdu<'_, '_> { - fn pdu_header(&self) -> &PduHeader { - &self.common.pdu_header - } - fn file_directive_type(&self) -> Option { - None - } -} - -impl WritablePduPacket for FileDataPdu<'_, '_> { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + /// Write [Self] to the provided buffer and returns the written size. + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { if buf.len() < self.len_written() { return Err(ByteConversionError::ToSliceTooSmall { found: buf.len(), @@ -271,10 +281,31 @@ impl WritablePduPacket for FileDataPdu<'_, '_> { Ok(current_idx) } - fn len_written(&self) -> usize { + pub fn len_written(&self) -> usize { self.common.pdu_header.header_len() + self.calc_pdu_datafield_len() } } +impl CfdpPdu for FileDataPdu<'_, '_> { + #[inline] + fn pdu_header(&self) -> &PduHeader { + &self.common.pdu_header + } + + #[inline] + fn file_directive_type(&self) -> Option { + None + } +} + +impl WritablePduPacket for FileDataPdu<'_, '_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + fn len_written(&self) -> usize { + self.len_written() + } +} /// File Data PDU creator abstraction. /// diff --git a/src/cfdp/pdu/finished.rs b/src/cfdp/pdu/finished.rs index a7b8261..fd0e935 100644 --- a/src/cfdp/pdu/finished.rs +++ b/src/cfdp/pdu/finished.rs @@ -109,23 +109,33 @@ impl<'fs_responses> FinishedPduCreator<'fs_responses> { finished_pdu } + #[inline] + pub fn pdu_header(&self) -> &PduHeader { + &self.pdu_header + } + + #[inline] pub fn condition_code(&self) -> ConditionCode { self.condition_code } + #[inline] pub fn delivery_code(&self) -> DeliveryCode { self.delivery_code } + #[inline] pub fn file_status(&self) -> FileStatus { self.file_status } // If there are no filestore responses, an empty slice will be returned. + #[inline] pub fn filestore_responses(&self) -> &[FilestoreResponseTlv<'_, '_, '_>] { self.fs_responses } + #[inline] pub fn fault_location(&self) -> Option { self.fault_location } @@ -143,20 +153,9 @@ impl<'fs_responses> FinishedPduCreator<'fs_responses> { } datafield_len } -} -impl CfdpPdu for FinishedPduCreator<'_> { - fn pdu_header(&self) -> &PduHeader { - &self.pdu_header - } - - fn file_directive_type(&self) -> Option { - Some(FileDirectiveType::FinishedPdu) - } -} - -impl WritablePduPacket for FinishedPduCreator<'_> { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + /// Write [Self] to the provided buffer and returns the written size. + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { let expected_len = self.len_written(); if buf.len() < expected_len { return Err(ByteConversionError::ToSliceTooSmall { @@ -185,11 +184,33 @@ impl WritablePduPacket for FinishedPduCreator<'_> { Ok(current_idx) } - fn len_written(&self) -> usize { + pub fn len_written(&self) -> usize { self.pdu_header.header_len() + self.calc_pdu_datafield_len() } } +impl CfdpPdu for FinishedPduCreator<'_> { + #[inline] + fn pdu_header(&self) -> &PduHeader { + self.pdu_header() + } + + #[inline] + fn file_directive_type(&self) -> Option { + Some(FileDirectiveType::FinishedPdu) + } +} + +impl WritablePduPacket for FinishedPduCreator<'_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + fn len_written(&self) -> usize { + self.len_written() + } +} + /// Helper structure to loop through all filestore responses of a read Finished PDU. It should be /// noted that iterators in Rust are not fallible, but the TLV creation can fail, for example if /// the raw TLV data is invalid for some reason. In that case, the iterator will yield [None] @@ -276,10 +297,12 @@ impl<'buf> FinishedPduReader<'buf> { }) } + #[inline] pub fn fs_responses_raw(&self) -> &[u8] { self.fs_responses_raw } + #[inline] pub fn fs_responses_iter(&self) -> FilestoreResponseIterator<'_> { FilestoreResponseIterator { responses_buf: self.fs_responses_raw, @@ -287,22 +310,31 @@ impl<'buf> FinishedPduReader<'buf> { } } + #[inline] pub fn condition_code(&self) -> ConditionCode { self.condition_code } + #[inline] pub fn delivery_code(&self) -> DeliveryCode { self.delivery_code } + #[inline] pub fn file_status(&self) -> FileStatus { self.file_status } + #[inline] pub fn fault_location(&self) -> Option { self.fault_location } + #[inline] + pub fn pdu_header(&self) -> &PduHeader { + &self.pdu_header + } + fn parse_tlv_fields( mut current_idx: usize, full_len_without_crc: usize, @@ -360,10 +392,12 @@ impl<'buf> FinishedPduReader<'buf> { } impl CfdpPdu for FinishedPduReader<'_> { + #[inline] fn pdu_header(&self) -> &PduHeader { - &self.pdu_header + self.pdu_header() } + #[inline] fn file_directive_type(&self) -> Option { Some(FileDirectiveType::FinishedPdu) } diff --git a/src/cfdp/pdu/metadata.rs b/src/cfdp/pdu/metadata.rs index f1ae30d..115bf65 100644 --- a/src/cfdp/pdu/metadata.rs +++ b/src/cfdp/pdu/metadata.rs @@ -128,18 +128,27 @@ impl<'src_name, 'dest_name, 'opts> MetadataPduCreator<'src_name, 'dest_name, 'op pdu } + #[inline] pub fn metadata_params(&self) -> &MetadataGenericParams { &self.metadata_params } + #[inline] pub fn src_file_name(&self) -> Lv<'src_name> { self.src_file_name } + #[inline] pub fn dest_file_name(&self) -> Lv<'dest_name> { self.dest_file_name } + #[inline] + pub fn pdu_header(&self) -> &PduHeader { + &self.pdu_header + } + + #[inline] pub fn options(&self) -> &'opts [u8] { self.options } @@ -169,20 +178,9 @@ impl<'src_name, 'dest_name, 'opts> MetadataPduCreator<'src_name, 'dest_name, 'op } len } -} -impl CfdpPdu for MetadataPduCreator<'_, '_, '_> { - fn pdu_header(&self) -> &PduHeader { - &self.pdu_header - } - - fn file_directive_type(&self) -> Option { - Some(FileDirectiveType::MetadataPdu) - } -} - -impl WritablePduPacket for MetadataPduCreator<'_, '_, '_> { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + /// Write [Self] to the provided buffer and returns the written size. + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { let expected_len = self.len_written(); if buf.len() < expected_len { return Err(ByteConversionError::ToSliceTooSmall { @@ -217,11 +215,33 @@ impl WritablePduPacket for MetadataPduCreator<'_, '_, '_> { Ok(current_idx) } - fn len_written(&self) -> usize { + pub fn len_written(&self) -> usize { self.pdu_header.header_len() + self.calc_pdu_datafield_len() } } +impl CfdpPdu for MetadataPduCreator<'_, '_, '_> { + #[inline] + fn pdu_header(&self) -> &PduHeader { + self.pdu_header() + } + + #[inline] + fn file_directive_type(&self) -> Option { + Some(FileDirectiveType::MetadataPdu) + } +} + +impl WritablePduPacket for MetadataPduCreator<'_, '_, '_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + fn len_written(&self) -> usize { + self.len_written() + } +} + /// Helper structure to loop through all options of a metadata PDU. It should be noted that /// iterators in Rust are not fallible, but the TLV creation can fail, for example if the raw TLV /// data is invalid for some reason. In that case, the iterator will yield [None] because there @@ -330,26 +350,36 @@ impl<'raw> MetadataPduReader<'raw> { }) } + #[inline] + pub fn pdu_header(&self) -> &PduHeader { + &self.pdu_header + } + + #[inline] pub fn options(&self) -> &'raw [u8] { self.options } + #[inline] pub fn metadata_params(&self) -> &MetadataGenericParams { &self.metadata_params } + #[inline] pub fn src_file_name(&self) -> Lv<'_> { self.src_file_name } + #[inline] pub fn dest_file_name(&self) -> Lv<'_> { self.dest_file_name } } impl CfdpPdu for MetadataPduReader<'_> { + #[inline] fn pdu_header(&self) -> &PduHeader { - &self.pdu_header + self.pdu_header() } fn file_directive_type(&self) -> Option { diff --git a/src/cfdp/pdu/mod.rs b/src/cfdp/pdu/mod.rs index e1c511e..b62e7e4 100644 --- a/src/cfdp/pdu/mod.rs +++ b/src/cfdp/pdu/mod.rs @@ -311,6 +311,8 @@ pub struct PduHeader { } impl PduHeader { + pub const FIXED_LEN: usize = FIXED_HEADER_LEN; + #[inline] pub fn new_for_file_data( pdu_conf: CommonPduConfig, @@ -565,6 +567,7 @@ impl PduHeader { &self.pdu_conf } + #[inline] pub fn seg_metadata_flag(&self) -> SegmentMetadataFlag { self.seg_metadata_flag } diff --git a/src/cfdp/pdu/nak.rs b/src/cfdp/pdu/nak.rs index 7695993..a631693 100644 --- a/src/cfdp/pdu/nak.rs +++ b/src/cfdp/pdu/nak.rs @@ -18,6 +18,7 @@ pub enum SegmentRequests<'a> { } impl SegmentRequests<'_> { + #[inline] pub fn is_empty(&self) -> bool { match self { SegmentRequests::U32Pairs(pairs) => pairs.is_empty(), @@ -122,14 +123,17 @@ impl<'seg_reqs> NakPduCreator<'seg_reqs> { Ok(nak_pdu) } + #[inline] pub fn start_of_scope(&self) -> u64 { self.start_of_scope } + #[inline] pub fn end_of_scope(&self) -> u64 { self.end_of_scope } + #[inline] pub fn segment_requests(&self) -> Option<&SegmentRequests<'_>> { self.segment_requests.as_ref() } @@ -144,6 +148,7 @@ impl<'seg_reqs> NakPduCreator<'seg_reqs> { } } + #[inline] pub fn pdu_header(&self) -> &PduHeader { &self.pdu_header } @@ -162,20 +167,9 @@ impl<'seg_reqs> NakPduCreator<'seg_reqs> { } datafield_len } -} -impl CfdpPdu for NakPduCreator<'_> { - fn pdu_header(&self) -> &PduHeader { - &self.pdu_header - } - - fn file_directive_type(&self) -> Option { - Some(FileDirectiveType::NakPdu) - } -} - -impl WritablePduPacket for NakPduCreator<'_> { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + /// Write [Self] to the provided buffer and returns the written size. + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { let expected_len = self.len_written(); if buf.len() < expected_len { return Err(ByteConversionError::ToSliceTooSmall { @@ -238,11 +232,35 @@ impl WritablePduPacket for NakPduCreator<'_> { Ok(current_idx) } + #[inline] fn len_written(&self) -> usize { self.pdu_header.header_len() + self.calc_pdu_datafield_len() } } +impl CfdpPdu for NakPduCreator<'_> { + #[inline] + fn pdu_header(&self) -> &PduHeader { + self.pdu_header() + } + + #[inline] + fn file_directive_type(&self) -> Option { + Some(FileDirectiveType::NakPdu) + } +} + +impl WritablePduPacket for NakPduCreator<'_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + #[inline] + fn len_written(&self) -> usize { + self.len_written() + } +} + /// Special iterator type for the NAK PDU which allows to iterate over both normal and large file /// segment requests. #[derive(Debug)] diff --git a/src/cfdp/tlv/mod.rs b/src/cfdp/tlv/mod.rs index d0fd38f..a580031 100644 --- a/src/cfdp/tlv/mod.rs +++ b/src/cfdp/tlv/mod.rs @@ -26,6 +26,7 @@ pub trait GenericTlv { /// Checks whether the type field contains one of the standard types specified in the CFDP /// standard and is part of the [TlvType] enum. + #[inline] fn is_standard_tlv(&self) -> bool { if let TlvTypeField::Standard(_) = self.tlv_type_field() { return true; @@ -34,6 +35,7 @@ pub trait GenericTlv { } /// Returns the standard TLV type if the TLV field is not a custom field + #[inline] fn tlv_type(&self) -> Option { if let TlvTypeField::Standard(tlv_type) = self.tlv_type_field() { Some(tlv_type) @@ -47,17 +49,20 @@ pub trait ReadableTlv { fn value(&self) -> &[u8]; /// Checks whether the value field is empty. + #[inline] fn is_empty(&self) -> bool { self.value().is_empty() } /// Helper method to retrieve the length of the value. Simply calls the [slice::len] method of /// [Self::value] + #[inline] fn len_value(&self) -> usize { self.value().len() } /// Returns the full raw length, including the length byte. + #[inline] fn len_full(&self) -> usize { self.len_value() + 2 } @@ -153,6 +158,8 @@ pub struct Tlv<'data> { } impl<'data> Tlv<'data> { + pub const MIN_LEN: usize = MIN_TLV_LEN; + pub fn new(tlv_type: TlvType, data: &[u8]) -> Result, TlvLvDataTooLargeError> { Ok(Tlv { tlv_type_field: TlvTypeField::Standard(tlv_type), @@ -196,6 +203,7 @@ impl<'data> Tlv<'data> { /// If the TLV was generated from a raw bytestream using [Self::from_bytes], the raw start /// of the TLV can be retrieved with this method. + #[inline] pub fn raw_data(&self) -> Option<&[u8]> { self.lv.raw_data() } @@ -229,12 +237,15 @@ impl WritableTlv for Tlv<'_> { self.lv.write_to_be_bytes_no_len_check(&mut buf[1..]); Ok(self.len_full()) } + + #[inline] fn len_written(&self) -> usize { self.len_full() } } impl GenericTlv for Tlv<'_> { + #[inline] fn tlv_type_field(&self) -> TlvTypeField { self.tlv_type_field } @@ -277,6 +288,19 @@ pub mod alloc_mod { } } + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + generic_len_check_data_serialization(buf, self.data.len(), MIN_TLV_LEN)?; + buf[0] = self.tlv_type_field.into(); + buf[1] = self.data.len() as u8; + buf[2..2 + self.data.len()].copy_from_slice(&self.data); + Ok(self.len_written()) + } + + #[inline] + fn len_written(&self) -> usize { + self.data.len() + 2 + } + pub fn as_tlv(&self) -> Tlv<'_> { Tlv { tlv_type_field: self.tlv_type_field, @@ -288,6 +312,7 @@ pub mod alloc_mod { } impl ReadableTlv for TlvOwned { + #[inline] fn value(&self) -> &[u8] { &self.data } @@ -295,19 +320,17 @@ pub mod alloc_mod { impl WritableTlv for TlvOwned { fn write_to_bytes(&self, buf: &mut [u8]) -> Result { - generic_len_check_data_serialization(buf, self.data.len(), MIN_TLV_LEN)?; - buf[0] = self.tlv_type_field.into(); - buf[1] = self.data.len() as u8; - buf[2..2 + self.data.len()].copy_from_slice(&self.data); - Ok(self.len_written()) + self.write_to_bytes(buf) } + #[inline] fn len_written(&self) -> usize { - self.data.len() + 2 + self.len_written() } } impl GenericTlv for TlvOwned { + #[inline] fn tlv_type_field(&self) -> TlvTypeField { self.tlv_type_field } @@ -334,6 +357,7 @@ pub struct EntityIdTlv { } impl EntityIdTlv { + #[inline] pub fn new(entity_id: UnsignedByteField) -> Self { Self { entity_id } } @@ -348,14 +372,17 @@ impl EntityIdTlv { Ok(()) } + #[inline] pub fn entity_id(&self) -> &UnsignedByteField { &self.entity_id } + #[inline] pub fn len_value(&self) -> usize { self.entity_id.size() } + #[inline] pub fn len_full(&self) -> usize { 2 + self.entity_id.size() } @@ -380,9 +407,7 @@ impl EntityIdTlv { // Can't fail. Ok(Tlv::new(TlvType::EntityId, &buf[2..2 + self.entity_id.size()]).unwrap()) } -} -impl WritableTlv for EntityIdTlv { fn write_to_bytes(&self, buf: &mut [u8]) -> Result { Self::len_check(buf)?; buf[0] = TlvType::EntityId as u8; @@ -390,12 +415,25 @@ impl WritableTlv for EntityIdTlv { Ok(2 + self.entity_id.write_to_be_bytes(&mut buf[2..])?) } + #[inline] fn len_written(&self) -> usize { self.len_full() } } +impl WritableTlv for EntityIdTlv { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + #[inline] + fn len_written(&self) -> usize { + self.len_written() + } +} + impl GenericTlv for EntityIdTlv { + #[inline] fn tlv_type_field(&self) -> TlvTypeField { TlvTypeField::Standard(TlvType::EntityId) } @@ -440,6 +478,7 @@ impl TryFrom> for EntityIdTlv { } } +#[inline] pub fn fs_request_has_second_filename(action_code: FilestoreActionCode) -> bool { if action_code == FilestoreActionCode::RenameFile || action_code == FilestoreActionCode::AppendFile @@ -462,6 +501,7 @@ struct FilestoreTlvBase<'first_name, 'second_name> { } impl FilestoreTlvBase<'_, '_> { + #[inline] fn base_len_value(&self) -> usize { let mut len = 1 + self.first_name.len_full(); if let Some(second_name) = self.second_name { @@ -571,22 +611,27 @@ impl<'first_name, 'second_name> FilestoreRequestTlv<'first_name, 'second_name> { }) } + #[inline] pub fn action_code(&self) -> FilestoreActionCode { self.base.action_code } + #[inline] pub fn first_name(&self) -> Lv<'first_name> { self.base.first_name } + #[inline] pub fn second_name(&self) -> Option> { self.base.second_name } + #[inline] pub fn len_value(&self) -> usize { self.base.base_len_value() } + #[inline] pub fn len_full(&self) -> usize { 2 + self.len_value() } @@ -625,9 +670,7 @@ impl<'first_name, 'second_name> FilestoreRequestTlv<'first_name, 'second_name> { }, }) } -} -impl WritableTlv for FilestoreRequestTlv<'_, '_> { fn write_to_bytes(&self, buf: &mut [u8]) -> Result { if buf.len() < self.len_full() { return Err(ByteConversionError::ToSliceTooSmall { @@ -653,12 +696,25 @@ impl WritableTlv for FilestoreRequestTlv<'_, '_> { Ok(current_idx) } + #[inline] fn len_written(&self) -> usize { self.len_full() } } +impl WritableTlv for FilestoreRequestTlv<'_, '_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + #[inline] + fn len_written(&self) -> usize { + self.len_written() + } +} + impl GenericTlv for FilestoreRequestTlv<'_, '_> { + #[inline] fn tlv_type_field(&self) -> TlvTypeField { TlvTypeField::Standard(TlvType::FilestoreRequest) } @@ -733,26 +789,32 @@ impl<'first_name, 'second_name, 'fs_msg> FilestoreResponseTlv<'first_name, 'seco false } + #[inline] pub fn action_code(&self) -> FilestoreActionCode { self.base.action_code } + #[inline] pub fn status_code(&self) -> u8 { self.status_code } + #[inline] pub fn first_name(&self) -> Lv<'first_name> { self.base.first_name } + #[inline] pub fn second_name(&self) -> Option> { self.base.second_name } + #[inline] pub fn len_value(&self) -> usize { self.base.base_len_value() + self.filestore_message.len_full() } + #[inline] pub fn len_full(&self) -> usize { 2 + self.len_value() } @@ -810,9 +872,7 @@ impl<'first_name, 'second_name, 'fs_msg> FilestoreResponseTlv<'first_name, 'seco filestore_message, }) } -} -impl WritableTlv for FilestoreResponseTlv<'_, '_, '_> { fn write_to_bytes(&self, buf: &mut [u8]) -> Result { if buf.len() < self.len_full() { return Err(ByteConversionError::ToSliceTooSmall { @@ -845,7 +905,19 @@ impl WritableTlv for FilestoreResponseTlv<'_, '_, '_> { } } +impl WritableTlv for FilestoreResponseTlv<'_, '_, '_> { + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.write_to_bytes(buf) + } + + #[inline] + fn len_written(&self) -> usize { + self.len_written() + } +} + impl GenericTlv for FilestoreResponseTlv<'_, '_, '_> { + #[inline] fn tlv_type_field(&self) -> TlvTypeField { TlvTypeField::Standard(TlvType::FilestoreResponse) } diff --git a/src/cfdp/tlv/msg_to_user.rs b/src/cfdp/tlv/msg_to_user.rs index 5dc7346..f3fe04a 100644 --- a/src/cfdp/tlv/msg_to_user.rs +++ b/src/cfdp/tlv/msg_to_user.rs @@ -37,10 +37,12 @@ impl<'data> MsgToUserTlv<'data> { } } + #[inline] pub fn is_standard_tlv(&self) -> bool { true } + #[inline] pub fn tlv_type(&self) -> Option { Some(TlvType::MsgToUser) } @@ -83,6 +85,7 @@ impl<'data> MsgToUserTlv<'data> { Ok(msg_to_user) } + #[inline] pub fn to_tlv(&self) -> Tlv<'data> { self.tlv } @@ -91,6 +94,17 @@ impl<'data> MsgToUserTlv<'data> { pub fn to_owned(&self) -> TlvOwned { self.tlv.to_owned() } + + #[inline] + fn len_written(&self) -> usize { + self.len_full() + } + + delegate!( + to self.tlv { + pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result; + } + ); } impl<'a> From> for Tlv<'a> { @@ -100,18 +114,18 @@ impl<'a> From> for Tlv<'a> { } impl WritableTlv for MsgToUserTlv<'_> { + #[inline] fn len_written(&self) -> usize { - self.len_full() + self.len_written() } - delegate!( - to self.tlv { - fn write_to_bytes(&self, buf: &mut [u8]) -> Result; - } - ); + fn write_to_bytes(&self, buf: &mut [u8]) -> Result { + self.tlv.write_to_bytes(buf) + } } impl GenericTlv for MsgToUserTlv<'_> { + #[inline] fn tlv_type_field(&self) -> TlvTypeField { self.tlv.tlv_type_field() } diff --git a/src/ecss/tc.rs b/src/ecss/tc.rs index ba3c7bf..81dcd7f 100644 --- a/src/ecss/tc.rs +++ b/src/ecss/tc.rs @@ -583,6 +583,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { /// * `sec_header` - Information contained in the secondary header, including the service /// and subservice type /// * `app_data_len` - Custom application data length + /// * `has_checksum` - Packet should have a CRC-16-CCITT checksum appended at the end #[inline] pub fn new( buf: &'buf mut [u8], @@ -716,6 +717,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { } } +/// Builder API to create a [PusTcCreator]. #[derive(Debug)] pub struct PusTcBuilder<'a> { sp_header: SpHeader, @@ -813,6 +815,7 @@ impl<'a> PusTcBuilder<'a> { ) } + #[inline] pub fn with_app_data(mut self, app_data: &'a [u8]) -> Self { self.app_data = app_data; self @@ -844,10 +847,7 @@ pub struct PusTcReader<'raw_data> { impl<'raw_data> PusTcReader<'raw_data> { /// Create a [PusTcReader] instance from a raw slice. The given packet should have a - /// a CRC16-CCITT checksum which is also verified. - /// - /// On success, it returns a tuple containing the instance and the found byte length of the - /// packet. This function also expects a CRC16 checksum and will verify it. + /// a CRC-16-CCITT checksum which is also verified. pub fn new(slice: &'raw_data [u8]) -> Result { let pus_tc = Self::new_no_checksum_verification(slice, true)?; // Unwrap for CRC16 okay, should always have some value. diff --git a/src/ecss/tm.rs b/src/ecss/tm.rs index ee995e7..e887ad5 100644 --- a/src/ecss/tm.rs +++ b/src/ecss/tm.rs @@ -920,8 +920,7 @@ pub struct PusTmReader<'raw_data> { } impl<'raw_data> PusTmReader<'raw_data> { - /// Create a [PusTmReader] instance from a raw slice. On success, it returns a tuple containing - /// the instance and the found byte length of the packet. The timestamp length needs to be + /// Create a [PusTmReader] instance from a raw slice. The timestamp length needs to be /// known beforehand. /// /// This function will verify the CRC-16-CCITT of the PUS packet and will return an appropriate @@ -957,6 +956,8 @@ impl<'raw_data> PusTmReader<'raw_data> { Ok(tc) } + /// Create a [PusTmReader] instance from a raw slice. The timestamp length needs to be + /// known beforehand. This variant can be used to parse packets without a checksum. pub fn new_no_checksum(slice: &'raw_data [u8], timestamp_len: usize) -> Result { Self::new_no_checksum_verification( slice, @@ -966,6 +967,7 @@ impl<'raw_data> PusTmReader<'raw_data> { }, ) } + pub fn new_no_checksum_verification( slice: &'raw_data [u8], reader_config: ReaderConfig, @@ -1200,16 +1202,13 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { Some(writer) } - /// Set the sequence count. Returns false and does not update the value if the passed value - /// exceeds [MAX_APID]. #[inline] - pub fn set_apid(&mut self, apid: u11) -> bool { + pub fn set_apid(&mut self, apid: u11) { // Clear APID part of the raw packet ID let updated_apid = ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16) & !MAX_APID.as_u16()) | apid.as_u16(); self.raw_tm[0..2].copy_from_slice(&updated_apid.to_be_bytes()); - true } /// This function sets the message counter in the PUS TM secondary header. @@ -1243,11 +1242,10 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { } #[inline] - pub fn set_seq_count(&mut self, seq_count: u14) -> bool { + pub fn set_seq_count(&mut self, seq_count: u14) { let new_psc = (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000) | seq_count.as_u16(); self.raw_tm[2..4].copy_from_slice(&new_psc.to_be_bytes()); - true } /// This method has to be called after modifying fields to ensure the CRC16 of the telemetry diff --git a/src/lib.rs b/src/lib.rs index c1e60ec..3854ea0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -203,10 +203,10 @@ impl PacketId { } #[inline] - pub const fn new(ptype: PacketType, sec_header: bool, apid: u11) -> Self { + pub const fn new(packet_type: PacketType, sec_header_flag: bool, apid: u11) -> Self { PacketId { - packet_type: ptype, - sec_header_flag: sec_header, + packet_type, + sec_header_flag, apid, } } @@ -412,6 +412,8 @@ impl Default for SpHeader { } impl SpHeader { + pub const HEADER_LEN: usize = CCSDS_HEADER_LEN; + #[inline] pub const fn new(packet_id: PacketId, psc: PacketSequenceControl, data_len: u16) -> Self { Self { @@ -424,8 +426,6 @@ impl SpHeader { /// This constructor sets the sequence flag field to [SequenceFlags::Unsegmented] and the data /// length to 0. - /// - /// This constructor will panic if the APID exceeds [MAX_APID]. #[inline] pub const fn new_from_apid(apid: u11) -> Self { SpHeader { @@ -439,10 +439,6 @@ impl SpHeader { } } - /// This constructor panics if the passed APID exceeds [MAX_APID] or the passed packet sequence - /// count exceeds [MAX_SEQ_COUNT]. - /// - /// The checked constructor variants can be used to avoid panics. #[inline] pub const fn new_from_fields( ptype: PacketType, @@ -460,7 +456,6 @@ impl SpHeader { } } - /// This is an unchecked constructor which can panic on invalid input. #[inline] pub const fn new_for_tm( apid: u11, @@ -471,7 +466,6 @@ impl SpHeader { Self::new_from_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len) } - /// This is an unchecked constructor which can panic on invalid input. #[inline] pub const fn new_for_tc( apid: u11, @@ -483,16 +477,12 @@ impl SpHeader { } /// Variant of [SpHeader::new_for_tc] which sets the sequence flag field to [SequenceFlags::Unsegmented]. - /// - /// This is an unchecked constructor which can panic on invalid input. #[inline] pub const fn new_for_unseg_tc(apid: u11, seq_count: u14, data_len: u16) -> Self { Self::new_for_tc(apid, SequenceFlags::Unsegmented, seq_count, data_len) } /// Variant of [SpHeader::new_for_tm] which sets the sequence flag field to [SequenceFlags::Unsegmented]. - /// - /// This is an unchecked constructor which can panic on invalid input. #[inline] pub const fn new_for_unseg_tm(apid: u11, seq_count: u14, data_len: u16) -> Self { Self::new_for_tm(apid, SequenceFlags::Unsegmented, seq_count, data_len) @@ -508,7 +498,7 @@ impl SpHeader { /// Retrieve the total packet size based on the data length field #[inline] fn packet_len(&self) -> usize { - usize::from(self.data_len()) + CCSDS_HEADER_LEN + 1 + usize::from(self.data_len()) + Self::HEADER_LEN + 1 } #[inline] @@ -540,15 +530,15 @@ impl SpHeader { /// This function also returns the remaining part of the passed slice starting past the read /// CCSDS header. pub fn from_be_bytes(buf: &[u8]) -> Result<(Self, &[u8]), ByteConversionError> { - if buf.len() < CCSDS_HEADER_LEN { + if buf.len() < Self::HEADER_LEN { return Err(ByteConversionError::FromSliceTooSmall { found: buf.len(), expected: CCSDS_HEADER_LEN, }); } // Unwrap okay, this can not fail. - let zc_header = zc::SpHeader::read_from_bytes(&buf[0..CCSDS_HEADER_LEN]).unwrap(); - Ok((Self::from(zc_header), &buf[CCSDS_HEADER_LEN..])) + let zc_header = zc::SpHeader::read_from_bytes(&buf[0..Self::HEADER_LEN]).unwrap(); + Ok((Self::from(zc_header), &buf[Self::HEADER_LEN..])) } /// Write the header to a raw buffer using big endian format. This function returns the @@ -557,7 +547,7 @@ impl SpHeader { &self, buf: &'a mut [u8], ) -> Result<&'a mut [u8], ByteConversionError> { - if buf.len() < CCSDS_HEADER_LEN { + if buf.len() < Self::HEADER_LEN { return Err(ByteConversionError::FromSliceTooSmall { found: buf.len(), expected: CCSDS_HEADER_LEN, @@ -565,14 +555,14 @@ impl SpHeader { } let zc_header: zc::SpHeader = zc::SpHeader::from(*self); // Unwrap okay, this can not fail. - zc_header.write_to(&mut buf[0..CCSDS_HEADER_LEN]).unwrap(); - Ok(&mut buf[CCSDS_HEADER_LEN..]) + zc_header.write_to(&mut buf[0..Self::HEADER_LEN]).unwrap(); + Ok(&mut buf[Self::HEADER_LEN..]) } /// Create a vector containing the CCSDS header. #[cfg(feature = "alloc")] pub fn to_vec(&self) -> alloc::vec::Vec { - let mut vec = alloc::vec![0; CCSDS_HEADER_LEN]; + let mut vec = alloc::vec![0; Self::HEADER_LEN]; // This can not fail. self.write_to_be_bytes(&mut vec[..]).unwrap(); vec