Improvements for writable abstractions #39

Merged
muellerr merged 4 commits from improvements-for-writable-abstractions into main 2023-11-24 16:36:35 +01:00
9 changed files with 167 additions and 81 deletions

View File

@ -8,11 +8,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
# [unreleased] # [unreleased]
## Added
- Add `WritablePduPacket` trait which is a common trait of all CFDP PDU implementations.
## Fixed ## Fixed
- Set the directtion field inside the PDU header field correctl explicitely for all CFDP PDU - Set the direction field inside the PDU header field correctly explicitely for all CFDP PDU
packets. packets.
## Changed
- Renamed `SerializablePusPacket` to `WritablePusPacket`.
- Renamed `WritablePduPacket.written_len` and `SerializablePusPacket.len_packed` to `len_written`.
# [v0.7.0-beta.2] 2023-09-26 # [v0.7.0-beta.2] 2023-09-26
## Added ## Added

View File

@ -42,10 +42,6 @@ impl EofPdu {
&self.pdu_header &self.pdu_header
} }
pub fn written_len(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
pub fn condition_code(&self) -> ConditionCode { pub fn condition_code(&self) -> ConditionCode {
self.condition_code self.condition_code
} }
@ -117,7 +113,7 @@ impl 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.written_len(); let expected_len = self.len_written();
if buf.len() < expected_len { if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(), found: buf.len(),
@ -145,6 +141,10 @@ impl WritablePduPacket for EofPdu {
} }
Ok(current_idx) Ok(current_idx)
} }
fn len_written(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
} }
#[cfg(test)] #[cfg(test)]
@ -159,7 +159,7 @@ mod tests {
let pdu_conf = common_pdu_conf(CrcFlag::NoCrc, LargeFileFlag::Normal); let pdu_conf = common_pdu_conf(CrcFlag::NoCrc, LargeFileFlag::Normal);
let pdu_header = PduHeader::new_no_file_data(pdu_conf, 0); let pdu_header = PduHeader::new_no_file_data(pdu_conf, 0);
let eof_pdu = EofPdu::new_no_error(pdu_header, 0x01020304, 12); let eof_pdu = EofPdu::new_no_error(pdu_header, 0x01020304, 12);
assert_eq!(eof_pdu.written_len(), pdu_header.header_len() + 2 + 4 + 4); assert_eq!(eof_pdu.len_written(), pdu_header.header_len() + 2 + 4 + 4);
assert_eq!(eof_pdu.file_checksum(), 0x01020304); assert_eq!(eof_pdu.file_checksum(), 0x01020304);
assert_eq!(eof_pdu.file_size(), 12); assert_eq!(eof_pdu.file_size(), 12);
assert_eq!(eof_pdu.condition_code(), ConditionCode::NoError); assert_eq!(eof_pdu.condition_code(), ConditionCode::NoError);
@ -174,7 +174,7 @@ mod tests {
let res = eof_pdu.write_to_bytes(&mut buf); let res = eof_pdu.write_to_bytes(&mut buf);
assert!(res.is_ok()); assert!(res.is_ok());
let written = res.unwrap(); let written = res.unwrap();
assert_eq!(written, eof_pdu.written_len()); assert_eq!(written, eof_pdu.len_written());
verify_raw_header(eof_pdu.pdu_header(), &buf); verify_raw_header(eof_pdu.pdu_header(), &buf);
let mut current_idx = eof_pdu.pdu_header().header_len(); let mut current_idx = eof_pdu.pdu_header().header_len();
buf[current_idx] = FileDirectiveType::EofPdu as u8; buf[current_idx] = FileDirectiveType::EofPdu as u8;
@ -205,11 +205,22 @@ mod tests {
let mut buf: [u8; 64] = [0; 64]; let mut buf: [u8; 64] = [0; 64];
eof_pdu.write_to_bytes(&mut buf).unwrap(); eof_pdu.write_to_bytes(&mut buf).unwrap();
let eof_read_back = EofPdu::from_bytes(&buf); let eof_read_back = EofPdu::from_bytes(&buf);
if !eof_read_back.is_ok() { if eof_read_back.is_err() {
let e = eof_read_back.unwrap_err(); let e = eof_read_back.unwrap_err();
panic!("deserialization failed with: {e}") panic!("deserialization failed with: {e}")
} }
let eof_read_back = eof_read_back.unwrap(); let eof_read_back = eof_read_back.unwrap();
assert_eq!(eof_read_back, eof_pdu); assert_eq!(eof_read_back, eof_pdu);
} }
#[test]
fn test_write_to_vec() {
let pdu_conf = common_pdu_conf(CrcFlag::NoCrc, LargeFileFlag::Normal);
let pdu_header = PduHeader::new_no_file_data(pdu_conf, 0);
let eof_pdu = EofPdu::new_no_error(pdu_header, 0x01020304, 12);
let mut buf: [u8; 64] = [0; 64];
let written = eof_pdu.write_to_bytes(&mut buf).unwrap();
let pdu_vec = eof_pdu.to_vec().unwrap();
assert_eq!(buf[0..written], pdu_vec);
}
} }

