continue making checksum optional

This commit is contained in:
Robin Mueller
2025-09-09 15:02:51 +02:00
parent bf86f58b48
commit 2ded5957c9
6 changed files with 431 additions and 147 deletions

View File

@@ -21,6 +21,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Renamed `SeqCountProviderSimple` to `SequenceCounterSimple` - Renamed `SeqCountProviderSimple` to `SequenceCounterSimple`
- Renamed `CcsdsSimpleSeqCountProvider` to `SequenceCounterCcsdsSimple` - Renamed `CcsdsSimpleSeqCountProvider` to `SequenceCounterCcsdsSimple`
- Renamed `SeqCountProviderSync` to `SequenceCounterSync` - Renamed `SeqCountProviderSync` to `SequenceCounterSync`
- Renamed `PusPacket::opt_crc16` to `PusPacket::checksum`
- ECSS checksum generation is now optional as specified in the standard. Added `has_checksum`
parameters for ECSS TM/TC creators and readers to reflect this.
## Removed ## Removed
@@ -31,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added PUS A legacy support for telecommands inside the `ecss.tc_pus_a` module - Added PUS A legacy support for telecommands inside the `ecss.tc_pus_a` module
- Added `SequenceCounter::increment_mut` and `SequenceCounter::get_and_increment_mut` - Added `SequenceCounter::increment_mut` and `SequenceCounter::get_and_increment_mut`
- Implemented `SequenceCounter` for `Atomic` unsigned types and references of them - Implemented `SequenceCounter` for `Atomic` unsigned types and references of them
- `PusPacket::has_checksum`
# [v0.15.0] 2025-07-18 # [v0.15.0] 2025-07-18

View File

