From 374f39f13b4baf37fb89293513f773b308bf9251 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Fri, 31 Oct 2025 15:59:41 +0100 Subject: [PATCH] add option to ignore checksum for CCSDS --- src/lib.rs | 145 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 107 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1124c61..fbb8599 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,8 +104,10 @@ pub const MAX_SEQ_COUNT: u14 = u14::MAX; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] pub enum ChecksumType { - /// Default CRC16-CCITT checksum. - Crc16CcittFalse, + /// Check the default CRC16-CCITT checksum. + WithCrc16, + /// Packet has a CRC16 which should be ignored. + WithCrc16Ignored, } /// Generic error type when converting to and from raw byte slices. @@ -213,7 +215,8 @@ pub const fn ccsds_packet_len_for_user_data_len( return Some(7); } let checksum_len = match checksum { - Some(ChecksumType::Crc16CcittFalse) => 2, + Some(ChecksumType::WithCrc16) => 2, + Some(ChecksumType::WithCrc16Ignored) => 2, None => 0, }; let len = data_len @@ -230,7 +233,7 @@ pub const fn ccsds_packet_len_for_user_data_len( /// Returns [None] if the packet length exceeds the maximum allowed size [u16::MAX]. #[inline] pub fn ccsds_packet_len_for_user_data_len_with_checksum(data_len: usize) -> Option { - ccsds_packet_len_for_user_data_len(data_len, Some(ChecksumType::Crc16CcittFalse)) + ccsds_packet_len_for_user_data_len(data_len, Some(ChecksumType::WithCrc16)) } /// Abstraction for the CCSDS Packet ID, which forms the last thirteen bits @@ -879,7 +882,7 @@ impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { /// checksum. #[inline] pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option { - ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::Crc16CcittFalse)) + ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::WithCrc16)) } /// Generic constructor. @@ -892,7 +895,9 @@ impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { ) -> Result { let full_packet_len = match checksum { Some(crc_type) => match crc_type { - ChecksumType::Crc16CcittFalse => CCSDS_HEADER_LEN + packet_data_len + 2, + ChecksumType::WithCrc16 | ChecksumType::WithCrc16Ignored => { + CCSDS_HEADER_LEN + packet_data_len + 2 + } }, None => { // Special case: At least one byte of user data is required. @@ -935,7 +940,7 @@ impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { packet_type, payload_len, buf, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -950,7 +955,7 @@ impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { PacketType::Tm, payload_len, buf, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -966,7 +971,7 @@ impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { PacketType::Tc, payload_len, buf, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } } @@ -1001,7 +1006,9 @@ impl CcsdsPacketCreatorWithReservedData<'_> { pub fn packet_data_mut(&mut self) -> &mut [u8] { let len = self.packet_len(); match self.checksum { - Some(ChecksumType::Crc16CcittFalse) => &mut self.buf[CCSDS_HEADER_LEN..len - 2], + Some(ChecksumType::WithCrc16) | Some(ChecksumType::WithCrc16Ignored) => { + &mut self.buf[CCSDS_HEADER_LEN..len - 2] + } None => &mut self.buf[CCSDS_HEADER_LEN..len], } } @@ -1011,7 +1018,9 @@ impl CcsdsPacketCreatorWithReservedData<'_> { pub fn packet_data(&mut self) -> &[u8] { let len = self.packet_len(); match self.checksum { - Some(ChecksumType::Crc16CcittFalse) => &self.buf[CCSDS_HEADER_LEN..len - 2], + Some(ChecksumType::WithCrc16) | Some(ChecksumType::WithCrc16Ignored) => { + &self.buf[CCSDS_HEADER_LEN..len - 2] + } None => &self.buf[CCSDS_HEADER_LEN..len], } } @@ -1026,11 +1035,11 @@ impl CcsdsPacketCreatorWithReservedData<'_> { .unwrap(); let len = self.packet_len(); match self.checksum { - Some(ChecksumType::Crc16CcittFalse) => { + Some(ChecksumType::WithCrc16) => { let crc16 = CRC_CCITT_FALSE.checksum(&self.buf[0..len - 2]); self.buf[len - 2..len].copy_from_slice(&crc16.to_be_bytes()); } - None => (), + None | Some(ChecksumType::WithCrc16Ignored) => (), }; len } @@ -1153,13 +1162,15 @@ impl CcsdsPacketCreatorCommon { ) -> Result { let sp_data_len = (packet_data_len + match checksum { - Some(ChecksumType::Crc16CcittFalse) => 2, + Some(ChecksumType::WithCrc16) | Some(ChecksumType::WithCrc16Ignored) => 2, None => 0, } - 1) as u16; let full_packet_len = match checksum { Some(crc_type) => match crc_type { - ChecksumType::Crc16CcittFalse => CCSDS_HEADER_LEN + packet_data_len + 2, + ChecksumType::WithCrc16 | ChecksumType::WithCrc16Ignored => { + CCSDS_HEADER_LEN + packet_data_len + 2 + } }, None => { // Special case: At least one byte of user data is required. @@ -1207,11 +1218,11 @@ impl CcsdsPacketCreatorCommon { .write_to_be_bytes(&mut buf[0..CCSDS_HEADER_LEN])?; buf[CCSDS_HEADER_LEN..CCSDS_HEADER_LEN + packet_data.len()].copy_from_slice(packet_data); match self.checksum { - Some(ChecksumType::Crc16CcittFalse) => { + Some(ChecksumType::WithCrc16) => { let crc16 = CRC_CCITT_FALSE.checksum(&buf[0..len_written - 2]); buf[len_written - 2..len_written].copy_from_slice(&crc16.to_be_bytes()); } - None => (), + None | Some(ChecksumType::WithCrc16Ignored) => (), }; Ok(len_written) } @@ -1245,7 +1256,7 @@ impl<'app_data> CcsdsPacketCreator<'app_data> { /// data length, assuming there is a CRC16 appended at the packet. #[inline] pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option { - ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::Crc16CcittFalse)) + ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::WithCrc16)) } /// Generic constructor. @@ -1273,7 +1284,7 @@ impl<'app_data> CcsdsPacketCreator<'app_data> { sp_header, packet_type, app_data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -1286,7 +1297,7 @@ impl<'app_data> CcsdsPacketCreator<'app_data> { sp_header, PacketType::Tm, app_data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -1299,7 +1310,7 @@ impl<'app_data> CcsdsPacketCreator<'app_data> { sp_header, PacketType::Tc, app_data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } } @@ -1378,7 +1389,7 @@ impl CcsdsPacketCreatorOwned { /// data length, assuming there is a CRC16 appended at the packet. #[inline] pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option { - ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::Crc16CcittFalse)) + ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::WithCrc16)) } /// Generic constructor. @@ -1406,7 +1417,7 @@ impl CcsdsPacketCreatorOwned { sp_header, packet_type, packet_data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -1419,7 +1430,7 @@ impl CcsdsPacketCreatorOwned { sp_header, PacketType::Tm, packet_data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -1432,7 +1443,7 @@ impl CcsdsPacketCreatorOwned { sp_header, PacketType::Tc, packet_data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) } @@ -1523,7 +1534,7 @@ impl<'buf> CcsdsPacketReader<'buf> { pub fn new_with_checksum( buf: &'buf [u8], ) -> Result, CcsdsPacketReadError> { - Self::new(buf, Some(ChecksumType::Crc16CcittFalse)) + Self::new(buf, Some(ChecksumType::WithCrc16)) } /// Generic constructor. @@ -1540,12 +1551,15 @@ impl<'buf> CcsdsPacketReader<'buf> { .into()); } let user_data = match checksum { - Some(ChecksumType::Crc16CcittFalse) => { + Some(ChecksumType::WithCrc16) => { if CRC_CCITT_FALSE.checksum(&buf[0..sp_header.packet_len()]) != 0 { return Err(CcsdsPacketReadError::CrcError); } &buf[CCSDS_HEADER_LEN..sp_header.packet_len() - 2] } + Some(ChecksumType::WithCrc16Ignored) => { + &buf[CCSDS_HEADER_LEN..sp_header.packet_len() - 2] + } None => &buf[CCSDS_HEADER_LEN..sp_header.packet_len()], }; Ok(Self { @@ -1987,7 +2001,7 @@ pub(crate) mod tests { // Special case: One dummy byte is required. assert_eq!(ccsds_packet_len_for_user_data_len(0, None).unwrap(), 7); assert_eq!( - ccsds_packet_len_for_user_data_len(1, Some(ChecksumType::Crc16CcittFalse)).unwrap(), + ccsds_packet_len_for_user_data_len(1, Some(ChecksumType::WithCrc16)).unwrap(), 9 ); assert_eq!( @@ -2009,13 +2023,13 @@ pub(crate) mod tests { // 2 less bytes available because of the checksum. assert!(ccsds_packet_len_for_user_data_len( u16::MAX as usize - 1, - Some(ChecksumType::Crc16CcittFalse) + Some(ChecksumType::WithCrc16) ) .is_some()); // This is too much. assert!(ccsds_packet_len_for_user_data_len( u16::MAX as usize, - Some(ChecksumType::Crc16CcittFalse) + Some(ChecksumType::WithCrc16) ) .is_none()); } @@ -2030,7 +2044,7 @@ pub(crate) mod tests { packet_type, 4, &mut buf, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap(); assert_eq!(packet_creator.packet_len(), 12); @@ -2118,7 +2132,7 @@ pub(crate) mod tests { PacketType::Tc, 4, &mut buf, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap(); packet_creator.packet_data_mut().copy_from_slice(&data); @@ -2162,6 +2176,29 @@ pub(crate) mod tests { assert_eq!(reader.packet_len(), 7); } + #[test] + fn test_ccsds_creator_creation_ignored_checksum() { + let mut buf: [u8; 32] = [0; 32]; + let data = [1, 2, 3, 4, 5]; + let mut packet_creator = CcsdsPacketCreatorWithReservedData::new( + SpacePacketHeader::new_from_apid(u11::new(0x1)), + PacketType::Tc, + data.len(), + &mut buf, + Some(ChecksumType::WithCrc16Ignored), + ) + .unwrap(); + packet_creator.packet_data_mut().copy_from_slice(&data); + // Special case. + assert_eq!(packet_creator.packet_len(), 13); + packet_creator.finish(); + let reader = + CcsdsPacketReader::new(&buf[0..13], Some(ChecksumType::WithCrc16Ignored)).unwrap(); + // Enforced 1 byte packet length. + assert_eq!(reader.packet_data(), &data); + assert_eq!(reader.packet_len(), 13); + } + #[test] fn test_ccsds_creator_creation_buf_too_small() { let mut buf: [u8; 8] = [0; 8]; @@ -2288,7 +2325,7 @@ pub(crate) mod tests { sp_header, PacketType::Tc, &data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap() .to_vec(), @@ -2296,7 +2333,7 @@ pub(crate) mod tests { sp_header, PacketType::Tc, &data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap() .to_vec(), @@ -2347,6 +2384,24 @@ pub(crate) mod tests { generic_ccsds_creator_test(true, true); } + #[test] + fn test_ccsds_creator_ignored_checksum() { + let data = [1, 2, 3, 4]; + let mut sp_header = SpacePacketHeader::new_from_apid(u11::new(0x1)); + sp_header.set_packet_type(PacketType::Tc); + let packet_raw = CcsdsPacketCreatorOwned::new( + sp_header, + PacketType::Tc, + &data, + Some(ChecksumType::WithCrc16Ignored), + ) + .unwrap() + .to_vec(); + let reader = + CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16Ignored)).unwrap(); + assert_eq!(reader.packet_data(), data); + } + fn generic_test_creator(packet_raw: &[u8], sp_header: &SpHeader, packet_type: PacketType) { assert_eq!(CRC_CCITT_FALSE.checksum(packet_raw), 0); let sp_header_from_raw = SpacePacketHeader::from_be_bytes( @@ -2445,7 +2500,7 @@ pub(crate) mod tests { SpacePacketHeader::new_from_apid(u11::new(0x1)), packet_type, &data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap(); let sp_header = packet_creator.sp_header(); @@ -2460,7 +2515,7 @@ pub(crate) mod tests { SpacePacketHeader::new_from_apid(u11::new(0x1)), packet_type, &data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap(); let sp_header = packet_creator.sp_header(); @@ -2475,7 +2530,7 @@ pub(crate) mod tests { SpacePacketHeader::new_from_apid(u11::new(0x1)), packet_type, &data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap(); let sp_header = packet_creator.sp_header(); @@ -2490,7 +2545,7 @@ pub(crate) mod tests { SpacePacketHeader::new_from_apid(u11::new(0x1)), packet_type, &data, - Some(ChecksumType::Crc16CcittFalse), + Some(ChecksumType::WithCrc16), ) .unwrap(); let sp_header = packet_creator.sp_header(); @@ -2621,6 +2676,20 @@ pub(crate) mod tests { assert!(reader_error.is_err()); assert_eq!(reader_error.unwrap_err(), CcsdsPacketReadError::CrcError); } + #[test] + fn test_ccsds_checksum_ignored() { + let data = [1, 2, 3, 4]; + let packet_creator = CcsdsPacketCreator::new_tc_with_checksum( + SpacePacketHeader::new_from_apid(u11::new(0x1)), + &data, + ) + .unwrap(); + let mut packet_raw = packet_creator.to_vec(); + *packet_raw.last_mut().unwrap() = 0; + let reader = + CcsdsPacketReader::new(&packet_raw, Some(ChecksumType::WithCrc16Ignored)).unwrap(); + assert_eq!(reader.packet_data(), data); + } #[test] fn sp_header_to_buf_too_small() { -- 2.43.0