diff --git a/src/ecss/tc.rs b/src/ecss/tc.rs index dc867b5..f5bab83 100644 --- a/src/ecss/tc.rs +++ b/src/ecss/tc.rs @@ -708,6 +708,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { } } +#[derive(Debug)] pub struct PusTcBuilder<'a> { sp_header: SpHeader, sec_header: PusTcSecondaryHeader, diff --git a/src/ecss/tm.rs b/src/ecss/tm.rs index eb11e39..7703d66 100644 --- a/src/ecss/tm.rs +++ b/src/ecss/tm.rs @@ -51,8 +51,8 @@ use crate::ecss::{ WritablePusPacket, }; use crate::{ - ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN, - MAX_APID, + ByteConversionError, CcsdsPacket, PacketId, PacketSequenceControl, PacketType, SequenceFlags, + SpHeader, CCSDS_HEADER_LEN, MAX_APID, }; use arbitrary_int::traits::Integer; use arbitrary_int::{u11, u14, u3, u4}; @@ -344,8 +344,12 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> { Self::new(sp_header, sec_header, &[], packet_config) } + pub fn builder() -> PusTmBuilder<'time, 'src_data> { + PusTmBuilder::new() + } + #[inline] - fn has_checksum(&self) -> bool { + pub fn has_checksum(&self) -> bool { self.has_checksum } @@ -359,6 +363,21 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> { self.source_data } + #[inline] + pub fn service(&self) -> u8 { + self.sec_header.service + } + + #[inline] + pub fn subservice(&self) -> u8 { + self.sec_header.subservice + } + + #[inline] + pub fn apid(&self) -> u11 { + self.sp_header.packet_id.apid + } + #[inline] pub fn set_dest_id(&mut self, dest_id: u16) { self.sec_header.dest_id = dest_id; @@ -570,6 +589,126 @@ impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> { impl IsPusTelemetry for PusTmCreator<'_, '_> {} +#[derive(Debug)] +pub struct PusTmBuilder<'time, 'src_data> { + sp_header: SpHeader, + sec_header: PusTmSecondaryHeader<'time>, + source_data: &'src_data [u8], + has_checksum: bool, +} + +impl Default for PusTmBuilder<'_, '_> { + fn default() -> Self { + Self::new() + } +} + +impl PusTmBuilder<'_, '_> { + pub fn new() -> Self { + Self { + sp_header: SpHeader::new( + PacketId::new_for_tm(true, u11::new(0)), + PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0)), + 0, + ), + sec_header: PusTmSecondaryHeader::new(0, 0, 0, 0, &[]), + source_data: &[], + has_checksum: true, + } + } + + #[inline] + pub fn with_apid(mut self, apid: u11) -> Self { + self.sp_header.packet_id.set_apid(apid); + self + } + + #[inline] + pub fn with_packet_id(mut self, mut packet_id: PacketId) -> Self { + packet_id.packet_type = PacketType::Tc; + self.sp_header.packet_id = packet_id; + self + } + + #[inline] + pub fn with_packet_sequence_control(mut self, psc: PacketSequenceControl) -> Self { + self.sp_header.psc = psc; + self + } + + #[inline] + pub fn with_sequence_count(mut self, seq_count: u14) -> Self { + self.sp_header.psc.seq_count = seq_count; + self + } + + #[inline] + pub fn with_service(mut self, service: u8) -> Self { + self.sec_header.service = service; + self + } + + #[inline] + pub fn with_subservice(mut self, service: u8) -> Self { + self.sec_header.subservice = service; + self + } + + #[inline] + pub fn with_dest_id(mut self, dest_id: u16) -> Self { + self.sec_header.dest_id = dest_id; + self + } + + #[inline] + pub fn with_msg_counter(mut self, msg_counter: u16) -> Self { + self.sec_header.msg_counter = msg_counter; + self + } + + #[inline] + pub fn with_sc_time_ref_status(mut self, sc_time_ref_status: u4) -> Self { + self.sec_header.sc_time_ref_status = sc_time_ref_status; + self + } + + #[inline] + pub fn with_checksum(mut self, has_checksum: bool) -> Self { + self.has_checksum = has_checksum; + self + } +} + +impl<'src_data> PusTmBuilder<'_, 'src_data> { + #[inline] + pub fn with_source_data(mut self, source_data: &'src_data [u8]) -> Self { + self.source_data = source_data; + self + } +} + +impl<'time> PusTmBuilder<'time, '_> { + #[inline] + pub fn with_timestamp(mut self, timestamp: &'time [u8]) -> Self { + self.sec_header.timestamp = timestamp; + self + } +} + +impl<'time, 'src_data> PusTmBuilder<'time, 'src_data> { + pub fn build(self) -> PusTmCreator<'time, 'src_data> { + PusTmCreator::new( + self.sp_header, + self.sec_header, + self.source_data, + CreatorConfig { + has_checksum: self.has_checksum, + set_ccsds_len: true, + }, + ) + } +} + /// A specialized variant of [PusTmCreator] designed for efficiency when handling large source /// data. /// @@ -1171,14 +1310,13 @@ impl GenericPusTmSecondaryHeader for PusTmZeroCopyWriter<'_> { #[cfg(test)] mod tests { - use alloc::string::ToString; - use super::*; use crate::time::cds::CdsTime; #[cfg(feature = "serde")] use crate::time::CcsdsTimeProvider; use crate::SpHeader; use crate::{ecss::PusVersion::PusC, MAX_SEQ_COUNT}; + use alloc::string::ToString; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; @@ -1190,6 +1328,20 @@ mod tests { PusTmCreator::new_no_source_data(sph, tm_header, CreatorConfig::default()) } + fn base_ping_reply_full_ctor_builder<'a, 'b>( + timestamp: &'a [u8], + alt_api: bool, + ) -> PusTmCreator<'a, 'b> { + if alt_api {} + PusTmBuilder::new() + .with_apid(u11::new(0x123)) + .with_sequence_count(u14::new(0x234)) + .with_service(17) + .with_subservice(2) + .with_timestamp(timestamp) + .build() + } + fn base_ping_reply_full_ctor_no_checksum<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> { let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); @@ -1938,4 +2090,41 @@ mod tests { let output_converted_back: PusTmReader = from_bytes(&output).unwrap(); assert_eq!(output_converted_back, tm_reader); } + + #[test] + fn test_builder() { + assert_eq!( + base_ping_reply_full_ctor_builder(dummy_timestamp(), false), + base_ping_reply_full_ctor(dummy_timestamp()) + ); + } + + #[test] + fn test_builder_2() { + assert_eq!( + base_ping_reply_full_ctor_builder(dummy_timestamp(), true), + base_ping_reply_full_ctor(dummy_timestamp()) + ); + } + + #[test] + fn test_builder_3() { + let tm = PusTmBuilder::new() + .with_packet_id(PacketId::new_for_tc(true, u11::new(0x02))) + .with_packet_sequence_control(PacketSequenceControl::new( + SequenceFlags::Unsegmented, + u14::new(0x34), + )) + .with_service(17) + .with_subservice(2) + .with_dest_id(0x2f2f) + .with_checksum(false) + .build(); + assert_eq!(tm.seq_count().value(), 0x34); + assert_eq!(tm.sequence_flags(), SequenceFlags::Unsegmented); + assert_eq!(tm.apid().value(), 0x02); + assert_eq!(tm.packet_type(), PacketType::Tm); + assert_eq!(tm.service(), 17); + assert_eq!(tm.subservice(), 2); + } }