@@ -172,7 +172,12 @@ pub trait PusPacket: CcsdsPacket {
fn service(&self) -> u8; fn service(&self) -> u8;
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
fn user_data(&self) -> &[u8]; fn user_data(&self) -> &[u8];
fn opt_crc16(&self) -> Option<u16>; /// CRC-16-CCITT checksum.
fn checksum(&self) -> Option<u16>;
/// The presence of the CRC-16-CCITT checksum is optional.
fn has_checksum(&self) -> bool {
self.checksum().is_some()
}
} }
pub(crate) fn crc_from_raw_data(raw_data: &[u8]) -> Result<u16, ByteConversionError> { pub(crate) fn crc_from_raw_data(raw_data: &[u8]) -> Result<u16, ByteConversionError> {
@@ -199,13 +204,18 @@ pub(crate) fn user_data_from_raw(
current_idx: usize, current_idx: usize,
total_len: usize, total_len: usize,
slice: &[u8], slice: &[u8],
has_checksum: bool,
) -> Result<&[u8], ByteConversionError> { ) -> Result<&[u8], ByteConversionError> {
match current_idx { if has_checksum {
_ if current_idx > total_len - 2 => Err(ByteConversionError::FromSliceTooSmall { if current_idx > total_len - 2 {
found: total_len - 2, return Err(ByteConversionError::FromSliceTooSmall {
expected: current_idx, found: total_len - 2,
}), expected: current_idx,
_ => Ok(&slice[current_idx..total_len - 2]), });
}
Ok(&slice[current_idx..total_len - 2])
} else {
Ok(&slice[current_idx..total_len])
} }
} }
@@ -422,6 +432,23 @@ pub trait WritablePusPacket {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CreatorConfig {
pub set_ccsds_len: bool,
pub has_checksum: bool,
}
impl Default for CreatorConfig {
fn default() -> Self {
Self {
set_ccsds_len: true,
has_checksum: true,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use alloc::string::ToString; use alloc::string::ToString;

View File

@@ -34,6 +34,7 @@
//! assert_eq!(pus_tc.apid(), 0x02); //! assert_eq!(pus_tc.apid(), 0x02);
//! ``` //! ```
use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE};
pub use crate::ecss::CreatorConfig;
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, PusError, PusPacket, PusVersion, verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, PusVersion,
@@ -256,8 +257,7 @@ impl<'app_data> PusTcCreator<'app_data> {
mut sp_header: SpHeader, mut sp_header: SpHeader,
sec_header: PusTcSecondaryHeader, sec_header: PusTcSecondaryHeader,
app_data: &'app_data [u8], app_data: &'app_data [u8],
set_ccsds_len: bool, creator_config: CreatorConfig,
has_checksum: bool,
) -> Self { ) -> Self {
sp_header.set_packet_type(PacketType::Tc); sp_header.set_packet_type(PacketType::Tc);
sp_header.set_sec_header_flag(); sp_header.set_sec_header_flag();
@@ -265,9 +265,9 @@ impl<'app_data> PusTcCreator<'app_data> {
sp_header, sp_header,
app_data, app_data,
sec_header, sec_header,
has_checksum, has_checksum: creator_config.has_checksum,
}; };
if set_ccsds_len { if creator_config.set_ccsds_len {
pus_tc.update_ccsds_data_len(); pus_tc.update_ccsds_data_len();
} }
pus_tc pus_tc
@@ -281,15 +281,13 @@ impl<'app_data> PusTcCreator<'app_data> {
service: u8, service: u8,
subservice: u8, subservice: u8,
app_data: &'app_data [u8], app_data: &'app_data [u8],
set_ccsds_len: bool, creator_config: CreatorConfig,
has_checksum: bool,
) -> Self { ) -> Self {
Self::new( Self::new(
sph, sph,
PusTcSecondaryHeader::new(service, subservice, ACK_ALL, 0), PusTcSecondaryHeader::new(service, subservice, ACK_ALL, 0),
app_data, app_data,
set_ccsds_len, creator_config,
has_checksum,
) )
} }
@@ -297,10 +295,9 @@ impl<'app_data> PusTcCreator<'app_data> {
pub fn new_no_app_data( pub fn new_no_app_data(
sp_header: SpHeader, sp_header: SpHeader,
sec_header: PusTcSecondaryHeader, sec_header: PusTcSecondaryHeader,
set_ccsds_len: bool, creator_config: CreatorConfig,
has_checksum: bool,
) -> Self { ) -> Self {
Self::new(sp_header, sec_header, &[], set_ccsds_len, has_checksum) Self::new(sp_header, sec_header, &[], creator_config)
} }
#[inline] #[inline]
@@ -363,6 +360,11 @@ impl<'app_data> PusTcCreator<'app_data> {
digest.finalize() digest.finalize()
} }
#[inline]
pub fn has_checksum(&self) -> bool {
self.has_checksum
}
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
pub fn append_to_vec(&self, vec: &mut Vec<u8>) -> usize { pub fn append_to_vec(&self, vec: &mut Vec<u8>) -> usize {
let sph_zc = crate::zc::SpHeader::from(self.sp_header); let sph_zc = crate::zc::SpHeader::from(self.sp_header);
@@ -438,8 +440,9 @@ impl WritablePusPacket for PusTcCreator<'_> {
len len
} }
#[inline]
fn has_checksum(&self) -> bool { fn has_checksum(&self) -> bool {
self.has_checksum self.has_checksum()
} }
/// Write the raw PUS byte representation to a provided buffer. /// Write the raw PUS byte representation to a provided buffer.
@@ -476,9 +479,16 @@ impl PusPacket for PusTcCreator<'_> {
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
if !self.has_checksum {
return None;
}
Some(self.calc_own_crc16()) Some(self.calc_own_crc16())
} }
fn has_checksum(&self) -> bool {
self.has_checksum
}
} }
impl GenericPusTcSecondaryHeader for PusTcCreator<'_> { impl GenericPusTcSecondaryHeader for PusTcCreator<'_> {
@@ -680,29 +690,44 @@ pub struct PusTcReader<'raw_data> {
sp_header: SpHeader, sp_header: SpHeader,
sec_header: PusTcSecondaryHeader, sec_header: PusTcSecondaryHeader,
app_data: &'raw_data [u8], app_data: &'raw_data [u8],
crc16: u16, crc16: Option<u16>,
} }
impl<'raw_data> PusTcReader<'raw_data> { impl<'raw_data> PusTcReader<'raw_data> {
/// Create a [PusTcReader] instance from a raw slice. On success, it returns a tuple containing /// Create a [PusTcReader] instance from a raw slice. The given packet should have a
/// the instance and the found byte length of the packet. This function also performs a CRC /// a CRC16-CCITT checksum which is also verified.
/// check and will return an appropriate [PusError] if the check fails. ///
/// 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.
pub fn new(slice: &'raw_data [u8]) -> Result<Self, PusError> { pub fn new(slice: &'raw_data [u8]) -> Result<Self, PusError> {
let pus_tc = Self::new_no_crc_check(slice)?; let pus_tc = Self::new_no_checksum_verification(slice, true)?;
verify_crc16_ccitt_false_from_raw_to_pus_error(pus_tc.raw_data(), pus_tc.crc16())?; // Unwrap for CRC16 okay, should always have some value.
verify_crc16_ccitt_false_from_raw_to_pus_error(pus_tc.raw_data(), pus_tc.crc16().unwrap())?;
Ok(pus_tc) Ok(pus_tc)
} }
/// Similar to [PusTcReader::new], but uses a table-less CRC16 algorithm which can reduce /// Similar to [PusTcReader::new], but uses a table-less CRC16 algorithm which can reduce
/// binary size and memory usage. /// binary size and memory usage.
pub fn new_crc_no_table(slice: &'raw_data [u8]) -> Result<Self, PusError> { pub fn new_checksum_no_table(slice: &'raw_data [u8]) -> Result<Self, PusError> {
let pus_tc = Self::new_no_crc_check(slice)?; let pus_tc = Self::new_no_checksum_verification(slice, true)?;
verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(pus_tc.raw_data(), pus_tc.crc16())?; // Unwrap for CRC16 okay, should always have some value.
verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(
pus_tc.raw_data(),
pus_tc.crc16().unwrap(),
)?;
Ok(pus_tc) Ok(pus_tc)
} }
/// Creates a new instance without performing a CRC check. /// Read a PUS TC from a raw slice where no checksum is expected.
pub fn new_no_crc_check(slice: &'raw_data [u8]) -> Result<Self, PusError> { pub fn new_no_checksum(slice: &'raw_data [u8]) -> Result<Self, PusError> {
Self::new_no_checksum_verification(slice, false)
}
/// Create a new [Self] instance without verifying the checksum, even if the packet has one.
pub fn new_no_checksum_verification(
slice: &'raw_data [u8],
has_checksum: bool,
) -> Result<Self, PusError> {
let raw_data_len = slice.len(); let raw_data_len = slice.len();
if raw_data_len < PUS_TC_MIN_LEN_WITHOUT_APP_DATA { if raw_data_len < PUS_TC_MIN_LEN_WITHOUT_APP_DATA {
return Err(ByteConversionError::FromSliceTooSmall { return Err(ByteConversionError::FromSliceTooSmall {
@@ -735,12 +760,16 @@ impl<'raw_data> PusTcReader<'raw_data> {
.map_err(|_| ByteConversionError::ZeroCopyFromError)?; .map_err(|_| ByteConversionError::ZeroCopyFromError)?;
current_idx += PUC_TC_SECONDARY_HEADER_LEN; current_idx += PUC_TC_SECONDARY_HEADER_LEN;
let raw_data = &slice[0..total_len]; let raw_data = &slice[0..total_len];
let mut crc16 = None;
if has_checksum {
crc16 = Some(crc_from_raw_data(&slice[total_len - 2..total_len])?);
}
Ok(Self { Ok(Self {
sp_header, sp_header,
sec_header: PusTcSecondaryHeader::try_from(sec_header).unwrap(), sec_header: PusTcSecondaryHeader::try_from(sec_header).unwrap(),
raw_data, raw_data,
app_data: user_data_from_raw(current_idx, total_len, slice)?, app_data: user_data_from_raw(current_idx, total_len, slice, has_checksum)?,
crc16: crc_from_raw_data(raw_data)?, crc16,
}) })
} }
@@ -765,7 +794,7 @@ impl<'raw_data> PusTcReader<'raw_data> {
} }
#[inline] #[inline]
pub fn crc16(&self) -> u16 { pub fn crc16(&self) -> Option<u16> {
self.crc16 self.crc16
} }
} }
@@ -791,14 +820,18 @@ impl PusPacket for PusTcReader<'_> {
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
}); });
fn has_checksum(&self) -> bool {
self.crc16.is_some()
}
#[inline] #[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.app_data self.app_data
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.crc16) self.crc16
} }
} }
@@ -850,17 +883,56 @@ mod tests {
fn base_ping_tc_full_ctor() -> PusTcCreator<'static> { fn base_ping_tc_full_ctor() -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap();
let tc_header = PusTcSecondaryHeader::new_simple(17, 1); let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
PusTcCreator::new_no_app_data(sph, tc_header, true, true) PusTcCreator::new_no_app_data(sph, tc_header, CreatorConfig::default())
}
fn base_ping_tc_full_ctor_no_checksum() -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap();
let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
PusTcCreator::new_no_app_data(
sph,
tc_header,
CreatorConfig {
set_ccsds_len: true,
has_checksum: false,
},
)
} }
fn base_ping_tc_simple_ctor() -> PusTcCreator<'static> { fn base_ping_tc_simple_ctor() -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap();
PusTcCreator::new_simple(sph, 17, 1, &[], true, true) PusTcCreator::new_simple(sph, 17, 1, &[], CreatorConfig::default())
} }
fn base_ping_tc_simple_ctor_with_app_data(app_data: &'static [u8]) -> PusTcCreator<'static> { fn base_ping_tc_simple_ctor_no_checksum() -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap();
PusTcCreator::new_simple(sph, 17, 1, app_data, true, true) PusTcCreator::new_simple(
sph,
17,
1,
&[],
CreatorConfig {
set_ccsds_len: true,
has_checksum: false,
},
)
}
fn base_ping_tc_simple_ctor_with_app_data(
app_data: &'static [u8],
has_checksum: bool,
) -> PusTcCreator<'static> {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap();
PusTcCreator::new_simple(
sph,
17,
1,
app_data,
CreatorConfig {
set_ccsds_len: true,
has_checksum,
},
)
} }
#[test] #[test]
@@ -869,6 +941,14 @@ mod tests {
verify_test_tc(&pus_tc, false, 13); verify_test_tc(&pus_tc, false, 13);
} }
#[test]
fn test_tc_fields_no_checksum() {
let pus_tc = base_ping_tc_full_ctor_no_checksum();
assert!(!pus_tc.has_checksum());
assert!(pus_tc.checksum().is_none());
verify_test_tc(&pus_tc, false, 11);
}
#[test] #[test]
fn test_serialization() { fn test_serialization() {
let pus_tc = base_ping_tc_simple_ctor(); let pus_tc = base_ping_tc_simple_ctor();
@@ -878,11 +958,23 @@ mod tests {
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 13); assert_eq!(size, 13);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
#[test]
fn test_serialization_no_checksum() {
let pus_tc = base_ping_tc_simple_ctor_no_checksum();
let mut test_buf: [u8; 32] = [0; 32];
let size = pus_tc
.write_to_bytes(test_buf.as_mut_slice())
.expect("Error writing TC to buffer");
assert_eq!(size, 11);
assert_eq!(0, u16::from_be_bytes(test_buf[11..13].try_into().unwrap()));
verify_test_tc(&pus_tc, false, 11);
}
#[test] #[test]
fn test_serialization_with_trait_1() { fn test_serialization_with_trait_1() {
let pus_tc = base_ping_tc_simple_ctor(); let pus_tc = base_ping_tc_simple_ctor();
@@ -891,7 +983,7 @@ mod tests {
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 13); assert_eq!(size, 13);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
@@ -905,7 +997,7 @@ mod tests {
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 13); assert_eq!(size, 13);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
@@ -919,13 +1011,13 @@ mod tests {
.expect("error writing tc to buffer"); .expect("error writing tc to buffer");
assert_eq!(size, 13); assert_eq!(size, 13);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
#[test] #[test]
fn test_serialization_no_crc() { fn test_serialization_no_checksum_generation() {
let pus_tc = base_ping_tc_simple_ctor(); let pus_tc = base_ping_tc_simple_ctor();
let mut test_buf: [u8; 32] = [0; 32]; let mut test_buf: [u8; 32] = [0; 32];
let size = pus_tc let size = pus_tc
@@ -937,7 +1029,7 @@ mod tests {
} }
#[test] #[test]
fn test_serialization_no_crc_with_trait() { fn test_serialization_no_checksum_with_trait() {
let pus_tc = base_ping_tc_simple_ctor(); let pus_tc = base_ping_tc_simple_ctor();
let mut test_buf: [u8; 32] = [0; 32]; let mut test_buf: [u8; 32] = [0; 32];
let size = WritablePusPacket::write_to_bytes_no_checksum(&pus_tc, test_buf.as_mut_slice()) let size = WritablePusPacket::write_to_bytes_no_checksum(&pus_tc, test_buf.as_mut_slice())
@@ -994,7 +1086,7 @@ mod tests {
.write_to_bytes(test_buf.as_mut_slice()) .write_to_bytes(test_buf.as_mut_slice())
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 13); assert_eq!(size, 13);
let tc_from_raw = PusTcReader::new_crc_no_table(&test_buf) let tc_from_raw = PusTcReader::new_checksum_no_table(&test_buf)
.expect("Creating PUS TC struct from raw buffer failed"); .expect("Creating PUS TC struct from raw buffer failed");
assert_eq!(tc_from_raw.packet_len(), 13); assert_eq!(tc_from_raw.packet_len(), 13);
verify_test_tc_with_reader(&tc_from_raw, false, 13); verify_test_tc_with_reader(&tc_from_raw, false, 13);
@@ -1020,7 +1112,16 @@ mod tests {
#[test] #[test]
fn test_update_func() { fn test_update_func() {
let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap();
let mut tc = PusTcCreator::new_simple(sph, 17, 1, &[], false, true); let mut tc = PusTcCreator::new_simple(
sph,
17,
1,
&[],
CreatorConfig {
set_ccsds_len: false,
has_checksum: true,
},
);
assert_eq!(tc.data_len(), 0); assert_eq!(tc.data_len(), 0);
tc.update_ccsds_data_len(); tc.update_ccsds_data_len();
assert_eq!(tc.data_len(), 6); assert_eq!(tc.data_len(), 6);
@@ -1028,7 +1129,7 @@ mod tests {
#[test] #[test]
fn test_deserialization_with_app_data() { fn test_deserialization_with_app_data() {
let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3]); let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3], true);
let mut test_buf: [u8; 32] = [0; 32]; let mut test_buf: [u8; 32] = [0; 32];
let size = pus_tc let size = pus_tc
.write_to_bytes(test_buf.as_mut_slice()) .write_to_bytes(test_buf.as_mut_slice())
@@ -1042,7 +1143,7 @@ mod tests {
assert_eq!(tc_from_raw.user_data(), tc_from_raw.app_data()); assert_eq!(tc_from_raw.user_data(), tc_from_raw.app_data());
assert_eq!(tc_from_raw.raw_data(), &test_buf[..size]); assert_eq!(tc_from_raw.raw_data(), &test_buf[..size]);
assert_eq!( assert_eq!(
tc_from_raw.opt_crc16().unwrap(), tc_from_raw.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
assert_eq!(user_data[0], 1); assert_eq!(user_data[0], 1);
@@ -1050,9 +1151,33 @@ mod tests {
assert_eq!(user_data[2], 3); assert_eq!(user_data[2], 3);
} }
#[test]
fn test_deserialization_with_app_data_no_checksum() {
let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3], false);
let mut test_buf: [u8; 32] = [0; 32];
let size = pus_tc
.write_to_bytes(test_buf.as_mut_slice())
.expect("Error writing TC to buffer");
assert_eq!(size, 14);
let tc_from_raw =
PusTcReader::new_no_checksum(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
assert_eq!(tc_from_raw.packet_len(), 14);
verify_test_tc_with_reader(&tc_from_raw, true, 14);
let user_data = tc_from_raw.user_data();
assert_eq!(tc_from_raw.user_data(), tc_from_raw.app_data());
assert_eq!(tc_from_raw.raw_data(), &test_buf[..size]);
assert_eq!(
0,
u16::from_be_bytes(test_buf[size..size + 2].try_into().unwrap())
);
assert_eq!(user_data[0], 1);
assert_eq!(user_data[1], 2);
assert_eq!(user_data[2], 3);
}
#[test] #[test]
fn test_reader_eq() { fn test_reader_eq() {
let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3]); let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3], true);
let mut test_buf: [u8; 32] = [0; 32]; let mut test_buf: [u8; 32] = [0; 32];
pus_tc pus_tc
.write_to_bytes(test_buf.as_mut_slice()) .write_to_bytes(test_buf.as_mut_slice())
@@ -1111,7 +1236,7 @@ mod tests {
#[test] #[test]
fn test_with_application_data_vec() { fn test_with_application_data_vec() {
let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3]); let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3], true);
verify_test_tc(&pus_tc, true, 16); verify_test_tc(&pus_tc, true, 16);
let mut test_vec = Vec::new(); let mut test_vec = Vec::new();
let size = pus_tc.append_to_vec(&mut test_vec); let size = pus_tc.append_to_vec(&mut test_vec);
@@ -1143,7 +1268,7 @@ mod tests {
#[test] #[test]
fn test_with_application_data_buf() { fn test_with_application_data_buf() {
let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3]); let pus_tc = base_ping_tc_simple_ctor_with_app_data(&[1, 2, 3], true);
verify_test_tc(&pus_tc, true, 16); verify_test_tc(&pus_tc, true, 16);
let mut test_buf: [u8; 32] = [0; 32]; let mut test_buf: [u8; 32] = [0; 32];
let size = pus_tc let size = pus_tc
@@ -1284,7 +1409,7 @@ mod tests {
#[test] #[test]
fn test_reader_buf_too_small() { fn test_reader_buf_too_small() {
let app_data = &[1, 2, 3, 4]; let app_data = &[1, 2, 3, 4];
let pus_tc = base_ping_tc_simple_ctor_with_app_data(app_data); let pus_tc = base_ping_tc_simple_ctor_with_app_data(app_data, true);
let mut buf = [0; 32]; let mut buf = [0; 32];
let written_len = pus_tc.write_to_bytes(&mut buf).unwrap(); let written_len = pus_tc.write_to_bytes(&mut buf).unwrap();
let error = PusTcReader::new(&buf[0..PUS_TC_MIN_LEN_WITHOUT_APP_DATA + 1]); let error = PusTcReader::new(&buf[0..PUS_TC_MIN_LEN_WITHOUT_APP_DATA + 1]);

View File

@@ -508,7 +508,7 @@ impl PusPacket for PusTcCreator<'_> {
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.calc_own_crc16()) Some(self.calc_own_crc16())
} }
} }
@@ -738,7 +738,7 @@ impl<'raw_data> PusTcReader<'raw_data> {
sp_header, sp_header,
sec_header, sec_header,
raw_data, raw_data,
app_data: user_data_from_raw(current_idx, total_len, slice)?, app_data: user_data_from_raw(current_idx, total_len, slice, true)?,
crc16: crc_from_raw_data(raw_data)?, crc16: crc_from_raw_data(raw_data)?,
}) })
} }
@@ -790,13 +790,18 @@ impl PusPacket for PusTcReader<'_> {
fn pus_version(&self) -> Result<PusVersion, u8>; fn pus_version(&self) -> Result<PusVersion, u8>;
}); });
#[inline]
fn has_checksum(&self) -> bool {
true
}
#[inline] #[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.app_data self.app_data
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.crc16) Some(self.crc16)
} }
} }
@@ -881,7 +886,7 @@ mod tests {
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 11); assert_eq!(size, 11);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
@@ -894,7 +899,7 @@ mod tests {
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 11); assert_eq!(size, 11);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
@@ -908,7 +913,7 @@ mod tests {
.expect("Error writing TC to buffer"); .expect("Error writing TC to buffer");
assert_eq!(size, 11); assert_eq!(size, 11);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
@@ -922,7 +927,7 @@ mod tests {
.expect("error writing tc to buffer"); .expect("error writing tc to buffer");
assert_eq!(size, 11); assert_eq!(size, 11);
assert_eq!( assert_eq!(
pus_tc.opt_crc16().unwrap(), pus_tc.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
} }
@@ -1045,7 +1050,7 @@ mod tests {
assert_eq!(tc_from_raw.user_data(), tc_from_raw.app_data()); assert_eq!(tc_from_raw.user_data(), tc_from_raw.app_data());
assert_eq!(tc_from_raw.raw_data(), &test_buf[..size]); assert_eq!(tc_from_raw.raw_data(), &test_buf[..size]);
assert_eq!( assert_eq!(
tc_from_raw.opt_crc16().unwrap(), tc_from_raw.checksum().unwrap(),
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap()) u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
); );
assert_eq!(user_data[0], 1); assert_eq!(user_data[0], 1);

View File

@@ -43,9 +43,10 @@
//! assert_eq!(ping_tm_reader.timestamp(), &time_buf); //! assert_eq!(ping_tm_reader.timestamp(), &time_buf);
//! ``` //! ```
use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE};
pub use crate::ecss::CreatorConfig;
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, PusError, PusPacket, PusVersion,
WritablePusPacket, WritablePusPacket,
}; };
use crate::{ use crate::{
@@ -71,8 +72,7 @@ pub trait IsPusTelemetry {}
/// Length without timestamp /// Length without timestamp
pub const PUS_TM_MIN_SEC_HEADER_LEN: usize = 7; pub const PUS_TM_MIN_SEC_HEADER_LEN: usize = 7;
pub const PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA: usize = pub const PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA: usize = CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN;
CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + size_of::<CrcType>();
pub trait GenericPusTmSecondaryHeader { pub trait GenericPusTmSecondaryHeader {
fn pus_version(&self) -> Result<PusVersion, u8>; fn pus_version(&self) -> Result<PusVersion, u8>;
@@ -275,6 +275,7 @@ pub struct PusTmCreator<'time, 'src_data> {
/// If this is set to false, a manual call to [Self::calc_own_crc16] or /// If this is set to false, a manual call to [Self::calc_own_crc16] or
/// [Self::update_packet_fields] is necessary for the serialized or cached CRC16 to be valid. /// [Self::update_packet_fields] is necessary for the serialized or cached CRC16 to be valid.
pub calc_crc_on_serialization: bool, pub calc_crc_on_serialization: bool,
has_checksum: bool,
} }
impl<'time, 'src_data> PusTmCreator<'time, 'src_data> { impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
@@ -295,7 +296,7 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
mut sp_header: SpHeader, mut sp_header: SpHeader,
sec_header: PusTmSecondaryHeader<'time>, sec_header: PusTmSecondaryHeader<'time>,
source_data: &'src_data [u8], source_data: &'src_data [u8],
set_ccsds_len: bool, packet_config: CreatorConfig,
) -> Self { ) -> Self {
sp_header.set_packet_type(PacketType::Tm); sp_header.set_packet_type(PacketType::Tm);
sp_header.set_sec_header_flag(); sp_header.set_sec_header_flag();
@@ -304,8 +305,9 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
source_data, source_data,
sec_header, sec_header,
calc_crc_on_serialization: true, calc_crc_on_serialization: true,
has_checksum: packet_config.has_checksum,
}; };
if set_ccsds_len { if packet_config.set_ccsds_len {
pus_tm.update_ccsds_data_len(); pus_tm.update_ccsds_data_len();
} }
pus_tm pus_tm
@@ -319,21 +321,26 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
time_provider: &impl TimeWriter, time_provider: &impl TimeWriter,
stamp_buf: &'time mut [u8], stamp_buf: &'time mut [u8],
source_data: &'src_data [u8], source_data: &'src_data [u8],
set_ccsds_len: bool, packet_config: CreatorConfig,
) -> Result<Self, TimestampError> { ) -> Result<Self, TimestampError> {
let stamp_size = time_provider.write_to_bytes(stamp_buf)?; let stamp_size = time_provider.write_to_bytes(stamp_buf)?;
let sec_header = let sec_header =
PusTmSecondaryHeader::new_simple(service, subservice, &stamp_buf[0..stamp_size]); PusTmSecondaryHeader::new_simple(service, subservice, &stamp_buf[0..stamp_size]);
Ok(Self::new(sp_header, sec_header, source_data, set_ccsds_len)) Ok(Self::new(sp_header, sec_header, source_data, packet_config))
} }
#[inline] #[inline]
pub fn new_no_source_data( pub fn new_no_source_data(
sp_header: SpHeader, sp_header: SpHeader,
sec_header: PusTmSecondaryHeader<'time>, sec_header: PusTmSecondaryHeader<'time>,
set_ccsds_len: bool, packet_config: CreatorConfig,
) -> Self { ) -> Self {
Self::new(sp_header, sec_header, &[], set_ccsds_len) Self::new(sp_header, sec_header, &[], packet_config)
}
#[inline]
fn has_checksum(&self) -> bool {
self.has_checksum
} }
#[inline] #[inline]
@@ -429,6 +436,7 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
self.sp_header, self.sp_header,
self.sec_header, self.sec_header,
self.source_data.len(), self.source_data.len(),
self.has_checksum,
)?; )?;
writer_unfinalized writer_unfinalized
.source_data_mut() .source_data_mut()
@@ -441,6 +449,9 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
pub fn append_to_vec(&self, vec: &mut Vec<u8>) -> Result<usize, PusError> { pub fn append_to_vec(&self, vec: &mut Vec<u8>) -> Result<usize, PusError> {
let sph_zc = crate::zc::SpHeader::from(self.sp_header); let sph_zc = crate::zc::SpHeader::from(self.sp_header);
let mut appended_len = PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + self.sec_header.timestamp.len(); let mut appended_len = PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + self.sec_header.timestamp.len();
if self.has_checksum {
appended_len += 2;
}
appended_len += self.source_data.len(); appended_len += self.source_data.len();
let start_idx = vec.len(); let start_idx = vec.len();
vec.extend_from_slice(sph_zc.as_bytes()); vec.extend_from_slice(sph_zc.as_bytes());
@@ -459,14 +470,18 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
impl WritablePusPacket for PusTmCreator<'_, '_> { impl WritablePusPacket for PusTmCreator<'_, '_> {
#[inline] #[inline]
fn len_written(&self) -> usize { fn len_written(&self) -> usize {
PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA let mut len = 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();
if self.has_checksum {
len += 2
}
len
} }
/// Currently, checksum is always added. /// Currently, checksum is always added.
fn has_checksum(&self) -> bool { fn has_checksum(&self) -> bool {
true self.has_checksum
} }
/// Write the raw PUS byte representation to a provided buffer. /// Write the raw PUS byte representation to a provided buffer.
@@ -502,6 +517,11 @@ impl PusPacket for PusTmCreator<'_, '_> {
Ok(self.sec_header.pus_version) Ok(self.sec_header.pus_version)
} }
#[inline]
fn has_checksum(&self) -> bool {
self.has_checksum()
}
delegate!(to self.sec_header { delegate!(to self.sec_header {
#[inline] #[inline]
fn service(&self) -> u8; fn service(&self) -> u8;
@@ -515,7 +535,7 @@ impl PusPacket for PusTmCreator<'_, '_> {
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.calc_own_crc16()) Some(self.calc_own_crc16())
} }
} }
@@ -574,11 +594,15 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
mut sp_header: SpHeader, mut sp_header: SpHeader,
sec_header: PusTmSecondaryHeader, sec_header: PusTmSecondaryHeader,
src_data_len: usize, src_data_len: usize,
has_checksum: bool,
) -> Result<Self, ByteConversionError> { ) -> Result<Self, ByteConversionError> {
sp_header.set_packet_type(PacketType::Tm); sp_header.set_packet_type(PacketType::Tm);
sp_header.set_sec_header_flag(); sp_header.set_sec_header_flag();
let len_written = let mut len_written =
PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + sec_header.timestamp.len() + src_data_len; PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA + sec_header.timestamp.len() + src_data_len;
if has_checksum {
len_written += 2;
}
if len_written > buf.len() { if len_written > buf.len() {
return Err(ByteConversionError::ToSliceTooSmall { return Err(ByteConversionError::ToSliceTooSmall {
found: buf.len(), found: buf.len(),
@@ -586,7 +610,7 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
}); });
} }
sp_header.data_len = len_written as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1; sp_header.data_len = len_written as u16 - size_of::<crate::zc::SpHeader>() as u16 - 1;
Self::write_to_bytes_partially(buf, sp_header, sec_header, src_data_len) Self::write_to_bytes_partially(buf, sp_header, sec_header, src_data_len, has_checksum)
} }
fn write_to_bytes_partially( fn write_to_bytes_partially(
@@ -594,6 +618,7 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
sp_header: SpHeader, sp_header: SpHeader,
sec_header: PusTmSecondaryHeader, sec_header: PusTmSecondaryHeader,
src_data_len: usize, src_data_len: usize,
has_checksum: bool,
) -> Result<Self, ByteConversionError> { ) -> Result<Self, ByteConversionError> {
let mut curr_idx = 0; let mut curr_idx = 0;
sp_header.write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?; sp_header.write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?;
@@ -608,10 +633,13 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
curr_idx += sec_header.timestamp.len(); curr_idx += sec_header.timestamp.len();
let source_data_offset = curr_idx; let source_data_offset = curr_idx;
curr_idx += src_data_len; curr_idx += src_data_len;
if has_checksum {
curr_idx += 2;
}
Ok(Self { Ok(Self {
buf, buf,
source_data_offset, source_data_offset,
full_len: curr_idx + 2, full_len: curr_idx,
}) })
} }
@@ -669,6 +697,14 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ReaderConfig {
pub timestamp_len: usize,
pub has_checksum: bool,
}
/// This class models the PUS C telemetry packet. It is the primary data structure to read /// This class models the PUS C telemetry packet. It is the primary data structure to read
/// a telemetry packet from raw bytes. /// a telemetry packet from raw bytes.
/// ///
@@ -690,7 +726,7 @@ pub struct PusTmReader<'raw_data> {
#[cfg_attr(feature = "serde", serde(skip))] #[cfg_attr(feature = "serde", serde(skip))]
raw_data: &'raw_data [u8], raw_data: &'raw_data [u8],
source_data: &'raw_data [u8], source_data: &'raw_data [u8],
crc16: u16, checksum_crc16: Option<u16>,
} }
impl<'raw_data> PusTmReader<'raw_data> { impl<'raw_data> PusTmReader<'raw_data> {
@@ -701,24 +737,39 @@ impl<'raw_data> PusTmReader<'raw_data> {
/// This function will check the CRC-16 of the PUS packet and will return an appropriate /// This function will check the CRC-16 of the PUS packet and will return an appropriate
/// [PusError] if the check fails. /// [PusError] if the check fails.
pub fn new(slice: &'raw_data [u8], timestamp_len: usize) -> Result<Self, PusError> { pub fn new(slice: &'raw_data [u8], timestamp_len: usize) -> Result<Self, PusError> {
let tc = Self::new_no_crc_check(slice, timestamp_len)?; let tc = Self::new_no_checksum_verification(
verify_crc16_ccitt_false_from_raw_to_pus_error(tc.raw_data(), tc.crc16)?; slice,
ReaderConfig {
timestamp_len,
has_checksum: true,
},
)?;
verify_crc16_ccitt_false_from_raw_to_pus_error(tc.raw_data(), tc.checksum().unwrap())?;
Ok(tc) Ok(tc)
} }
/// Like [PusTmReader::new] but uses a table-less CRC implementation. /// Like [PusTmReader::new] but uses a table-less CRC implementation.
pub fn new_crc_no_table( pub fn new_checksum_no_table(
slice: &'raw_data [u8], slice: &'raw_data [u8],
timestamp_len: usize, timestamp_len: usize,
) -> Result<Self, PusError> { ) -> Result<Self, PusError> {
let tc = Self::new_no_crc_check(slice, timestamp_len)?; let tc = Self::new_no_checksum_verification(
verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(tc.raw_data(), tc.crc16)?; slice,
ReaderConfig {
timestamp_len,
has_checksum: true,
},
)?;
verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(
tc.raw_data(),
tc.checksum().unwrap(),
)?;
Ok(tc) Ok(tc)
} }
pub fn new_no_crc_check( pub fn new_no_checksum_verification(
slice: &'raw_data [u8], slice: &'raw_data [u8],
timestamp_len: usize, reader_config: ReaderConfig,
) -> Result<Self, PusError> { ) -> Result<Self, PusError> {
let raw_data_len = slice.len(); let raw_data_len = slice.len();
if raw_data_len < PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA { if raw_data_len < PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA {
@@ -753,16 +804,25 @@ impl<'raw_data> PusTmReader<'raw_data> {
current_idx += PUS_TM_MIN_SEC_HEADER_LEN; current_idx += PUS_TM_MIN_SEC_HEADER_LEN;
let zc_sec_header_wrapper = zc::PusTmSecHeader { let zc_sec_header_wrapper = zc::PusTmSecHeader {
zc_header: sec_header_zc, zc_header: sec_header_zc,
timestamp: &slice[current_idx..current_idx + timestamp_len], timestamp: &slice[current_idx..current_idx + reader_config.timestamp_len],
}; };
current_idx += timestamp_len; current_idx += reader_config.timestamp_len;
let raw_data = &slice[0..total_len]; let raw_data = &slice[0..total_len];
let mut crc16 = None;
if reader_config.has_checksum {
crc16 = Some(crc_from_raw_data(raw_data)?);
}
Ok(Self { Ok(Self {
sp_header, sp_header,
sec_header: PusTmSecondaryHeader::try_from(zc_sec_header_wrapper).unwrap(), sec_header: PusTmSecondaryHeader::try_from(zc_sec_header_wrapper).unwrap(),
raw_data: &slice[0..total_len], raw_data,
source_data: user_data_from_raw(current_idx, total_len, slice)?, source_data: user_data_from_raw(
crc16: crc_from_raw_data(raw_data)?, current_idx,
total_len,
slice,
reader_config.has_checksum,
)?,
checksum_crc16: crc16,
}) })
} }
@@ -782,8 +842,8 @@ impl<'raw_data> PusTmReader<'raw_data> {
} }
#[inline] #[inline]
pub fn crc16(&self) -> u16 { pub fn checksum(&self) -> Option<u16> {
self.crc16 self.checksum_crc16
} }
/// This function will return the slice [Self] was constructed from. /// This function will return the slice [Self] was constructed from.
@@ -798,7 +858,7 @@ impl PartialEq for PusTmReader<'_> {
self.sec_header == other.sec_header self.sec_header == other.sec_header
&& self.source_data == other.source_data && self.source_data == other.source_data
&& self.sp_header == other.sp_header && self.sp_header == other.sp_header
&& self.crc16 == other.crc16 && self.checksum_crc16 == other.checksum_crc16
} }
} }
@@ -816,14 +876,19 @@ impl PusPacket for PusTmReader<'_> {
fn subservice(&self) -> u8; fn subservice(&self) -> u8;
}); });
#[inline]
fn has_checksum(&self) -> bool {
self.checksum_crc16.is_some()
}
#[inline] #[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
self.source_data self.source_data
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.crc16()) self.checksum()
} }
} }
@@ -875,6 +940,7 @@ impl PartialEq<PusTmReader<'_>> for PusTmCreator<'_, '_> {
pub struct PusTmZeroCopyWriter<'raw> { pub struct PusTmZeroCopyWriter<'raw> {
raw_tm: &'raw mut [u8], raw_tm: &'raw mut [u8],
timestamp_len: usize, timestamp_len: usize,
has_checksum: bool,
} }
impl<'raw> PusTmZeroCopyWriter<'raw> { impl<'raw> PusTmZeroCopyWriter<'raw> {
@@ -883,9 +949,13 @@ impl<'raw> PusTmZeroCopyWriter<'raw> {
/// ///
/// It is the responsibility of the user to ensure the raw slice contains a valid telemetry /// It is the responsibility of the user to ensure the raw slice contains a valid telemetry
/// packet. /// packet.
pub fn new(raw_tm: &'raw mut [u8], timestamp_len: usize) -> Option<Self> { pub fn new(raw_tm: &'raw mut [u8], timestamp_len: usize, has_checksum: bool) -> Option<Self> {
let raw_tm_len = raw_tm.len(); let raw_tm_len = raw_tm.len();
if raw_tm_len < CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + timestamp_len { let min_len = CCSDS_HEADER_LEN
+ PUS_TM_MIN_SEC_HEADER_LEN
+ timestamp_len
+ if has_checksum { 2 } else { 0 };
if raw_tm_len < min_len {
return None; return None;
} }
let sp_header = crate::zc::SpHeader::read_from_bytes(&raw_tm[0..CCSDS_HEADER_LEN]).unwrap(); let sp_header = crate::zc::SpHeader::read_from_bytes(&raw_tm[0..CCSDS_HEADER_LEN]).unwrap();
@@ -895,6 +965,7 @@ impl<'raw> PusTmZeroCopyWriter<'raw> {
let writer = Self { let writer = Self {
raw_tm: &mut raw_tm[..sp_header.packet_len()], raw_tm: &mut raw_tm[..sp_header.packet_len()],
timestamp_len, timestamp_len,
has_checksum,
}; };
Some(writer) Some(writer)
} }
@@ -959,9 +1030,11 @@ impl<'raw> PusTmZeroCopyWriter<'raw> {
/// This method has to be called after modifying fields to ensure the CRC16 of the telemetry /// This method has to be called after modifying fields to ensure the CRC16 of the telemetry
/// packet remains valid. /// packet remains valid.
pub fn finish(self) { pub fn finish(self) {
let slice_len = self.raw_tm.len(); if self.has_checksum {
let crc16 = calc_pus_crc16(&self.raw_tm[..slice_len - 2]); let slice_len = self.raw_tm.len();
self.raw_tm[slice_len - 2..].copy_from_slice(&crc16.to_be_bytes()); let crc16 = calc_pus_crc16(&self.raw_tm[..slice_len - 2]);
self.raw_tm[slice_len - 2..].copy_from_slice(&crc16.to_be_bytes());
}
} }
} }
@@ -998,6 +1071,11 @@ impl PusPacket for PusTmZeroCopyWriter<'_> {
self.raw_tm[7] self.raw_tm[7]
} }
#[inline]
fn has_checksum(&self) -> bool {
self.has_checksum
}
#[inline] #[inline]
fn subservice(&self) -> u8 { fn subservice(&self) -> u8 {
self.raw_tm[8] self.raw_tm[8]
@@ -1005,12 +1083,20 @@ impl PusPacket for PusTmZeroCopyWriter<'_> {
#[inline] #[inline]
fn user_data(&self) -> &[u8] { fn user_data(&self) -> &[u8] {
&self.raw_tm[CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + self.timestamp_len if self.has_checksum {
..self.sp_header().packet_len() - 2] &self.raw_tm[CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + self.timestamp_len
..self.sp_header().packet_len() - 2]
} else {
&self.raw_tm[CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN + self.timestamp_len
..self.sp_header().packet_len()]
}
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
if !self.has_checksum {
return None;
}
Some(u16::from_be_bytes( Some(u16::from_be_bytes(
self.raw_tm[self.sp_header().packet_len() - 2..self.sp_header().packet_len()] self.raw_tm[self.sp_header().packet_len() - 2..self.sp_header().packet_len()]
.try_into() .try_into()
@@ -1062,18 +1148,18 @@ mod tests {
fn base_ping_reply_full_ctor<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> { fn base_ping_reply_full_ctor<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
PusTmCreator::new_no_source_data(sph, tm_header, true) PusTmCreator::new_no_source_data(sph, tm_header, CreatorConfig::default())
} }
fn ping_reply_with_data<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> { fn ping_reply_with_data<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
PusTmCreator::new(sph, tm_header, DUMMY_DATA, true) PusTmCreator::new(sph, tm_header, DUMMY_DATA, CreatorConfig::default())
} }
fn base_hk_reply<'a, 'b>(timestamp: &'a [u8], src_data: &'b [u8]) -> PusTmCreator<'a, 'b> { fn base_hk_reply<'a, 'b>(timestamp: &'a [u8], src_data: &'b [u8]) -> PusTmCreator<'a, 'b> {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp);
PusTmCreator::new(sph, tc_header, src_data, true) PusTmCreator::new(sph, tc_header, src_data, CreatorConfig::default())
} }
fn dummy_timestamp() -> &'static [u8] { fn dummy_timestamp() -> &'static [u8] {
@@ -1091,9 +1177,16 @@ mod tests {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let time_provider = CdsTime::new_with_u16_days(0, 0); let time_provider = CdsTime::new_with_u16_days(0, 0);
let mut stamp_buf: [u8; 8] = [0; 8]; let mut stamp_buf: [u8; 8] = [0; 8];
let pus_tm = let pus_tm = PusTmCreator::new_simple(
PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true) sph,
.unwrap(); 17,
2,
&time_provider,
&mut stamp_buf,
&[],
CreatorConfig::default(),
)
.unwrap();
verify_ping_reply(&pus_tm, false, 22, &[64, 0, 0, 0, 0, 0, 0]); verify_ping_reply(&pus_tm, false, 22, &[64, 0, 0, 0, 0, 0, 0]);
} }
@@ -1106,7 +1199,7 @@ mod tests {
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 22); assert_eq!(ser_len, 22);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf); verify_raw_ping_reply(pus_tm.checksum(), &buf);
} }
#[test] #[test]
@@ -1116,7 +1209,7 @@ mod tests {
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
let mut pus_tm = let mut pus_tm =
PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0).unwrap(); PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0, true).unwrap();
assert_eq!(pus_tm.source_data_len(), 0); assert_eq!(pus_tm.source_data_len(), 0);
assert_eq!(pus_tm.source_data(), &[]); assert_eq!(pus_tm.source_data(), &[]);
assert_eq!(pus_tm.source_data_mut(), &[]); assert_eq!(pus_tm.source_data_mut(), &[]);
@@ -1132,7 +1225,7 @@ mod tests {
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
let mut pus_tm = let mut pus_tm =
PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0).unwrap(); PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0, true).unwrap();
assert_eq!(pus_tm.source_data_len(), 0); assert_eq!(pus_tm.source_data_len(), 0);
assert_eq!(pus_tm.source_data(), &[]); assert_eq!(pus_tm.source_data(), &[]);
assert_eq!(pus_tm.source_data_mut(), &[]); assert_eq!(pus_tm.source_data_mut(), &[]);
@@ -1152,7 +1245,7 @@ mod tests {
.write_to_bytes_crc_no_table(&mut buf) .write_to_bytes_crc_no_table(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 22); assert_eq!(ser_len, 22);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf); verify_raw_ping_reply(pus_tm.checksum(), &buf);
} }
#[test] #[test]
@@ -1189,7 +1282,7 @@ mod tests {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp()); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp());
let mut hk_reply_unwritten = let mut hk_reply_unwritten =
PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3).unwrap(); PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3, true).unwrap();
assert_eq!(hk_reply_unwritten.source_data_len(), 3); assert_eq!(hk_reply_unwritten.source_data_len(), 3);
assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]); assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]);
assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]); assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]);
@@ -1209,7 +1302,7 @@ mod tests {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp()); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp());
let mut hk_reply_unwritten = let mut hk_reply_unwritten =
PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3).unwrap(); PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3, true).unwrap();
assert_eq!(hk_reply_unwritten.source_data_len(), 3); assert_eq!(hk_reply_unwritten.source_data_len(), 3);
assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]); assert_eq!(hk_reply_unwritten.source_data(), &[0, 0, 0]);
assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]); assert_eq!(hk_reply_unwritten.source_data_mut(), &[0, 0, 0]);
@@ -1261,7 +1354,10 @@ mod tests {
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(
tm_deserialized.checksum().unwrap(),
pus_tm.checksum().unwrap()
);
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp()); verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
} }
@@ -1277,7 +1373,10 @@ mod tests {
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(
tm_deserialized.checksum().unwrap(),
pus_tm.checksum().unwrap()
);
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp()); verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
} }
@@ -1291,11 +1390,14 @@ mod tests {
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 22); assert_eq!(ser_len, 22);
let tm_deserialized = let tm_deserialized =
PusTmReader::new_crc_no_table(&buf, 7).expect("Deserialization failed"); PusTmReader::new_checksum_no_table(&buf, 7).expect("Deserialization failed");
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(
tm_deserialized.checksum().unwrap(),
pus_tm.checksum().unwrap()
);
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp()); verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
} }
@@ -1326,7 +1428,14 @@ mod tests {
fn test_manual_field_update() { fn test_manual_field_update() {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp()); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp());
let mut tm = PusTmCreator::new_no_source_data(sph, tc_header, false); let mut tm = PusTmCreator::new_no_source_data(
sph,
tc_header,
CreatorConfig {
set_ccsds_len: false,
has_checksum: true,
},
);
tm.calc_crc_on_serialization = false; tm.calc_crc_on_serialization = false;
assert_eq!(tm.data_len(), 0x00); assert_eq!(tm.data_len(), 0x00);
let mut buf: [u8; 32] = [0; 32]; let mut buf: [u8; 32] = [0; 32];
@@ -1365,7 +1474,7 @@ mod tests {
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());
assert_eq!(res.unwrap(), 22); assert_eq!(res.unwrap(), 22);
verify_raw_ping_reply(pus_tm.opt_crc16(), vec.as_slice()); verify_raw_ping_reply(pus_tm.checksum(), vec.as_slice());
} }
#[test] #[test]
@@ -1492,7 +1601,7 @@ mod tests {
let tm_size = ping_tm let tm_size = ping_tm
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("writing PUS ping TM failed"); .expect("writing PUS ping TM failed");
let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7) let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7, true)
.expect("Creating zero copy writer failed"); .expect("Creating zero copy writer failed");
writer.set_destination_id(55); writer.set_destination_id(55);
writer.set_msg_count(100); writer.set_msg_count(100);
@@ -1517,7 +1626,7 @@ mod tests {
let tm_size = ping_tm let tm_size = ping_tm
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("writing PUS ping TM failed"); .expect("writing PUS ping TM failed");
let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7) let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7, true)
.expect("Creating zero copy writer failed"); .expect("Creating zero copy writer failed");
writer.set_destination_id(55); writer.set_destination_id(55);
writer.set_msg_count(100); writer.set_msg_count(100);
@@ -1537,7 +1646,7 @@ mod tests {
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("writing PUS ping TM failed"); .expect("writing PUS ping TM failed");
let crc16_raw = u16::from_be_bytes(buf[tm_size - 2..tm_size].try_into().unwrap()); let crc16_raw = u16::from_be_bytes(buf[tm_size - 2..tm_size].try_into().unwrap());
let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7) let mut writer = PusTmZeroCopyWriter::new(&mut buf[..tm_size], 7, true)
.expect("Creating zero copy writer failed"); .expect("Creating zero copy writer failed");
writer.set_destination_id(55); writer.set_destination_id(55);
writer.set_msg_count(100); writer.set_msg_count(100);
@@ -1551,7 +1660,7 @@ mod tests {
assert_eq!(writer.sec_header_without_timestamp().msg_counter(), 100); assert_eq!(writer.sec_header_without_timestamp().msg_counter(), 100);
assert_eq!(writer.user_data(), DUMMY_DATA); assert_eq!(writer.user_data(), DUMMY_DATA);
// Need to check crc16 before finish, because finish will update the CRC. // Need to check crc16 before finish, because finish will update the CRC.
let crc16 = writer.opt_crc16(); let crc16 = writer.checksum();
assert!(crc16.is_some()); assert!(crc16.is_some());
assert_eq!(crc16.unwrap(), crc16_raw); assert_eq!(crc16.unwrap(), crc16_raw);
writer.finish(); writer.finish();
@@ -1623,9 +1732,16 @@ mod tests {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let time_provider = CdsTime::new_with_u16_days(0, 0); let time_provider = CdsTime::new_with_u16_days(0, 0);
let mut stamp_buf: [u8; 8] = [0; 8]; let mut stamp_buf: [u8; 8] = [0; 8];
let pus_tm = let pus_tm = PusTmCreator::new_simple(
PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true) sph,
.unwrap(); 17,
2,
&time_provider,
&mut stamp_buf,
&[],
CreatorConfig::default(),
)
.unwrap();
let output = to_allocvec(&pus_tm).unwrap(); let output = to_allocvec(&pus_tm).unwrap();
let output_converted_back: PusTmCreator = from_bytes(&output).unwrap(); let output_converted_back: PusTmCreator = from_bytes(&output).unwrap();
@@ -1638,9 +1754,16 @@ mod tests {
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
let time_provider = CdsTime::new_with_u16_days(0, 0); let time_provider = CdsTime::new_with_u16_days(0, 0);
let mut stamp_buf: [u8; 8] = [0; 8]; let mut stamp_buf: [u8; 8] = [0; 8];
let pus_tm = let pus_tm = PusTmCreator::new_simple(
PusTmCreator::new_simple(sph, 17, 2, &time_provider, &mut stamp_buf, &[], true) sph,
.unwrap(); 17,
2,
&time_provider,
&mut stamp_buf,
&[],
CreatorConfig::default(),
)
.unwrap();
let pus_tm_vec = pus_tm.to_vec().unwrap(); let pus_tm_vec = pus_tm.to_vec().unwrap();
let tm_reader = PusTmReader::new(&pus_tm_vec, time_provider.len_as_bytes()).unwrap(); let tm_reader = PusTmReader::new(&pus_tm_vec, time_provider.len_as_bytes()).unwrap();
let output = to_allocvec(&tm_reader).unwrap(); let output = to_allocvec(&tm_reader).unwrap();

View File

@@ -560,7 +560,7 @@ impl PusPacket for PusTmCreator<'_, '_> {
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.calc_own_crc16()) Some(self.calc_own_crc16())
} }
} }
@@ -795,7 +795,7 @@ impl<'raw_data> PusTmReader<'raw_data> {
sp_header, sp_header,
sec_header, sec_header,
raw_data: &slice[0..total_len], raw_data: &slice[0..total_len],
source_data: user_data_from_raw(current_idx, total_len, slice)?, source_data: user_data_from_raw(current_idx, total_len, slice, true)?,
crc16: crc_from_raw_data(raw_data)?, crc16: crc_from_raw_data(raw_data)?,
}) })
} }
@@ -859,7 +859,7 @@ impl PusPacket for PusTmReader<'_> {
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(self.crc16()) Some(self.crc16())
} }
} }
@@ -1123,7 +1123,7 @@ impl PusPacket for PusTmZeroCopyWriter<'_> {
} }
#[inline] #[inline]
fn opt_crc16(&self) -> Option<u16> { fn checksum(&self) -> Option<u16> {
Some(u16::from_be_bytes( Some(u16::from_be_bytes(
self.raw_tm[self.sp_header().packet_len() - 2..self.sp_header().packet_len()] self.raw_tm[self.sp_header().packet_len() - 2..self.sp_header().packet_len()]
.try_into() .try_into()
@@ -1246,7 +1246,7 @@ mod tests {
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 18); assert_eq!(ser_len, 18);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf, ser_len, None, None); verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, None, None);
} }
#[test] #[test]
@@ -1264,7 +1264,7 @@ mod tests {
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 21); assert_eq!(ser_len, 21);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf, ser_len, msg_counter, dest_id); verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, msg_counter, dest_id);
} }
#[test] #[test]
@@ -1282,7 +1282,7 @@ mod tests {
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 20); assert_eq!(ser_len, 20);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf, ser_len, msg_counter, dest_id); verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, msg_counter, dest_id);
} }
#[test] #[test]
@@ -1300,7 +1300,7 @@ mod tests {
.write_to_bytes(&mut buf) .write_to_bytes(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 19); assert_eq!(ser_len, 19);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf, ser_len, msg_counter, dest_id); verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, msg_counter, dest_id);
} }
#[test] #[test]
@@ -1346,7 +1346,7 @@ mod tests {
.write_to_bytes_crc_no_table(&mut buf) .write_to_bytes_crc_no_table(&mut buf)
.expect("Serialization failed"); .expect("Serialization failed");
assert_eq!(ser_len, 18); assert_eq!(ser_len, 18);
verify_raw_ping_reply(pus_tm.opt_crc16(), &buf, ser_len, None, None); verify_raw_ping_reply(pus_tm.checksum(), &buf, ser_len, None, None);
} }
#[test] #[test]
@@ -1455,7 +1455,7 @@ mod tests {
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None); verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
} }
@@ -1486,7 +1486,7 @@ mod tests {
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
verify_ping_reply_with_reader( verify_ping_reply_with_reader(
&tm_deserialized, &tm_deserialized,
false, false,
@@ -1558,7 +1558,7 @@ mod tests {
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None); verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
} }
@@ -1576,7 +1576,7 @@ mod tests {
assert_eq!(ser_len, tm_deserialized.packet_len()); assert_eq!(ser_len, tm_deserialized.packet_len());
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data()); assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]); assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap()); assert_eq!(tm_deserialized.crc16(), pus_tm.checksum().unwrap());
verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None); verify_ping_reply_with_reader(&tm_deserialized, false, 18, dummy_timestamp(), None, None);
} }
@@ -1646,7 +1646,7 @@ mod tests {
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());
assert_eq!(res.unwrap(), 18); assert_eq!(res.unwrap(), 18);
verify_raw_ping_reply(pus_tm.opt_crc16(), vec.as_slice(), res.unwrap(), None, None); verify_raw_ping_reply(pus_tm.checksum(), vec.as_slice(), res.unwrap(), None, None);
} }
#[test] #[test]
@@ -1857,7 +1857,7 @@ mod tests {
assert!(writer.msg_counter().is_none()); assert!(writer.msg_counter().is_none());
assert_eq!(writer.user_data(), DUMMY_DATA); assert_eq!(writer.user_data(), DUMMY_DATA);
// Need to check crc16 before finish, because finish will update the CRC. // Need to check crc16 before finish, because finish will update the CRC.
let crc16 = writer.opt_crc16(); let crc16 = writer.checksum();
assert!(crc16.is_some()); assert!(crc16.is_some());
assert_eq!(crc16.unwrap(), crc16_raw); assert_eq!(crc16.unwrap(), crc16_raw);
writer.finish(); writer.finish();