Merge pull request 'improve CFDP module' (#153) from cfdp-module-improvements into main

Reviewed-on: #153
This commit was merged in pull request #153.
This commit is contained in:
2025-09-11 09:12:59 +02:00
13 changed files with 368 additions and 145 deletions

View File

@@ -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<Lv<'_>, TlvLvDataTooLargeError> {
if data.len() > u8::MAX as usize {

View File

@@ -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<FileDirectiveType> {
Some(FileDirectiveType::AckPdu)
}
}
impl WritablePduPacket for AckPdu {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
/// Write [Self] to the provided buffer and returns the written size.
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {
Some(FileDirectiveType::AckPdu)
}
}
impl WritablePduPacket for AckPdu {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
self.write_to_bytes(buf)
}
fn len_written(&self) -> usize {
self.len_written()
}
}
#[cfg(test)]
mod tests {
use crate::cfdp::{

View File

@@ -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<FileDirectiveType> {
Some(FileDirectiveType::EofPdu)
}
}
impl WritablePduPacket for EofPdu {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
/// Write [Self] to the provided buffer and returns the written size.
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {
Some(FileDirectiveType::EofPdu)
}
}
impl WritablePduPacket for EofPdu {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
self.write_to_bytes(buf)
}
fn len_written(&self) -> usize {
self.len_written()
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -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<usize, ByteConversionError> {
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<Self, ByteConversionError> {
@@ -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<FileDirectiveType> {
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<FileDirectiveType> {
None
}
}
impl WritablePduPacket for FileDataPdu<'_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
/// Write [Self] to the provided buffer and returns the written size.
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {
None
}
}
impl WritablePduPacket for FileDataPdu<'_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
self.write_to_bytes(buf)
}
fn len_written(&self) -> usize {
self.len_written()
}
}
/// File Data PDU creator abstraction.
///

View File

@@ -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<EntityIdTlv> {
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<FileDirectiveType> {
Some(FileDirectiveType::FinishedPdu)
}
}
impl WritablePduPacket for FinishedPduCreator<'_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
/// Write [Self] to the provided buffer and returns the written size.
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {
Some(FileDirectiveType::FinishedPdu)
}
}
impl WritablePduPacket for FinishedPduCreator<'_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<EntityIdTlv> {
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<FileDirectiveType> {
Some(FileDirectiveType::FinishedPdu)
}

View File

@@ -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<FileDirectiveType> {
Some(FileDirectiveType::MetadataPdu)
}
}
impl WritablePduPacket for MetadataPduCreator<'_, '_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
/// Write [Self] to the provided buffer and returns the written size.
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {
Some(FileDirectiveType::MetadataPdu)
}
}
impl WritablePduPacket for MetadataPduCreator<'_, '_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {

View File

@@ -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
}

View File

@@ -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<FileDirectiveType> {
Some(FileDirectiveType::NakPdu)
}
}
impl WritablePduPacket for NakPduCreator<'_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
/// Write [Self] to the provided buffer and returns the written size.
pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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<FileDirectiveType> {
Some(FileDirectiveType::NakPdu)
}
}
impl WritablePduPacket for NakPduCreator<'_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
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)]

View File

@@ -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<TlvType> {
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<Tlv<'_>, 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<usize, ByteConversionError> {
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<usize, ByteConversionError> {
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<usize, ByteConversionError> {
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<usize, ByteConversionError> {
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<Tlv<'_>> 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<Lv<'second_name>> {
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<usize, ByteConversionError> {
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<usize, ByteConversionError> {
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<Lv<'second_name>> {
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<usize, ByteConversionError> {
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<usize, ByteConversionError> {
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)
}

View File

@@ -37,10 +37,12 @@ impl<'data> MsgToUserTlv<'data> {
}
}
#[inline]
pub fn is_standard_tlv(&self) -> bool {
true
}
#[inline]
pub fn tlv_type(&self) -> Option<TlvType> {
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<usize, ByteConversionError>;
}
);
}
impl<'a> From<MsgToUserTlv<'a>> for Tlv<'a> {
@@ -100,18 +114,18 @@ impl<'a> From<MsgToUserTlv<'a>> 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<usize, ByteConversionError>;
}
);
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, ByteConversionError> {
self.tlv.write_to_bytes(buf)
}
}
impl GenericTlv for MsgToUserTlv<'_> {
#[inline]
fn tlv_type_field(&self) -> TlvTypeField {
self.tlv.tlv_type_field()
}

View File

@@ -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<Self, PusError> {
let pus_tc = Self::new_no_checksum_verification(slice, true)?;
// Unwrap for CRC16 okay, should always have some value.

View File

@@ -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, PusError> {
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

View File

@@ -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<u8> {
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