diff --git a/src/ecss/mod.rs b/src/ecss/mod.rs index 749616b..8c6dfe4 100644 --- a/src/ecss/mod.rs +++ b/src/ecss/mod.rs @@ -373,30 +373,41 @@ pub trait WritablePusPacket { /// The length here also includes the CRC length. fn len_written(&self) -> usize; - /// Writes the packet to the given slice without writing the CRC. - /// - /// The returned size is the written size WITHOUT the CRC. - fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result; + /// Checksum generation is enabled for the packet. + fn has_checksum(&self) -> bool; - /// First uses [Self::write_to_bytes_no_crc] to write the packet to the given slice and then - /// uses the [CRC_CCITT_FALSE] to calculate the CRC and write it to the slice. + /// Writes the packet to the given slice without writing the CRC checksum. + /// + /// The returned size is the written size WITHOUT the CRC checksum. + /// If the checksum generation is disabled, this function is identical to the APIs which + /// generate a checksum. + fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result; + + /// First uses [Self::write_to_bytes_no_checksum] to write the packet to the given slice and + /// then uses the [CRC_CCITT_FALSE] to calculate the CRC and write it to the slice if the + /// packet is configured to include a checksum. fn write_to_bytes(&self, slice: &mut [u8]) -> Result { - let mut curr_idx = self.write_to_bytes_no_crc(slice)?; - let mut digest = CRC_CCITT_FALSE.digest(); - digest.update(&slice[0..curr_idx]); - slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes()); - curr_idx += 2; + let mut curr_idx = self.write_to_bytes_no_checksum(slice)?; + if self.has_checksum() { + let mut digest = CRC_CCITT_FALSE.digest(); + digest.update(&slice[0..curr_idx]); + slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes()); + curr_idx += 2; + } Ok(curr_idx) } /// First uses [Self::write_to_bytes_no_crc] to write the packet to the given slice and then - /// uses the [CRC_CCITT_FALSE_NO_TABLE] to calculate the CRC and write it to the slice. - fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result { - let mut curr_idx = self.write_to_bytes_no_crc(slice)?; - let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest(); - digest.update(&slice[0..curr_idx]); - slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes()); - curr_idx += 2; + /// uses the [CRC_CCITT_FALSE_NO_TABLE] to calculate the CRC and write it to the slice if + /// the paket is configured to include a checksum. + fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result { + let mut curr_idx = self.write_to_bytes_no_checksum(slice)?; + if self.has_checksum() { + let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest(); + digest.update(&slice[0..curr_idx]); + slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes()); + curr_idx += 2; + } Ok(curr_idx) } diff --git a/src/ecss/tc.rs b/src/ecss/tc.rs index a5c6fa5..1655e5e 100644 --- a/src/ecss/tc.rs +++ b/src/ecss/tc.rs @@ -36,7 +36,7 @@ use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; use crate::ecss::{ 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, }; use crate::SpHeader; @@ -55,8 +55,7 @@ use super::verify_crc16_ccitt_false_from_raw_to_pus_error_no_table; /// PUS C secondary header length is fixed pub const PUC_TC_SECONDARY_HEADER_LEN: usize = size_of::(); -pub const PUS_TC_MIN_LEN_WITHOUT_APP_DATA: usize = - CCSDS_HEADER_LEN + PUC_TC_SECONDARY_HEADER_LEN + size_of::(); +pub const PUS_TC_MIN_LEN_WITHOUT_APP_DATA: usize = CCSDS_HEADER_LEN + PUC_TC_SECONDARY_HEADER_LEN; const PUS_VERSION: PusVersion = PusVersion::PusC; /// Marker trait for PUS telecommand structures. @@ -234,6 +233,7 @@ pub struct PusTcCreator<'app_data> { sp_header: SpHeader, pub sec_header: PusTcSecondaryHeader, app_data: &'app_data [u8], + has_checksum: bool, } impl<'app_data> PusTcCreator<'app_data> { @@ -249,12 +249,15 @@ impl<'app_data> PusTcCreator<'app_data> { /// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length /// field. If this is not set to true, [Self::update_ccsds_data_len] can be called to set /// the correct value to this field manually + /// * `has_checksum` - A CRC16 checksum will be generated and appended to the end of the + /// packet. #[inline] pub fn new( mut sp_header: SpHeader, sec_header: PusTcSecondaryHeader, app_data: &'app_data [u8], set_ccsds_len: bool, + has_checksum: bool, ) -> Self { sp_header.set_packet_type(PacketType::Tc); sp_header.set_sec_header_flag(); @@ -262,6 +265,7 @@ impl<'app_data> PusTcCreator<'app_data> { sp_header, app_data, sec_header, + has_checksum, }; if set_ccsds_len { pus_tc.update_ccsds_data_len(); @@ -278,12 +282,14 @@ impl<'app_data> PusTcCreator<'app_data> { subservice: u8, app_data: &'app_data [u8], set_ccsds_len: bool, + has_checksum: bool, ) -> Self { Self::new( sph, PusTcSecondaryHeader::new(service, subservice, ACK_ALL, 0), app_data, set_ccsds_len, + has_checksum, ) } @@ -292,8 +298,9 @@ impl<'app_data> PusTcCreator<'app_data> { sp_header: SpHeader, sec_header: PusTcSecondaryHeader, set_ccsds_len: bool, + has_checksum: bool, ) -> Self { - Self::new(sp_header, sec_header, &[], set_ccsds_len) + Self::new(sp_header, sec_header, &[], set_ccsds_len, has_checksum) } #[inline] @@ -367,9 +374,12 @@ impl<'app_data> PusTcCreator<'app_data> { let pus_tc_header = zc::PusTcSecondaryHeader::try_from(self.sec_header).unwrap(); vec.extend_from_slice(pus_tc_header.as_bytes()); vec.extend_from_slice(self.app_data); - let mut digest = CRC_CCITT_FALSE.digest(); - digest.update(&vec[start_idx..start_idx + appended_len - 2]); - vec.extend_from_slice(&digest.finalize().to_be_bytes()); + if self.has_checksum() { + let mut digest = CRC_CCITT_FALSE.digest(); + digest.update(&vec[start_idx..start_idx + appended_len]); + vec.extend_from_slice(&digest.finalize().to_be_bytes()); + appended_len += 2; + } appended_len } @@ -385,13 +395,13 @@ impl<'app_data> PusTcCreator<'app_data> { slice: &mut [u8], ) -> Result { let writer_unfinalized = self.common_write(slice)?; - Ok(writer_unfinalized.finalize_crc_no_table()) + Ok(writer_unfinalized.finalize_checksum_no_table()) } /// Write the raw PUS byte representation to a provided buffer. pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result { let writer_unfinalized = self.common_write(slice)?; - Ok(writer_unfinalized.finalize_no_crc()) + Ok(writer_unfinalized.finalize_no_checksum()) } fn common_write<'a>( @@ -409,6 +419,7 @@ impl<'app_data> PusTcCreator<'app_data> { self.sp_header, self.sec_header, self.app_data.len(), + self.has_checksum, )?; writer_unfinalized .app_data_mut() @@ -420,11 +431,19 @@ impl<'app_data> PusTcCreator<'app_data> { impl WritablePusPacket for PusTcCreator<'_> { #[inline] fn len_written(&self) -> usize { - PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len() + let mut len = PUS_TC_MIN_LEN_WITHOUT_APP_DATA + self.app_data.len(); + if self.has_checksum() { + len += 2; + } + len + } + + fn has_checksum(&self) -> bool { + self.has_checksum } /// Write the raw PUS byte representation to a provided buffer. - fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_no_crc(self, slice)?) } @@ -432,7 +451,7 @@ impl WritablePusPacket for PusTcCreator<'_> { Ok(Self::write_to_bytes(self, slice)?) } - fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_crc_no_table(self, slice)?) } } @@ -496,6 +515,7 @@ pub struct PusTcCreatorWithReservedAppData<'buf> { buf: &'buf mut [u8], app_data_offset: usize, full_len: usize, + has_checksum: bool, } impl<'buf> PusTcCreatorWithReservedAppData<'buf> { @@ -514,10 +534,14 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { mut sp_header: SpHeader, sec_header: PusTcSecondaryHeader, app_data_len: usize, + has_checksum: bool, ) -> Result { sp_header.set_packet_type(PacketType::Tc); sp_header.set_sec_header_flag(); - let len_written = PUS_TC_MIN_LEN_WITHOUT_APP_DATA + app_data_len; + let mut len_written = PUS_TC_MIN_LEN_WITHOUT_APP_DATA + app_data_len; + if has_checksum { + len_written += 2; + } if len_written > buf.len() { return Err(ByteConversionError::ToSliceTooSmall { found: buf.len(), @@ -525,7 +549,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { }); } sp_header.data_len = len_written as u16 - size_of::() as u16 - 1; - Self::write_to_bytes_partially(buf, sp_header, sec_header, app_data_len) + Self::write_to_bytes_partially(buf, sp_header, sec_header, app_data_len, has_checksum) } fn write_to_bytes_partially( @@ -533,6 +557,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { sp_header: SpHeader, sec_header: PusTcSecondaryHeader, app_data_len: usize, + has_checksum: bool, ) -> Result { let mut curr_idx = 0; sp_header.write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?; @@ -545,10 +570,14 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { curr_idx += sec_header_len; let app_data_offset = curr_idx; curr_idx += app_data_len; + if has_checksum { + curr_idx += 2; + } Ok(Self { buf, app_data_offset, - full_len: curr_idx + 2, + full_len: curr_idx, + has_checksum, }) } @@ -560,49 +589,74 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { /// Mutable access to the application data buffer. #[inline] pub fn app_data_mut(&mut self) -> &mut [u8] { - &mut self.buf[self.app_data_offset..self.full_len - 2] + let end_index = if self.has_checksum { + self.full_len - 2 + } else { + self.full_len + }; + &mut self.buf[self.app_data_offset..end_index] } /// Access to the source data buffer. #[inline] pub fn app_data(&self) -> &[u8] { - &self.buf[self.app_data_offset..self.full_len - 2] + let end_index = if self.has_checksum { + self.full_len - 2 + } else { + self.full_len + }; + &self.buf[self.app_data_offset..end_index] } #[inline] pub fn app_data_len(&self) -> usize { - self.full_len - 2 - self.app_data_offset + let mut len = self.full_len - self.app_data_offset; + if self.has_checksum { + len -= 2; + } + len } - /// Finalize the TC packet by calculating and writing the CRC16. + /// Finalize the TC packet by calculating and writing the CRC16 if checksum generation is + /// enabled. /// /// Returns the full packet length. pub fn finalize(self) -> usize { - let mut digest = CRC_CCITT_FALSE.digest(); - digest.update(&self.buf[0..self.full_len - 2]); - self.buf[self.full_len - 2..self.full_len] - .copy_from_slice(&digest.finalize().to_be_bytes()); - self.full_len + let written_len = self.len_written(); + if self.has_checksum { + let mut digest = CRC_CCITT_FALSE.digest(); + digest.update(&self.buf[0..written_len - 2]); + self.buf[self.full_len - 2..written_len] + .copy_from_slice(&digest.finalize().to_be_bytes()); + } + written_len } /// Finalize the TC packet by calculating and writing the CRC16 using a table-less - /// implementation. + /// implementation if checksum genration is enabled. /// /// Returns the full packet length. - pub fn finalize_crc_no_table(self) -> usize { - let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest(); - digest.update(&self.buf[0..self.full_len - 2]); - self.buf[self.full_len - 2..self.full_len] - .copy_from_slice(&digest.finalize().to_be_bytes()); - self.full_len + pub fn finalize_checksum_no_table(self) -> usize { + let written_len = self.len_written(); + if self.has_checksum { + let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest(); + digest.update(&self.buf[0..written_len - 2]); + self.buf[self.full_len - 2..written_len] + .copy_from_slice(&digest.finalize().to_be_bytes()); + } + written_len } - /// Finalize the TC packet without writing the CRC16. + /// Finalize the TC packet without writing the CRC16 checksum. /// - /// Returns the length WITHOUT the CRC16. + /// Returns the length WITHOUT the CRC16 checksum. #[inline] - pub fn finalize_no_crc(self) -> usize { - self.full_len - 2 + pub fn finalize_no_checksum(self) -> usize { + if self.has_checksum { + self.full_len - 2 + } else { + self.full_len + } } } @@ -796,17 +850,17 @@ mod tests { fn base_ping_tc_full_ctor() -> 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, true) + PusTcCreator::new_no_app_data(sph, tc_header, true, true) } fn base_ping_tc_simple_ctor() -> PusTcCreator<'static> { let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); - PusTcCreator::new_simple(sph, 17, 1, &[], true) + PusTcCreator::new_simple(sph, 17, 1, &[], true, true) } fn base_ping_tc_simple_ctor_with_app_data(app_data: &'static [u8]) -> PusTcCreator<'static> { let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); - PusTcCreator::new_simple(sph, 17, 1, app_data, true) + PusTcCreator::new_simple(sph, 17, 1, app_data, true, true) } #[test] @@ -846,8 +900,9 @@ mod tests { fn test_serialization_with_trait_2() { let pus_tc = base_ping_tc_simple_ctor(); let mut test_buf: [u8; 32] = [0; 32]; - let size = WritablePusPacket::write_to_bytes_crc_no_table(&pus_tc, test_buf.as_mut_slice()) - .expect("Error writing TC to buffer"); + let size = + WritablePusPacket::write_to_bytes_checksum_no_table(&pus_tc, test_buf.as_mut_slice()) + .expect("Error writing TC to buffer"); assert_eq!(size, 13); assert_eq!( pus_tc.opt_crc16().unwrap(), @@ -885,7 +940,7 @@ mod tests { fn test_serialization_no_crc_with_trait() { let pus_tc = base_ping_tc_simple_ctor(); let mut test_buf: [u8; 32] = [0; 32]; - let size = WritablePusPacket::write_to_bytes_no_crc(&pus_tc, test_buf.as_mut_slice()) + let size = WritablePusPacket::write_to_bytes_no_checksum(&pus_tc, test_buf.as_mut_slice()) .expect("error writing tc to buffer"); assert_eq!(size, 11); assert_eq!(test_buf[11], 0); @@ -915,7 +970,7 @@ mod tests { let tc_header = PusTcSecondaryHeader::new_simple(17, 1); let mut test_buf: [u8; 32] = [0; 32]; let mut pus_tc = - PusTcCreatorWithReservedAppData::new(&mut test_buf, sph, tc_header, 0).unwrap(); + PusTcCreatorWithReservedAppData::new(&mut test_buf, sph, tc_header, 0, true).unwrap(); assert_eq!(pus_tc.len_written(), 13); assert_eq!(pus_tc.app_data_len(), 0); assert_eq!(pus_tc.app_data(), &[]); @@ -965,7 +1020,7 @@ mod tests { #[test] fn test_update_func() { let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); - let mut tc = PusTcCreator::new_simple(sph, 17, 1, &[], false); + let mut tc = PusTcCreator::new_simple(sph, 17, 1, &[], false, true); assert_eq!(tc.data_len(), 0); tc.update_ccsds_data_len(); assert_eq!(tc.data_len(), 6); diff --git a/src/ecss/tc_pus_a.rs b/src/ecss/tc_pus_a.rs index c6d0963..3d0537c 100644 --- a/src/ecss/tc_pus_a.rs +++ b/src/ecss/tc_pus_a.rs @@ -469,8 +469,13 @@ impl WritablePusPacket for PusTcCreator<'_> { CCSDS_HEADER_LEN + self.sec_header.written_len() + self.app_data.len() + 2 } + /// Currently, checksum is always added. + fn has_checksum(&self) -> bool { + true + } + /// Write the raw PUS byte representation to a provided buffer. - fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_no_crc(self, slice)?) } @@ -478,7 +483,7 @@ impl WritablePusPacket for PusTcCreator<'_> { Ok(Self::write_to_bytes(self, slice)?) } - fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_crc_no_table(self, slice)?) } } @@ -898,8 +903,9 @@ mod tests { fn test_serialization_with_trait_2() { let pus_tc = base_ping_tc_simple_ctor(); let mut test_buf: [u8; 32] = [0; 32]; - let size = WritablePusPacket::write_to_bytes_crc_no_table(&pus_tc, test_buf.as_mut_slice()) - .expect("Error writing TC to buffer"); + let size = + WritablePusPacket::write_to_bytes_checksum_no_table(&pus_tc, test_buf.as_mut_slice()) + .expect("Error writing TC to buffer"); assert_eq!(size, 11); assert_eq!( pus_tc.opt_crc16().unwrap(), @@ -937,7 +943,7 @@ mod tests { fn test_serialization_no_crc_with_trait() { let pus_tc = base_ping_tc_simple_ctor(); let mut test_buf: [u8; 32] = [0; 32]; - let size = WritablePusPacket::write_to_bytes_no_crc(&pus_tc, test_buf.as_mut_slice()) + let size = WritablePusPacket::write_to_bytes_no_checksum(&pus_tc, test_buf.as_mut_slice()) .expect("error writing tc to buffer"); assert_eq!(size, 9); assert_eq!(test_buf[9], 0); diff --git a/src/ecss/tm.rs b/src/ecss/tm.rs index a6d531d..84acd73 100644 --- a/src/ecss/tm.rs +++ b/src/ecss/tm.rs @@ -463,8 +463,14 @@ impl WritablePusPacket for PusTmCreator<'_, '_> { + self.sec_header.timestamp.len() + self.source_data.len() } + + /// Currently, checksum is always added. + fn has_checksum(&self) -> bool { + true + } + /// Write the raw PUS byte representation to a provided buffer. - fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_no_crc(self, slice)?) } @@ -472,7 +478,7 @@ impl WritablePusPacket for PusTmCreator<'_, '_> { Ok(Self::write_to_bytes(self, slice)?) } - fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_crc_no_table(self, slice)?) } } diff --git a/src/ecss/tm_pus_a.rs b/src/ecss/tm_pus_a.rs index f20d36c..2ada85a 100644 --- a/src/ecss/tm_pus_a.rs +++ b/src/ecss/tm_pus_a.rs @@ -508,8 +508,14 @@ impl WritablePusPacket for PusTmCreator<'_, '_> { fn len_written(&self) -> usize { CCSDS_HEADER_LEN + self.sec_header.written_len() + self.source_data.len() + 2 } + + /// Currently, checksum is always added. + fn has_checksum(&self) -> bool { + true + } + /// Write the raw PUS byte representation to a provided buffer. - fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_no_crc(self, slice)?) } @@ -517,7 +523,7 @@ impl WritablePusPacket for PusTmCreator<'_, '_> { Ok(Self::write_to_bytes(self, slice)?) } - fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result { + fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result { Ok(Self::write_to_bytes_crc_no_table(self, slice)?) } }