View File

@ -149,9 +149,6 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> {
} }
len len
} }
pub fn written_len(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
pub fn offset(&self) -> u64 { pub fn offset(&self) -> u64 {
self.offset self.offset
@ -197,10 +194,10 @@ impl<'seg_meta, 'file_data> FileDataPdu<'seg_meta, 'file_data> {
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> {
if buf.len() < self.written_len() { if buf.len() < self.len_written() {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(), found: buf.len(),
expected: self.written_len(), expected: self.len_written(),
} }
.into()); .into());
} }
@ -224,6 +221,10 @@ impl WritablePduPacket for FileDataPdu<'_, '_> {
} }
Ok(current_idx) Ok(current_idx)
} }
fn len_written(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
} }
#[cfg(test)] #[cfg(test)]
@ -233,13 +234,13 @@ mod tests {
use crate::cfdp::{SegmentMetadataFlag, SegmentationControl}; use crate::cfdp::{SegmentMetadataFlag, SegmentationControl};
use crate::util::UbfU8; use crate::util::UbfU8;
const SRC_ID: UbfU8 = UbfU8::new(1);
const DEST_ID: UbfU8 = UbfU8::new(2);
const SEQ_NUM: UbfU8 = UbfU8::new(3);
#[test] #[test]
fn test_basic() { fn test_basic() {
let src_id = UbfU8::new(1); let common_conf = CommonPduConfig::new_with_byte_fields(SRC_ID, DEST_ID, SEQ_NUM).unwrap();
let dest_id = UbfU8::new(2);
let transaction_seq_num = UbfU8::new(3);
let common_conf =
CommonPduConfig::new_with_byte_fields(src_id, dest_id, transaction_seq_num).unwrap();
let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0); let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0);
let file_data: [u8; 4] = [1, 2, 3, 4]; let file_data: [u8; 4] = [1, 2, 3, 4];
let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data); let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data);
@ -247,18 +248,14 @@ mod tests {
assert_eq!(fd_pdu.offset(), 10); assert_eq!(fd_pdu.offset(), 10);
assert!(fd_pdu.segment_metadata().is_none()); assert!(fd_pdu.segment_metadata().is_none());
assert_eq!( assert_eq!(
fd_pdu.written_len(), fd_pdu.len_written(),
fd_pdu.pdu_header.header_len() + core::mem::size_of::<u32>() + 4 fd_pdu.pdu_header.header_len() + core::mem::size_of::<u32>() + 4
); );
} }
#[test] #[test]
fn test_serialization() { fn test_serialization() {
let src_id = UbfU8::new(1); let common_conf = CommonPduConfig::new_with_byte_fields(SRC_ID, DEST_ID, SEQ_NUM).unwrap();
let dest_id = UbfU8::new(2);
let transaction_seq_num = UbfU8::new(3);
let common_conf =
CommonPduConfig::new_with_byte_fields(src_id, dest_id, transaction_seq_num).unwrap();
let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0); let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0);
let file_data: [u8; 4] = [1, 2, 3, 4]; let file_data: [u8; 4] = [1, 2, 3, 4];
let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data); let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data);
@ -287,13 +284,21 @@ mod tests {
assert_eq!(buf[current_idx], 4); assert_eq!(buf[current_idx], 4);
} }
#[test]
fn test_write_to_vec() {
let common_conf = CommonPduConfig::new_with_byte_fields(SRC_ID, DEST_ID, SEQ_NUM).unwrap();
let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0);
let file_data: [u8; 4] = [1, 2, 3, 4];
let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data);
let mut buf: [u8; 64] = [0; 64];
let written = fd_pdu.write_to_bytes(&mut buf).unwrap();
let pdu_vec = fd_pdu.to_vec().unwrap();
assert_eq!(buf[0..written], pdu_vec);
}
#[test] #[test]
fn test_deserialization() { fn test_deserialization() {
let src_id = UbfU8::new(1); let common_conf = CommonPduConfig::new_with_byte_fields(SRC_ID, DEST_ID, SEQ_NUM).unwrap();
let dest_id = UbfU8::new(2);
let transaction_seq_num = UbfU8::new(3);
let common_conf =
CommonPduConfig::new_with_byte_fields(src_id, dest_id, transaction_seq_num).unwrap();
let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0); let pdu_header = PduHeader::new_for_file_data_default(common_conf, 0);
let file_data: [u8; 4] = [1, 2, 3, 4]; let file_data: [u8; 4] = [1, 2, 3, 4];
let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data); let fd_pdu = FileDataPdu::new_no_seg_metadata(pdu_header, 10, &file_data);
@ -327,7 +332,7 @@ mod tests {
assert!(fd_pdu.segment_metadata().is_some()); assert!(fd_pdu.segment_metadata().is_some());
assert_eq!(*fd_pdu.segment_metadata().unwrap(), segment_meta); assert_eq!(*fd_pdu.segment_metadata().unwrap(), segment_meta);
assert_eq!( assert_eq!(
fd_pdu.written_len(), fd_pdu.len_written(),
fd_pdu.pdu_header.header_len() fd_pdu.pdu_header.header_len()
+ 1 + 1
+ seg_metadata.len() + seg_metadata.len()
@ -367,7 +372,7 @@ mod tests {
current_idx += 1; current_idx += 1;
assert_eq!(buf[current_idx], 4); assert_eq!(buf[current_idx], 4);
current_idx += 1; current_idx += 1;
assert_eq!(current_idx, fd_pdu.written_len()); assert_eq!(current_idx, fd_pdu.len_written());
} }
#[test] #[test]

View File

@ -102,10 +102,6 @@ impl<'fs_responses> FinishedPdu<'fs_responses> {
&self.pdu_header &self.pdu_header
} }
pub fn written_len(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
pub fn condition_code(&self) -> ConditionCode { pub fn condition_code(&self) -> ConditionCode {
self.condition_code self.condition_code
} }
@ -220,7 +216,7 @@ impl<'fs_responses> FinishedPdu<'fs_responses> {
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.written_len(); let expected_len = self.len_written();
if buf.len() < expected_len { if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(), found: buf.len(),
@ -248,6 +244,10 @@ impl WritablePduPacket for FinishedPdu<'_> {
} }
Ok(current_idx) Ok(current_idx)
} }
fn len_written(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
} }
#[cfg(test)] #[cfg(test)]
@ -298,7 +298,7 @@ mod tests {
let written = finished_pdu.write_to_bytes(&mut buf); let written = finished_pdu.write_to_bytes(&mut buf);
assert!(written.is_ok()); assert!(written.is_ok());
let written = written.unwrap(); let written = written.unwrap();
assert_eq!(written, finished_pdu.written_len()); assert_eq!(written, finished_pdu.len_written());
assert_eq!(written, finished_pdu.pdu_header().header_len() + 2); assert_eq!(written, finished_pdu.pdu_header().header_len() + 2);
assert_eq!( assert_eq!(
finished_pdu.pdu_header().pdu_conf.direction, finished_pdu.pdu_header().pdu_conf.direction,
@ -335,6 +335,20 @@ mod tests {
generic_serialization_test_no_error(DeliveryCode::Incomplete, FileStatus::Unreported); generic_serialization_test_no_error(DeliveryCode::Incomplete, FileStatus::Unreported);
} }
#[test]
fn test_write_to_vec() {
let finished_pdu = generic_finished_pdu(
CrcFlag::NoCrc,
LargeFileFlag::Normal,
DeliveryCode::Complete,
FileStatus::Retained,
);
let mut buf: [u8; 64] = [0; 64];
let written = finished_pdu.write_to_bytes(&mut buf).unwrap();
let pdu_vec = finished_pdu.to_vec().unwrap();
assert_eq!(buf[0..written], pdu_vec);
}
#[test] #[test]
fn test_deserialization_simple() { fn test_deserialization_simple() {
let finished_pdu = generic_finished_pdu( let finished_pdu = generic_finished_pdu(

View File

@ -174,10 +174,6 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
}) })
} }
pub fn written_len(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
fn calc_pdu_datafield_len(&self) -> usize { fn calc_pdu_datafield_len(&self) -> usize {
// One directve type octet and one byte of the directive parameter field. // One directve type octet and one byte of the directive parameter field.
let mut len = 2; let mut len = 2;
@ -256,7 +252,7 @@ impl<'src_name, 'dest_name, 'opts> MetadataPdu<'src_name, 'dest_name, 'opts> {
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.written_len(); let expected_len = self.len_written();
if buf.len() < expected_len { if buf.len() < expected_len {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(), found: buf.len(),
@ -291,17 +287,21 @@ impl WritablePduPacket for MetadataPdu<'_, '_, '_> {
} }
Ok(current_idx) Ok(current_idx)
} }
fn len_written(&self) -> usize {
self.pdu_header.header_len() + self.calc_pdu_datafield_len()
}
} }
#[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,
MetadataPdu, MetadataPdu,
}; };
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::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::{
@ -340,7 +340,7 @@ pub mod tests {
let (src_filename, dest_filename, metadata_pdu) = let (src_filename, dest_filename, metadata_pdu) =
generic_metadata_pdu(CrcFlag::NoCrc, LargeFileFlag::Normal, None); generic_metadata_pdu(CrcFlag::NoCrc, LargeFileFlag::Normal, None);
assert_eq!( assert_eq!(
metadata_pdu.written_len(), metadata_pdu.len_written(),
metadata_pdu.pdu_header().header_len() metadata_pdu.pdu_header().header_len()
+ 1 + 1
+ 1 + 1
@ -388,6 +388,16 @@ pub mod tests {
assert_eq!(current_idx, written); assert_eq!(current_idx, written);
} }
#[test]
fn test_write_to_vec() {
let (_, _, metadata_pdu) =
generic_metadata_pdu(CrcFlag::NoCrc, LargeFileFlag::Normal, None);
let mut buf: [u8; 64] = [0; 64];
let pdu_vec = metadata_pdu.to_vec().unwrap();
let written = metadata_pdu.write_to_bytes(&mut buf).unwrap();
assert_eq!(buf[0..written], pdu_vec);
}
#[test] #[test]
fn test_deserialization() { fn test_deserialization() {
let (_, _, metadata_pdu) = let (_, _, metadata_pdu) =

View File

@ -3,6 +3,8 @@ use crate::cfdp::*;
use crate::util::{UnsignedByteField, UnsignedByteFieldU8, UnsignedEnum}; use crate::util::{UnsignedByteField, UnsignedByteFieldU8, UnsignedEnum};
use crate::ByteConversionError; use crate::ByteConversionError;
use crate::CRC_CCITT_FALSE; use crate::CRC_CCITT_FALSE;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::fmt::{Display, Formatter}; use core::fmt::{Display, Formatter};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::error::Error; use std::error::Error;
@ -150,7 +152,17 @@ impl From<TlvLvError> for PduError {
} }
pub trait WritablePduPacket { pub trait WritablePduPacket {
fn len_written(&self) -> usize;
fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError>; fn write_to_bytes(&self, buf: &mut [u8]) -> Result<usize, PduError>;
#[cfg(feature = "alloc")]
fn to_vec(&self) -> Result<Vec<u8>, PduError> {
// This is the correct way to do this. See
// [this issue](https://github.com/rust-lang/rust-clippy/issues/4483) for caveats of more
// "efficient" implementations.
let mut vec = alloc::vec![0; self.len_written()];
self.write_to_bytes(&mut vec)?;
Ok(vec)
}
} }
/// Common configuration fields for a PDU. /// Common configuration fields for a PDU.

View File

@ -360,15 +360,15 @@ pub type EcssEnumU64 = GenericEcssEnumWrapper<u64>;
/// Generic trait for PUS packet abstractions which can written to a raw slice as their raw /// Generic trait for PUS packet abstractions which can written to a raw slice as their raw
/// byte representation. This is especially useful for generic abstractions which depend only /// byte representation. This is especially useful for generic abstractions which depend only
/// on the serialization of those packets. /// on the serialization of those packets.
pub trait SerializablePusPacket { pub trait WritablePusPacket {
fn len_packed(&self) -> usize; fn len_written(&self) -> usize;
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError>; fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError>;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn to_vec(&self) -> Result<Vec<u8>, PusError> { fn to_vec(&self) -> Result<Vec<u8>, PusError> {
// This is the correct way to do this. See // This is the correct way to do this. See
// [this issue](https://github.com/rust-lang/rust-clippy/issues/4483) for caveats of more // [this issue](https://github.com/rust-lang/rust-clippy/issues/4483) for caveats of more
// "efficient" implementations. // "efficient" implementations.
let mut vec = alloc::vec![0; self.len_packed()]; let mut vec = alloc::vec![0; self.len_written()];
self.write_to_bytes(&mut vec)?; self.write_to_bytes(&mut vec)?;
Ok(vec) Ok(vec)
} }

View File

@ -5,7 +5,7 @@
//! //!
//! ```rust //! ```rust
//! use spacepackets::{CcsdsPacket, SpHeader}; //! use spacepackets::{CcsdsPacket, SpHeader};
//! use spacepackets::ecss::{PusPacket, SerializablePusPacket}; //! use spacepackets::ecss::{PusPacket, WritablePusPacket};
//! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}; //! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
//! //!
//! // Create a ping telecommand with no user application data //! // Create a ping telecommand with no user application data
@ -34,7 +34,7 @@
use crate::ecss::{ use crate::ecss::{
ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw, ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw,
verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion, verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion,
SerializablePusPacket, WritablePusPacket,
}; };
use crate::{ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, CCSDS_HEADER_LEN}; use crate::{ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, CCSDS_HEADER_LEN};
use crate::{SpHeader, CRC_CCITT_FALSE}; use crate::{SpHeader, CRC_CCITT_FALSE};
@ -216,7 +216,7 @@ pub mod legacy_tc {
}; };
use crate::ecss::{ use crate::ecss::{
ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls, ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls,
verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, SerializablePusPacket, verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, WritablePusPacket,
CCSDS_HEADER_LEN, CCSDS_HEADER_LEN,
}; };
use crate::ecss::{user_data_from_raw, PusVersion}; use crate::ecss::{user_data_from_raw, PusVersion};
@ -347,7 +347,7 @@ pub mod legacy_tc {
/// is set correctly. /// is set correctly.
pub fn update_ccsds_data_len(&mut self) { pub fn update_ccsds_data_len(&mut self) {
self.sp_header.data_len = self.sp_header.data_len =
self.len_packed() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
} }
/// This function should be called before the TC packet is serialized if /// This function should be called before the TC packet is serialized if
@ -447,8 +447,8 @@ pub mod legacy_tc {
} }
} }
impl SerializablePusPacket for PusTc<'_> { impl WritablePusPacket for PusTc<'_> {
fn len_packed(&self) -> usize { fn len_written(&self) -> usize {
PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len() PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len()
} }
@ -456,7 +456,7 @@ pub mod legacy_tc {
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> { fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
let mut curr_idx = 0; let mut curr_idx = 0;
let tc_header_len = size_of::<zc::PusTcSecondaryHeader>(); let tc_header_len = size_of::<zc::PusTcSecondaryHeader>();
let total_size = self.len_packed(); let total_size = self.len_written();
if total_size > slice.len() { if total_size > slice.len() {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: slice.len(), found: slice.len(),
@ -619,7 +619,7 @@ impl<'raw_data> PusTcCreator<'raw_data> {
/// is set correctly. /// is set correctly.
pub fn update_ccsds_data_len(&mut self) { pub fn update_ccsds_data_len(&mut self) {
self.sp_header.data_len = self.sp_header.data_len =
self.len_packed() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
} }
/// This function should be called before the TC packet is serialized if /// This function should be called before the TC packet is serialized if
@ -653,8 +653,8 @@ impl<'raw_data> PusTcCreator<'raw_data> {
} }
} }
impl SerializablePusPacket for PusTcCreator<'_> { impl WritablePusPacket for PusTcCreator<'_> {
fn len_packed(&self) -> usize { fn len_written(&self) -> usize {
PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len() PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len()
} }
@ -662,7 +662,7 @@ impl SerializablePusPacket for PusTcCreator<'_> {
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> { fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
let mut curr_idx = 0; let mut curr_idx = 0;
let tc_header_len = size_of::<zc::PusTcSecondaryHeader>(); let tc_header_len = size_of::<zc::PusTcSecondaryHeader>();
let total_size = self.len_packed(); let total_size = self.len_written();
if total_size > slice.len() { if total_size > slice.len() {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: slice.len(), found: slice.len(),
@ -851,7 +851,7 @@ mod tests {
GenericPusTcSecondaryHeader, PusTcCreator, PusTcReader, PusTcSecondaryHeader, ACK_ALL, GenericPusTcSecondaryHeader, PusTcCreator, PusTcReader, PusTcSecondaryHeader, ACK_ALL,
}; };
use crate::ecss::PusVersion::PusC; use crate::ecss::PusVersion::PusC;
use crate::ecss::{PusError, PusPacket, SerializablePusPacket}; use crate::ecss::{PusError, PusPacket, WritablePusPacket};
use crate::{ByteConversionError, SpHeader}; use crate::{ByteConversionError, SpHeader};
use crate::{CcsdsPacket, SequenceFlags}; use crate::{CcsdsPacket, SequenceFlags};
use alloc::vec::Vec; use alloc::vec::Vec;
@ -905,6 +905,20 @@ mod tests {
verify_crc_no_app_data(&test_buf); verify_crc_no_app_data(&test_buf);
} }
#[test]
fn test_writing_into_vec() {
let pus_tc = base_ping_tc_simple_ctor();
let tc_vec = pus_tc.to_vec().expect("Error writing TC to buffer");
assert_eq!(tc_vec.len(), 13);
let (tc_from_raw, size) = PusTcReader::new(tc_vec.as_slice())
.expect("Creating PUS TC struct from raw buffer failed");
assert_eq!(size, 13);
verify_test_tc_with_reader(&tc_from_raw, false, 13);
assert!(tc_from_raw.user_data().is_empty());
verify_test_tc_raw(&tc_vec);
verify_crc_no_app_data(&tc_vec);
}
#[test] #[test]
fn test_update_func() { fn test_update_func() {
let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap(); let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap();
@ -993,7 +1007,7 @@ mod tests {
match err { match err {
PusError::ByteConversion(err) => match err { PusError::ByteConversion(err) => match err {
ByteConversionError::ToSliceTooSmall { found, expected } => { ByteConversionError::ToSliceTooSmall { found, expected } => {
assert_eq!(expected, pus_tc.len_packed()); assert_eq!(expected, pus_tc.len_written());
assert_eq!(found, 12); assert_eq!(found, 12);
} }
_ => panic!("Unexpected error"), _ => panic!("Unexpected error"),

View File

@ -3,7 +3,7 @@
use crate::ecss::{ use crate::ecss::{
calc_pus_crc16, ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw, calc_pus_crc16, ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw,
verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion, verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion,
SerializablePusPacket, WritablePusPacket,
}; };
use crate::{ use crate::{
ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN, ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN,
@ -203,7 +203,7 @@ pub mod legacy_tm {
use crate::ecss::PusVersion; use crate::ecss::PusVersion;
use crate::ecss::{ use crate::ecss::{
ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls, user_data_from_raw, ccsds_impl, crc_from_raw_data, crc_procedure, sp_header_impls, user_data_from_raw,
verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, SerializablePusPacket, verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, WritablePusPacket,
CCSDS_HEADER_LEN, CCSDS_HEADER_LEN,
}; };
use crate::SequenceFlags; use crate::SequenceFlags;
@ -314,7 +314,7 @@ pub mod legacy_tm {
/// is set correctly /// is set correctly
pub fn update_ccsds_data_len(&mut self) { pub fn update_ccsds_data_len(&mut self) {
self.sp_header.data_len = self.sp_header.data_len =
self.len_packed() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
} }
/// This function should be called before the TM packet is serialized if /// This function should be called before the TM packet is serialized if
@ -423,8 +423,8 @@ pub mod legacy_tm {
} }
} }
impl SerializablePusPacket for PusTm<'_> { impl WritablePusPacket for PusTm<'_> {
fn len_packed(&self) -> usize { fn len_written(&self) -> usize {
PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA
+ self.sec_header.timestamp.len() + self.sec_header.timestamp.len()
+ self.source_data.len() + self.source_data.len()
@ -432,7 +432,7 @@ pub mod legacy_tm {
/// Write the raw PUS byte representation to a provided buffer. /// Write the raw PUS byte representation to a provided buffer.
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> { fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
let mut curr_idx = 0; let mut curr_idx = 0;
let total_size = self.len_packed(); let total_size = self.len_written();
if total_size > slice.len() { if total_size > slice.len() {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: slice.len(), found: slice.len(),
@ -608,7 +608,7 @@ impl<'raw_data> PusTmCreator<'raw_data> {
/// is set correctly /// is set correctly
pub fn update_ccsds_data_len(&mut self) { pub fn update_ccsds_data_len(&mut self) {
self.sp_header.data_len = self.sp_header.data_len =
self.len_packed() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; self.len_written() as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
} }
/// This function should be called before the TM packet is serialized if /// This function should be called before the TM packet is serialized if
@ -650,8 +650,8 @@ impl<'raw_data> PusTmCreator<'raw_data> {
} }
} }
impl SerializablePusPacket for PusTmCreator<'_> { impl WritablePusPacket for PusTmCreator<'_> {
fn len_packed(&self) -> usize { fn len_written(&self) -> usize {
PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA
+ self.sec_header.timestamp.len() + self.sec_header.timestamp.len()
+ self.source_data.len() + self.source_data.len()
@ -659,7 +659,7 @@ impl SerializablePusPacket for PusTmCreator<'_> {
/// Write the raw PUS byte representation to a provided buffer. /// Write the raw PUS byte representation to a provided buffer.
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> { fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
let mut curr_idx = 0; let mut curr_idx = 0;
let total_size = self.len_packed(); let total_size = self.len_written();
if total_size > slice.len() { if total_size > slice.len() {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: slice.len(), found: slice.len(),
@ -949,31 +949,31 @@ mod tests {
fn base_ping_reply_full_ctor(timestamp: &[u8]) -> PusTmCreator { fn base_ping_reply_full_ctor(timestamp: &[u8]) -> PusTmCreator {
let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, &timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
PusTmCreator::new(&mut sph, tm_header, None, true) PusTmCreator::new(&mut sph, tm_header, None, true)
} }
fn base_hk_reply<'a>(timestamp: &'a [u8], src_data: &'a [u8]) -> PusTmCreator<'a> { fn base_hk_reply<'a>(timestamp: &'a [u8], src_data: &'a [u8]) -> PusTmCreator<'a> {
let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(3, 5, &timestamp); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp);
PusTmCreator::new(&mut sph, tc_header, Some(src_data), true) PusTmCreator::new(&mut sph, tc_header, Some(src_data), true)
} }
fn dummy_timestamp() -> &'static [u8] { fn dummy_timestamp() -> &'static [u8] {
return &[0, 1, 2, 3, 4, 5, 6]; &[0, 1, 2, 3, 4, 5, 6]
} }
#[test] #[test]
fn test_basic() { fn test_basic() {
let timestamp = dummy_timestamp(); let timestamp = dummy_timestamp();
let pus_tm = base_ping_reply_full_ctor(&timestamp); let pus_tm = base_ping_reply_full_ctor(timestamp);
verify_ping_reply(&pus_tm, false, 22, dummy_timestamp()); verify_ping_reply(&pus_tm, false, 22, dummy_timestamp());
} }
#[test] #[test]
fn test_serialization_no_source_data() { fn test_serialization_no_source_data() {
let timestamp = dummy_timestamp(); let timestamp = dummy_timestamp();
let pus_tm = base_ping_reply_full_ctor(&timestamp); let pus_tm = base_ping_reply_full_ctor(timestamp);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
let ser_len = pus_tm let ser_len = pus_tm
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
@ -999,7 +999,7 @@ mod tests {
#[test] #[test]
fn test_setters() { fn test_setters() {
let timestamp = dummy_timestamp(); let timestamp = dummy_timestamp();
let mut pus_tm = base_ping_reply_full_ctor(&timestamp); let mut pus_tm = base_ping_reply_full_ctor(timestamp);
pus_tm.set_sc_time_ref_status(0b1010); pus_tm.set_sc_time_ref_status(0b1010);
pus_tm.set_dest_id(0x7fff); pus_tm.set_dest_id(0x7fff);
pus_tm.set_msg_counter(0x1f1f); pus_tm.set_msg_counter(0x1f1f);
@ -1010,10 +1010,21 @@ mod tests {
assert_eq!(pus_tm.apid(), 0x7ff); assert_eq!(pus_tm.apid(), 0x7ff);
} }
#[test]
fn test_write_into_vec() {
let timestamp = dummy_timestamp();
let pus_tm = base_ping_reply_full_ctor(timestamp);
let tm_vec = pus_tm.to_vec().expect("Serialization failed");
assert_eq!(tm_vec.len(), 22);
let (tm_deserialized, size) =
PusTmReader::new(tm_vec.as_slice(), 7).expect("Deserialization failed");
assert_eq!(tm_vec.len(), size);
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
}
#[test] #[test]
fn test_deserialization_no_source_data() { fn test_deserialization_no_source_data() {
let timestamp = dummy_timestamp(); let timestamp = dummy_timestamp();
let pus_tm = base_ping_reply_full_ctor(&timestamp); let pus_tm = base_ping_reply_full_ctor(timestamp);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
let ser_len = pus_tm let ser_len = pus_tm
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
@ -1045,7 +1056,7 @@ mod tests {
#[test] #[test]
fn test_target_buf_too_small() { fn test_target_buf_too_small() {
let timestamp = dummy_timestamp(); let timestamp = dummy_timestamp();
let pus_tm = base_ping_reply_full_ctor(&timestamp); let pus_tm = base_ping_reply_full_ctor(timestamp);
let mut buf: [u8; 16] = [0; 16]; let mut buf: [u8; 16] = [0; 16];
let res = pus_tm.write_to_bytes(&mut buf); let res = pus_tm.write_to_bytes(&mut buf);
assert!(res.is_err()); assert!(res.is_err());
@ -1069,7 +1080,7 @@ mod tests {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
fn test_append_to_vec() { fn test_append_to_vec() {
let timestamp = dummy_timestamp(); let timestamp = dummy_timestamp();
let pus_tm = base_ping_reply_full_ctor(&timestamp); let pus_tm = base_ping_reply_full_ctor(timestamp);
let mut vec = Vec::new(); let mut vec = Vec::new();
let res = pus_tm.append_to_vec(&mut vec); let res = pus_tm.append_to_vec(&mut vec);
assert!(res.is_ok()); assert!(res.is_ok());
@ -1124,7 +1135,7 @@ mod tests {
exp_full_len: usize, exp_full_len: usize,
exp_timestamp: &[u8], exp_timestamp: &[u8],
) { ) {
assert_eq!(tm.len_packed(), exp_full_len); assert_eq!(tm.len_written(), exp_full_len);
assert_eq!(tm.timestamp(), exp_timestamp); assert_eq!(tm.timestamp(), exp_timestamp);
verify_ping_reply_generic(tm, has_user_data, exp_full_len); verify_ping_reply_generic(tm, has_user_data, exp_full_len);
} }