Add TM builder API

This commit is contained in:
Robin Mueller
2025-09-10 17:01:49 +02:00
parent 89788c1341
commit 845a8ac8f4
2 changed files with 195 additions and 5 deletions

View File

@@ -708,6 +708,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
}
}
#[derive(Debug)]
pub struct PusTcBuilder<'a> {
sp_header: SpHeader,
sec_header: PusTcSecondaryHeader,

View File

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