Merge pull request 'custom impl for CommonPduConfig PartialEq' (#40) from common-pdu-abstractions into main
All checks were successful
Rust/spacepackets/pipeline/head This commit looks good

Reviewed-on: #40
This commit is contained in:
Robin Müller 2023-11-25 19:21:22 +01:00
commit 478f8aa216
6 changed files with 143 additions and 21 deletions

View File

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Added ## Added
- Add `WritablePduPacket` trait which is a common trait of all CFDP PDU implementations. - Add `WritablePduPacket` trait which is a common trait of all CFDP PDU implementations.
- Add `CfdpPdu` trait which exposes fields and attributes common to all CFDP PDUs.
## Fixed ## Fixed
@ -21,6 +22,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Renamed `SerializablePusPacket` to `WritablePusPacket`. - Renamed `SerializablePusPacket` to `WritablePusPacket`.
- Renamed `WritablePduPacket.written_len` and `SerializablePusPacket.len_packed` to `len_written`. - Renamed `WritablePduPacket.written_len` and `SerializablePusPacket.len_packed` to `len_written`.
- Introduce custom implementation of `PartialEq` for `CommonPduConfig` which only compares the
values for the source entity ID, destination entity ID and transaction sequence number field to
allow those fields to have different widths.
# [v0.7.0-beta.2] 2023-09-26 # [v0.7.0-beta.2] 2023-09-26
@ -112,7 +116,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
`PusTm` object. `PusTm` object.
## Changed ## Changed
- The `EcssEnumeration` now requires the `UnsignedEnum` trait and only adds the `pfc` method to it. - The `EcssEnumeration` now requires the `UnsignedEnum` trait and only adds the `pfc` method to it.
- Renamed `byte_width` usages to `size` (part of new `UnsignedEnum` trait) - Renamed `byte_width` usages to `size` (part of new `UnsignedEnum` trait)
- Moved `ecss::CRC_CCITT_FALSE` CRC constant to the root module. This CRC type is not just used by - Moved `ecss::CRC_CCITT_FALSE` CRC constant to the root module. This CRC type is not just used by

View File

@ -8,7 +8,7 @@ use crate::ByteConversionError;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket; use super::{CfdpPdu, WritablePduPacket};
/// Finished PDU abstraction. /// Finished PDU abstraction.
/// ///
@ -111,6 +111,16 @@ impl EofPdu {
} }
} }
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 { impl WritablePduPacket for EofPdu {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> { fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.len_written(); let expected_len = self.len_written();

View File

@ -8,7 +8,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket; use super::{CfdpPdu, FileDirectiveType, 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))]
@ -191,6 +191,15 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> {
}) })
} }
} }
impl CfdpPdu for FileDataPdu<'_, '_> {
fn pdu_header(&self) -> &PduHeader {
&self.pdu_header
}
fn file_directive_type(&self) -> Option<FileDirectiveType> {
None
}
}
impl WritablePduPacket for FileDataPdu<'_, '_> { impl WritablePduPacket for FileDataPdu<'_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> { fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {

View File

@ -8,7 +8,7 @@ use num_enum::{IntoPrimitive, TryFromPrimitive};
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket; use super::{CfdpPdu, 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))]
@ -98,9 +98,6 @@ impl<'fs_responses> FinishedPdu<'fs_responses> {
finished_pdu.pdu_header.pdu_datafield_len = finished_pdu.calc_pdu_datafield_len() as u16; finished_pdu.pdu_header.pdu_datafield_len = finished_pdu.calc_pdu_datafield_len() as u16;
finished_pdu finished_pdu
} }
pub fn pdu_header(&self) -> &PduHeader {
&self.pdu_header
}
pub fn condition_code(&self) -> ConditionCode { pub fn condition_code(&self) -> ConditionCode {
self.condition_code self.condition_code
@ -214,6 +211,16 @@ impl<'fs_responses> FinishedPdu<'fs_responses> {
} }
} }
impl CfdpPdu for FinishedPdu<'_> {
fn pdu_header(&self) -> &PduHeader {
&self.pdu_header
}
fn file_directive_type(&self) -> Option<FileDirectiveType> {
Some(FileDirectiveType::FinishedPdu)
}
}
impl WritablePduPacket for FinishedPdu<'_> { impl WritablePduPacket for FinishedPdu<'_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> { fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.len_written(); let expected_len = self.len_written();

View File

@ -11,7 +11,7 @@ use alloc::vec::Vec;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::WritablePduPacket; use super::{CfdpPdu, 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))]
@ -193,10 +193,6 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
len len
} }
pub fn pdu_header(&self) -> &PduHeader {
&self.pdu_header
}
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> {
@ -250,6 +246,16 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
} }
} }
impl CfdpPdu for MetadataPdu<'_, '_, '_> {
fn pdu_header(&self) -> &PduHeader {
&self.pdu_header
}
fn file_directive_type(&self) -> Option<FileDirectiveType> {
Some(FileDirectiveType::MetadataPdu)
}
}
impl WritablePduPacket for MetadataPdu<'_, '_, '_> { impl WritablePduPacket for MetadataPdu<'_, '_, '_> {
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> { fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError> {
let expected_len = self.len_written(); let expected_len = self.len_written();
@ -300,12 +306,15 @@ pub mod tests {
build_metadata_opts_from_slice, build_metadata_opts_from_vec, MetadataGenericParams, build_metadata_opts_from_slice, build_metadata_opts_from_vec, MetadataGenericParams,
MetadataPdu, MetadataPdu,
}; };
use crate::cfdp::pdu::tests::{common_pdu_conf, verify_raw_header}; use crate::cfdp::pdu::tests::{
use crate::cfdp::pdu::WritablePduPacket; common_pdu_conf, verify_raw_header, TEST_DEST_ID, TEST_SEQ_NUM, TEST_SRC_ID,
};
use crate::cfdp::pdu::{CfdpPdu, WritablePduPacket};
use crate::cfdp::pdu::{FileDirectiveType, PduHeader}; use crate::cfdp::pdu::{FileDirectiveType, PduHeader};
use crate::cfdp::tlv::{Tlv, TlvType}; use crate::cfdp::tlv::{Tlv, TlvType};
use crate::cfdp::{ use crate::cfdp::{
ChecksumType, CrcFlag, LargeFileFlag, PduType, SegmentMetadataFlag, SegmentationControl, ChecksumType, CrcFlag, Direction, LargeFileFlag, PduType, SegmentMetadataFlag,
SegmentationControl, TransmissionMode,
}; };
use std::vec; use std::vec;
@ -351,6 +360,21 @@ pub mod tests {
assert_eq!(metadata_pdu.src_file_name(), src_filename); assert_eq!(metadata_pdu.src_file_name(), src_filename);
assert_eq!(metadata_pdu.dest_file_name(), dest_filename); assert_eq!(metadata_pdu.dest_file_name(), dest_filename);
assert_eq!(metadata_pdu.options(), None); assert_eq!(metadata_pdu.options(), None);
assert_eq!(metadata_pdu.crc_flag(), CrcFlag::NoCrc);
assert_eq!(metadata_pdu.file_flag(), LargeFileFlag::Normal);
assert_eq!(metadata_pdu.pdu_type(), PduType::FileDirective);
assert_eq!(
metadata_pdu.file_directive_type(),
Some(FileDirectiveType::MetadataPdu)
);
assert_eq!(
metadata_pdu.transmission_mode(),
TransmissionMode::Acknowledged
);
assert_eq!(metadata_pdu.direction(), Direction::TowardsReceiver);
assert_eq!(metadata_pdu.source_id(), TEST_SRC_ID.into());
assert_eq!(metadata_pdu.dest_id(), TEST_DEST_ID.into());
assert_eq!(metadata_pdu.transaction_seq_num(), TEST_SEQ_NUM.into());
} }
#[test] #[test]
@ -414,6 +438,7 @@ pub mod tests {
fn test_with_crc_flag() { fn test_with_crc_flag() {
let (src_filename, dest_filename, metadata_pdu) = let (src_filename, dest_filename, metadata_pdu) =
generic_metadata_pdu(CrcFlag::WithCrc, LargeFileFlag::Normal, None); generic_metadata_pdu(CrcFlag::WithCrc, LargeFileFlag::Normal, None);
assert_eq!(metadata_pdu.crc_flag(), CrcFlag::WithCrc);
let mut buf: [u8; 64] = [0; 64]; let mut buf: [u8; 64] = [0; 64];
let write_res = metadata_pdu.write_to_bytes(&mut buf); let write_res = metadata_pdu.write_to_bytes(&mut buf);
assert!(write_res.is_ok()); assert!(write_res.is_ok());

View File

@ -165,8 +165,51 @@ pub trait WritablePduPacket {
} }
} }
/// Abstraction trait for fields and properties common for all PDUs.
pub trait CfdpPdu {
fn pdu_header(&self) -> &PduHeader;
fn source_id(&self) -> UnsignedByteField {
self.pdu_header().common_pdu_conf().source_entity_id
}
fn dest_id(&self) -> UnsignedByteField {
self.pdu_header().common_pdu_conf().dest_entity_id
}
fn transaction_seq_num(&self) -> UnsignedByteField {
self.pdu_header().common_pdu_conf().transaction_seq_num
}
fn transmission_mode(&self) -> TransmissionMode {
self.pdu_header().common_pdu_conf().trans_mode
}
fn direction(&self) -> Direction {
self.pdu_header().common_pdu_conf().direction
}
fn crc_flag(&self) -> CrcFlag {
self.pdu_header().common_pdu_conf().crc_flag
}
fn file_flag(&self) -> LargeFileFlag {
self.pdu_header().common_pdu_conf().file_flag
}
fn pdu_type(&self) -> PduType {
self.pdu_header().pdu_type()
}
fn file_directive_type(&self) -> Option<FileDirectiveType>;
}
/// Common configuration fields for a PDU. /// Common configuration fields for a PDU.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] ///
/// Please note that this structure has a custom implementation of [PartialEq] which only
/// compares the values for source entity ID, destination entity ID and transaction sequence
/// number. This permits that those fields can have different widths, as long as the value is the
/// same.
#[derive(Debug, Copy, Clone, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CommonPduConfig { pub struct CommonPduConfig {
source_entity_id: UnsignedByteField, source_entity_id: UnsignedByteField,
@ -287,6 +330,18 @@ impl Default for CommonPduConfig {
} }
} }
impl PartialEq for CommonPduConfig {
fn eq(&self, other: &Self) -> bool {
self.source_entity_id.value() == other.source_entity_id.value()
&& self.dest_entity_id.value() == other.dest_entity_id.value()
&& self.transaction_seq_num.value() == other.transaction_seq_num.value()
&& self.trans_mode == other.trans_mode
&& self.file_flag == other.file_flag
&& self.crc_flag == other.crc_flag
&& self.direction == other.direction
}
}
pub const FIXED_HEADER_LEN: usize = 4; pub const FIXED_HEADER_LEN: usize = 4;
/// Abstraction for the PDU header common to all CFDP PDUs. /// Abstraction for the PDU header common to all CFDP PDUs.
@ -627,17 +682,18 @@ mod tests {
TransmissionMode, CFDP_VERSION_2, TransmissionMode, CFDP_VERSION_2,
}; };
use crate::util::{ use crate::util::{
UbfU8, UnsignedByteField, UnsignedByteFieldU16, UnsignedByteFieldU8, UnsignedEnum, UbfU16, UbfU8, UnsignedByteField, UnsignedByteFieldU16, UnsignedByteFieldU8, UnsignedEnum,
}; };
use crate::ByteConversionError; use crate::ByteConversionError;
use std::format; use std::format;
pub(crate) const TEST_SRC_ID: UbfU8 = UbfU8::new(5);
pub(crate) const TEST_DEST_ID: UbfU8 = UbfU8::new(10);
pub(crate) const TEST_SEQ_NUM: UbfU8 = UbfU8::new(20);
pub(crate) fn common_pdu_conf(crc_flag: CrcFlag, fss: LargeFileFlag) -> CommonPduConfig { pub(crate) fn common_pdu_conf(crc_flag: CrcFlag, fss: LargeFileFlag) -> CommonPduConfig {
let src_id = UbfU8::new(5);
let dest_id = UbfU8::new(10);
let transaction_seq_num = UbfU8::new(20);
let mut pdu_conf = let mut pdu_conf =
CommonPduConfig::new_with_byte_fields(src_id, dest_id, transaction_seq_num) CommonPduConfig::new_with_byte_fields(TEST_SRC_ID, TEST_DEST_ID, TEST_SEQ_NUM)
.expect("Generating common PDU config"); .expect("Generating common PDU config");
pdu_conf.crc_flag = crc_flag; pdu_conf.crc_flag = crc_flag;
pdu_conf.file_flag = fss; pdu_conf.file_flag = fss;
@ -728,6 +784,17 @@ mod tests {
assert_eq!(pdu_header.header_len(), 7); assert_eq!(pdu_header.header_len(), 7);
} }
#[test]
fn test_common_pdu_conf_partial_eq() {
let common_pdu_cfg_0 =
CommonPduConfig::new_with_byte_fields(UbfU8::new(1), UbfU8::new(2), UbfU8::new(3))
.expect("common config creation failed");
let common_pdu_cfg_1 =
CommonPduConfig::new_with_byte_fields(UbfU16::new(1), UbfU16::new(2), UbfU16::new(3))
.expect("common config creation failed");
assert_eq!(common_pdu_cfg_0, common_pdu_cfg_1);
}
#[test] #[test]
fn test_basic_state_default() { fn test_basic_state_default() {
let default_conf = CommonPduConfig::default(); let default_conf = CommonPduConfig::default();