Compare commits
2 Commits
main
...
msp430-twe
Author | SHA1 | Date | |
---|---|---|---|
418af9caf9 | |||
30d17ea805 |
15
CHANGELOG.md
15
CHANGELOG.md
@ -8,6 +8,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Moved CRC constants/implementations to dedicated `crc` module.
|
||||||
|
- `crc::CRC_CCITT_FALSE_NO_TABLE` and `crc::CRC_CCITT_FALSE_BIG_TABLE` variants.
|
||||||
|
- Renamed `PusPacket::crc16` to `PusPacket::opt_crc16`.
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- `WritablePusPacket::write_to_bytes_crc_no_table` and `WritablePusPacket::write_to_bytes_no_crc`
|
||||||
|
variants.
|
||||||
|
- `PusTmReader::new_crc_no_table` and `PusTcReader::new_crc_no_table` variants.
|
||||||
|
- `crc16` methods for PUS TM and PUS TC reader.
|
||||||
|
- PUS TM and PUS TC reader now return the reader instance directly instead of a tuple of the reader
|
||||||
|
and the read size. The instance `total_len` method can be used to retrieve the read lenght.
|
||||||
|
|
||||||
# [v0.13.1] 2025-03-21
|
# [v0.13.1] 2025-03-21
|
||||||
|
|
||||||
- Bugfix due to operator precendence for `PusTcSecondaryHeader::pus_version`,
|
- Bugfix due to operator precendence for `PusTcSecondaryHeader::pus_version`,
|
||||||
|
@ -13,7 +13,7 @@ categories = ["aerospace", "aerospace::space-protocols", "no-std", "hardware-sup
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crc = "3"
|
crc = { version = "3", git = "https://github.com/us-irs/crc-rs.git", branch = "opt-crc128-crc64", default-features = false }
|
||||||
delegate = ">=0.8, <=0.13"
|
delegate = ">=0.8, <=0.13"
|
||||||
paste = "1"
|
paste = "1"
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! CFDP Packet Data Unit (PDU) support.
|
//! CFDP Packet Data Unit (PDU) support.
|
||||||
use crate::cfdp::*;
|
use crate::cfdp::*;
|
||||||
|
use crate::crc::CRC_CCITT_FALSE;
|
||||||
use crate::util::{UnsignedByteField, UnsignedByteFieldU8, UnsignedEnum};
|
use crate::util::{UnsignedByteField, UnsignedByteFieldU8, UnsignedEnum};
|
||||||
use crate::ByteConversionError;
|
use crate::ByteConversionError;
|
||||||
use crate::CRC_CCITT_FALSE;
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
11
src/crc.rs
Normal file
11
src/crc.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/// CRC algorithm used by the PUS standard, the CCSDS TC standard and the CFDP standard, using
|
||||||
|
/// a [crc::NoTable] as the CRC implementation.
|
||||||
|
pub const CRC_CCITT_FALSE_NO_TABLE: crc::Crc<u16, crc::NoTable> =
|
||||||
|
crc::Crc::<u16, crc::NoTable>::new(&crc::CRC_16_IBM_3740);
|
||||||
|
/// CRC algorithm used by the PUS standard, the CCSDS TC standard and the CFDP standard, using
|
||||||
|
/// [crc::Table<1>] as the CRC implementation.
|
||||||
|
pub const CRC_CCITT_FALSE: crc::Crc<u16> = crc::Crc::<u16>::new(&crc::CRC_16_IBM_3740);
|
||||||
|
/// CRC algorithm used by the PUS standard, the CCSDS TC standard and the CFDP standard, using
|
||||||
|
/// a [crc::Table<16>] large table as the CRC implementation.
|
||||||
|
pub const CRC_CCITT_FALSE_BIG_TABLE: crc::Crc<u16, crc::Table<16>> =
|
||||||
|
crc::Crc::<u16, crc::Table<16>>::new(&crc::CRC_16_IBM_3740);
|
@ -3,7 +3,10 @@
|
|||||||
//!
|
//!
|
||||||
//! You can find the PUS telecommand types in the [tc] module and the the PUS telemetry
|
//! You can find the PUS telecommand types in the [tc] module and the the PUS telemetry
|
||||||
//! types inside the [tm] module.
|
//! types inside the [tm] module.
|
||||||
use crate::{ByteConversionError, CcsdsPacket, CRC_CCITT_FALSE};
|
use crate::{
|
||||||
|
crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE},
|
||||||
|
ByteConversionError, CcsdsPacket,
|
||||||
|
};
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
@ -170,7 +173,7 @@ 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 crc16(&self) -> Option<u16>;
|
fn opt_crc16(&self) -> Option<u16>;
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
@ -207,7 +210,7 @@ pub(crate) fn user_data_from_raw(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn verify_crc16_ccitt_false_from_raw_to_pus_error(
|
pub fn verify_crc16_ccitt_false_from_raw_to_pus_error(
|
||||||
raw_data: &[u8],
|
raw_data: &[u8],
|
||||||
crc16: u16,
|
crc16: u16,
|
||||||
) -> Result<(), PusError> {
|
) -> Result<(), PusError> {
|
||||||
@ -216,6 +219,15 @@ pub(crate) fn verify_crc16_ccitt_false_from_raw_to_pus_error(
|
|||||||
.ok_or(PusError::ChecksumFailure(crc16))
|
.ok_or(PusError::ChecksumFailure(crc16))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(
|
||||||
|
raw_data: &[u8],
|
||||||
|
crc16: u16,
|
||||||
|
) -> Result<(), PusError> {
|
||||||
|
verify_crc16_ccitt_false_from_raw_no_table(raw_data)
|
||||||
|
.then_some(())
|
||||||
|
.ok_or(PusError::ChecksumFailure(crc16))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn verify_crc16_ccitt_false_from_raw(raw_data: &[u8]) -> bool {
|
pub(crate) fn verify_crc16_ccitt_false_from_raw(raw_data: &[u8]) -> bool {
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
digest.update(raw_data);
|
digest.update(raw_data);
|
||||||
@ -225,6 +237,15 @@ pub(crate) fn verify_crc16_ccitt_false_from_raw(raw_data: &[u8]) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn verify_crc16_ccitt_false_from_raw_no_table(raw_data: &[u8]) -> bool {
|
||||||
|
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
||||||
|
digest.update(raw_data);
|
||||||
|
if digest.finalize() == 0 {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! ccsds_impl {
|
macro_rules! ccsds_impl {
|
||||||
() => {
|
() => {
|
||||||
delegate!(to self.sp_header {
|
delegate!(to self.sp_header {
|
||||||
@ -349,7 +370,34 @@ generic_ecss_enum_typedefs_and_from_impls! {
|
|||||||
/// on the serialization of those packets.
|
/// on the serialization of those packets.
|
||||||
pub trait WritablePusPacket {
|
pub trait WritablePusPacket {
|
||||||
fn len_written(&self) -> usize;
|
fn len_written(&self) -> usize;
|
||||||
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError>;
|
|
||||||
|
/// 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<usize, PusError>;
|
||||||
|
|
||||||
|
/// First uses [Self::write_to_bytes_no_crc] to write the packet to the given slice and then
|
||||||
|
/// uses the [CRC_CCITT_FALS] to calculate the CRC and write it to the slice.
|
||||||
|
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
|
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;
|
||||||
|
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<usize, PusError> {
|
||||||
|
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;
|
||||||
|
Ok(curr_idx)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
fn to_vec(&self) -> Result<Vec<u8>, PusError> {
|
fn to_vec(&self) -> Result<Vec<u8>, PusError> {
|
||||||
// This is the correct way to do this. See
|
// This is the correct way to do this. See
|
||||||
|
110
src/ecss/tc.rs
110
src/ecss/tc.rs
@ -33,13 +33,14 @@
|
|||||||
//! assert_eq!(pus_tc.subservice(), 1);
|
//! assert_eq!(pus_tc.subservice(), 1);
|
||||||
//! 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::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, CrcType, PusError, PusPacket, PusVersion,
|
verify_crc16_ccitt_false_from_raw_to_pus_error, CrcType, PusError, PusPacket, PusVersion,
|
||||||
WritablePusPacket,
|
WritablePusPacket,
|
||||||
};
|
};
|
||||||
|
use crate::SpHeader;
|
||||||
use crate::{ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, CCSDS_HEADER_LEN};
|
use crate::{ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, CCSDS_HEADER_LEN};
|
||||||
use crate::{SpHeader, CRC_CCITT_FALSE};
|
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use delegate::delegate;
|
use delegate::delegate;
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
@ -50,6 +51,8 @@ use zerocopy::{FromBytes, IntoBytes};
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use super::verify_crc16_ccitt_false_from_raw_to_pus_error_no_table;
|
||||||
|
|
||||||
/// PUS C secondary header length is fixed
|
/// PUS C secondary header length is fixed
|
||||||
pub const PUC_TC_SECONDARY_HEADER_LEN: usize = size_of::<zc::PusTcSecondaryHeader>();
|
pub const PUC_TC_SECONDARY_HEADER_LEN: usize = size_of::<zc::PusTcSecondaryHeader>();
|
||||||
pub const PUS_TC_MIN_LEN_WITHOUT_APP_DATA: usize =
|
pub const PUS_TC_MIN_LEN_WITHOUT_APP_DATA: usize =
|
||||||
@ -342,6 +345,17 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
digest.finalize()
|
digest.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This function calculates and returns the CRC16 for the current packet.
|
||||||
|
pub fn calc_own_crc16_no_table(&self) -> u16 {
|
||||||
|
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
||||||
|
let sph_zc = crate::zc::SpHeader::from(self.sp_header);
|
||||||
|
digest.update(sph_zc.as_bytes());
|
||||||
|
let pus_tc_header = zc::PusTcSecondaryHeader::try_from(self.sec_header).unwrap();
|
||||||
|
digest.update(pus_tc_header.as_bytes());
|
||||||
|
digest.update(self.app_data);
|
||||||
|
digest.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
#[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);
|
||||||
@ -367,7 +381,7 @@ impl WritablePusPacket for PusTcCreator<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Write the raw PUS byte representation to a provided buffer.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
let mut curr_idx = 0;
|
let mut curr_idx = 0;
|
||||||
let tc_header_len = size_of::<zc::PusTcSecondaryHeader>();
|
let tc_header_len = size_of::<zc::PusTcSecondaryHeader>();
|
||||||
let total_size = self.len_written();
|
let total_size = self.len_written();
|
||||||
@ -388,10 +402,6 @@ impl WritablePusPacket for PusTcCreator<'_> {
|
|||||||
curr_idx += tc_header_len;
|
curr_idx += tc_header_len;
|
||||||
slice[curr_idx..curr_idx + self.app_data.len()].copy_from_slice(self.app_data);
|
slice[curr_idx..curr_idx + self.app_data.len()].copy_from_slice(self.app_data);
|
||||||
curr_idx += self.app_data.len();
|
curr_idx += self.app_data.len();
|
||||||
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)
|
Ok(curr_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,7 +426,7 @@ impl PusPacket for PusTcCreator<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn crc16(&self) -> Option<u16> {
|
fn opt_crc16(&self) -> Option<u16> {
|
||||||
Some(self.calc_own_crc16())
|
Some(self.calc_own_crc16())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,7 +475,22 @@ 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. On success, it returns a tuple containing
|
||||||
/// the instance and the found byte length of the packet. This function also performs a CRC
|
/// the instance and the found byte length of the packet. This function also performs a CRC
|
||||||
/// check and will return an appropriate [PusError] if the check fails.
|
/// check and will return an appropriate [PusError] if the check fails.
|
||||||
pub fn new(slice: &'raw_data [u8]) -> Result<(Self, usize), PusError> {
|
pub fn new(slice: &'raw_data [u8]) -> Result<Self, PusError> {
|
||||||
|
let pus_tc = Self::new_no_crc_check(slice)?;
|
||||||
|
verify_crc16_ccitt_false_from_raw_to_pus_error(pus_tc.raw_data(), pus_tc.crc16())?;
|
||||||
|
Ok(pus_tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Similar to [PusTcReader::new], but uses a table-less CRC16 algorithm which can reduce
|
||||||
|
/// binary size and memory usage.
|
||||||
|
pub fn new_crc_no_table(slice: &'raw_data [u8]) -> Result<Self, PusError> {
|
||||||
|
let pus_tc = Self::new_no_crc_check(slice)?;
|
||||||
|
verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(pus_tc.raw_data(), pus_tc.crc16())?;
|
||||||
|
Ok(pus_tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new instance without performing a CRC check.
|
||||||
|
pub fn new_no_crc_check(slice: &'raw_data [u8]) -> 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 {
|
||||||
@ -498,15 +523,13 @@ 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 pus_tc = 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)?,
|
||||||
crc16: crc_from_raw_data(raw_data)?,
|
crc16: crc_from_raw_data(raw_data)?,
|
||||||
};
|
})
|
||||||
verify_crc16_ccitt_false_from_raw_to_pus_error(raw_data, pus_tc.crc16)?;
|
|
||||||
Ok((pus_tc, total_len))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -528,6 +551,11 @@ impl<'raw_data> PusTcReader<'raw_data> {
|
|||||||
pub fn sp_header(&self) -> &SpHeader {
|
pub fn sp_header(&self) -> &SpHeader {
|
||||||
&self.sp_header
|
&self.sp_header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn crc16(&self) -> u16 {
|
||||||
|
self.crc16
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for PusTcReader<'_> {
|
impl PartialEq for PusTcReader<'_> {
|
||||||
@ -557,7 +585,7 @@ impl PusPacket for PusTcReader<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn crc16(&self) -> Option<u16> {
|
fn opt_crc16(&self) -> Option<u16> {
|
||||||
Some(self.crc16)
|
Some(self.crc16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -640,7 +668,21 @@ 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.crc16().unwrap(),
|
pus_tc.opt_crc16().unwrap(),
|
||||||
|
u16::from_be_bytes(test_buf[size - 2..size].try_into().unwrap())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization_crc_no_table() {
|
||||||
|
let pus_tc = base_ping_tc_simple_ctor();
|
||||||
|
let mut test_buf: [u8; 32] = [0; 32];
|
||||||
|
let size = pus_tc
|
||||||
|
.write_to_bytes_crc_no_table(test_buf.as_mut_slice())
|
||||||
|
.expect("Error writing TC to buffer");
|
||||||
|
assert_eq!(size, 13);
|
||||||
|
assert_eq!(
|
||||||
|
pus_tc.opt_crc16().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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -653,9 +695,27 @@ 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, size) =
|
let tc_from_raw =
|
||||||
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
||||||
|
assert_eq!(tc_from_raw.total_len(), 13);
|
||||||
|
verify_test_tc_with_reader(&tc_from_raw, false, 13);
|
||||||
|
assert!(tc_from_raw.user_data().is_empty());
|
||||||
|
verify_test_tc_raw(&test_buf);
|
||||||
|
verify_crc_no_app_data(&test_buf);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialization_no_table() {
|
||||||
|
let pus_tc = base_ping_tc_simple_ctor();
|
||||||
|
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, 13);
|
assert_eq!(size, 13);
|
||||||
|
let tc_from_raw =
|
||||||
|
PusTcReader::new_crc_no_table(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
||||||
|
assert_eq!(tc_from_raw.total_len(), 13);
|
||||||
verify_test_tc_with_reader(&tc_from_raw, false, 13);
|
verify_test_tc_with_reader(&tc_from_raw, false, 13);
|
||||||
assert!(tc_from_raw.user_data().is_empty());
|
assert!(tc_from_raw.user_data().is_empty());
|
||||||
verify_test_tc_raw(&test_buf);
|
verify_test_tc_raw(&test_buf);
|
||||||
@ -667,9 +727,9 @@ mod tests {
|
|||||||
let pus_tc = base_ping_tc_simple_ctor();
|
let pus_tc = base_ping_tc_simple_ctor();
|
||||||
let tc_vec = pus_tc.to_vec().expect("Error writing TC to buffer");
|
let tc_vec = pus_tc.to_vec().expect("Error writing TC to buffer");
|
||||||
assert_eq!(tc_vec.len(), 13);
|
assert_eq!(tc_vec.len(), 13);
|
||||||
let (tc_from_raw, size) = PusTcReader::new(tc_vec.as_slice())
|
let tc_from_raw = PusTcReader::new(tc_vec.as_slice())
|
||||||
.expect("Creating PUS TC struct from raw buffer failed");
|
.expect("Creating PUS TC struct from raw buffer failed");
|
||||||
assert_eq!(size, 13);
|
assert_eq!(tc_from_raw.total_len(), 13);
|
||||||
verify_test_tc_with_reader(&tc_from_raw, false, 13);
|
verify_test_tc_with_reader(&tc_from_raw, false, 13);
|
||||||
assert!(tc_from_raw.user_data().is_empty());
|
assert!(tc_from_raw.user_data().is_empty());
|
||||||
verify_test_tc_raw(&tc_vec);
|
verify_test_tc_raw(&tc_vec);
|
||||||
@ -692,15 +752,15 @@ 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, 16);
|
assert_eq!(size, 16);
|
||||||
let (tc_from_raw, size) =
|
let tc_from_raw =
|
||||||
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
||||||
assert_eq!(size, 16);
|
assert_eq!(tc_from_raw.total_len(), 16);
|
||||||
verify_test_tc_with_reader(&tc_from_raw, true, 16);
|
verify_test_tc_with_reader(&tc_from_raw, true, 16);
|
||||||
let user_data = tc_from_raw.user_data();
|
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.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.crc16().unwrap(),
|
tc_from_raw.opt_crc16().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);
|
||||||
@ -715,9 +775,9 @@ mod tests {
|
|||||||
pus_tc
|
pus_tc
|
||||||
.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");
|
||||||
let (tc_from_raw_0, _) =
|
let tc_from_raw_0 =
|
||||||
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
||||||
let (tc_from_raw_1, _) =
|
let tc_from_raw_1 =
|
||||||
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
PusTcReader::new(&test_buf).expect("Creating PUS TC struct from raw buffer failed");
|
||||||
assert_eq!(tc_from_raw_0, tc_from_raw_1);
|
assert_eq!(tc_from_raw_0, tc_from_raw_1);
|
||||||
}
|
}
|
||||||
@ -869,7 +929,7 @@ mod tests {
|
|||||||
assert_eq!(*tc.sp_header(), comp_header);
|
assert_eq!(*tc.sp_header(), comp_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_test_tc_generic(tc: &(impl CcsdsPacket + PusPacket + GenericPusTcSecondaryHeader)) {
|
fn verify_test_tc_generic(tc: &(impl PusPacket + GenericPusTcSecondaryHeader)) {
|
||||||
assert_eq!(PusPacket::service(tc), 17);
|
assert_eq!(PusPacket::service(tc), 17);
|
||||||
assert_eq!(GenericPusTcSecondaryHeader::service(tc), 17);
|
assert_eq!(GenericPusTcSecondaryHeader::service(tc), 17);
|
||||||
assert_eq!(PusPacket::subservice(tc), 1);
|
assert_eq!(PusPacket::subservice(tc), 1);
|
||||||
@ -933,8 +993,8 @@ mod tests {
|
|||||||
let pus_tc = base_ping_tc_simple_ctor();
|
let pus_tc = base_ping_tc_simple_ctor();
|
||||||
let mut buf = [0; 32];
|
let mut buf = [0; 32];
|
||||||
pus_tc.write_to_bytes(&mut buf).unwrap();
|
pus_tc.write_to_bytes(&mut buf).unwrap();
|
||||||
assert_eq!(pus_tc, PusTcReader::new(&buf).unwrap().0);
|
assert_eq!(pus_tc, PusTcReader::new(&buf).unwrap());
|
||||||
assert_eq!(PusTcReader::new(&buf).unwrap().0, pus_tc);
|
assert_eq!(PusTcReader::new(&buf).unwrap(), pus_tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
138
src/ecss/tm.rs
138
src/ecss/tm.rs
@ -35,13 +35,14 @@
|
|||||||
//! println!("{:?}", &test_buf[0..written_size]);
|
//! println!("{:?}", &test_buf[0..written_size]);
|
||||||
//!
|
//!
|
||||||
//! // Deserialize from the raw byte representation
|
//! // Deserialize from the raw byte representation
|
||||||
//! let (ping_tm_reader, read_size) = PusTmReader::new(&test_buf, 7).expect("Deserialization failed");
|
//! let ping_tm_reader = PusTmReader::new(&test_buf, 7).expect("Deserialization failed");
|
||||||
//! assert_eq!(written_size, read_size);
|
//! assert_eq!(written_size, ping_tm_reader.total_len());
|
||||||
//! assert_eq!(ping_tm_reader.service(), 17);
|
//! assert_eq!(ping_tm_reader.service(), 17);
|
||||||
//! assert_eq!(ping_tm_reader.subservice(), 2);
|
//! assert_eq!(ping_tm_reader.subservice(), 2);
|
||||||
//! assert_eq!(ping_tm_reader.apid(), 0x02);
|
//! assert_eq!(ping_tm_reader.apid(), 0x02);
|
||||||
//! 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::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, CrcType, PusError, PusPacket, PusVersion,
|
||||||
@ -49,7 +50,7 @@ use crate::ecss::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN,
|
ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN,
|
||||||
CRC_CCITT_FALSE, MAX_APID, MAX_SEQ_COUNT,
|
MAX_APID, MAX_SEQ_COUNT,
|
||||||
};
|
};
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
@ -64,6 +65,8 @@ use crate::time::{TimeWriter, TimestampError};
|
|||||||
|
|
||||||
use self::zc::PusTmSecHeaderWithoutTimestamp;
|
use self::zc::PusTmSecHeaderWithoutTimestamp;
|
||||||
|
|
||||||
|
use super::verify_crc16_ccitt_false_from_raw_to_pus_error_no_table;
|
||||||
|
|
||||||
pub trait IsPusTelemetry {}
|
pub trait IsPusTelemetry {}
|
||||||
|
|
||||||
/// Length without timestamp
|
/// Length without timestamp
|
||||||
@ -389,6 +392,29 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
|
|||||||
|
|
||||||
/// Write the raw PUS byte representation to a provided buffer.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
pub fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
pub fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||||
|
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;
|
||||||
|
Ok(curr_idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
|
pub fn write_to_bytes_crc_no_table(
|
||||||
|
&self,
|
||||||
|
slice: &mut [u8],
|
||||||
|
) -> Result<usize, ByteConversionError> {
|
||||||
|
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;
|
||||||
|
Ok(curr_idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
|
pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||||
let mut curr_idx = 0;
|
let mut curr_idx = 0;
|
||||||
let total_size = self.len_written();
|
let total_size = self.len_written();
|
||||||
if total_size > slice.len() {
|
if total_size > slice.len() {
|
||||||
@ -411,10 +437,6 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
|
|||||||
curr_idx += self.sec_header.timestamp.len();
|
curr_idx += self.sec_header.timestamp.len();
|
||||||
slice[curr_idx..curr_idx + self.source_data.len()].copy_from_slice(self.source_data);
|
slice[curr_idx..curr_idx + self.source_data.len()].copy_from_slice(self.source_data);
|
||||||
curr_idx += self.source_data.len();
|
curr_idx += self.source_data.len();
|
||||||
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)
|
Ok(curr_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,8 +468,8 @@ impl WritablePusPacket for PusTmCreator<'_, '_> {
|
|||||||
+ self.source_data.len()
|
+ self.source_data.len()
|
||||||
}
|
}
|
||||||
/// Write the raw PUS byte representation to a provided buffer.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes(self, slice)?)
|
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +501,7 @@ impl PusPacket for PusTmCreator<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn crc16(&self) -> Option<u16> {
|
fn opt_crc16(&self) -> Option<u16> {
|
||||||
Some(self.calc_own_crc16())
|
Some(self.calc_own_crc16())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -534,7 +556,26 @@ 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, usize), PusError> {
|
pub fn new(slice: &'raw_data [u8], timestamp_len: usize) -> Result<Self, PusError> {
|
||||||
|
let tc = Self::new_no_crc_check(slice, timestamp_len)?;
|
||||||
|
verify_crc16_ccitt_false_from_raw_to_pus_error(tc.raw_data(), tc.crc16)?;
|
||||||
|
Ok(tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [PusTmReader::new] but uses a table-less CRC implementation.
|
||||||
|
pub fn new_crc_no_table(
|
||||||
|
slice: &'raw_data [u8],
|
||||||
|
timestamp_len: usize,
|
||||||
|
) -> Result<Self, PusError> {
|
||||||
|
let tc = Self::new_no_crc_check(slice, timestamp_len)?;
|
||||||
|
verify_crc16_ccitt_false_from_raw_to_pus_error_no_table(tc.raw_data(), tc.crc16)?;
|
||||||
|
Ok(tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_no_crc_check(
|
||||||
|
slice: &'raw_data [u8],
|
||||||
|
timestamp_len: usize,
|
||||||
|
) -> 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 {
|
||||||
return Err(ByteConversionError::FromSliceTooSmall {
|
return Err(ByteConversionError::FromSliceTooSmall {
|
||||||
@ -572,15 +613,13 @@ impl<'raw_data> PusTmReader<'raw_data> {
|
|||||||
};
|
};
|
||||||
current_idx += timestamp_len;
|
current_idx += timestamp_len;
|
||||||
let raw_data = &slice[0..total_len];
|
let raw_data = &slice[0..total_len];
|
||||||
let pus_tm = 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: &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)?,
|
||||||
crc16: crc_from_raw_data(raw_data)?,
|
crc16: crc_from_raw_data(raw_data)?,
|
||||||
};
|
})
|
||||||
verify_crc16_ccitt_false_from_raw_to_pus_error(raw_data, pus_tm.crc16)?;
|
|
||||||
Ok((pus_tm, total_len))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -598,6 +637,11 @@ impl<'raw_data> PusTmReader<'raw_data> {
|
|||||||
self.sec_header.timestamp
|
self.sec_header.timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn crc16(&self) -> u16 {
|
||||||
|
self.crc16
|
||||||
|
}
|
||||||
|
|
||||||
/// This function will return the slice [Self] was constructed from.
|
/// This function will return the slice [Self] was constructed from.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn raw_data(&self) -> &[u8] {
|
pub fn raw_data(&self) -> &[u8] {
|
||||||
@ -634,8 +678,8 @@ impl PusPacket for PusTmReader<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn crc16(&self) -> Option<u16> {
|
fn opt_crc16(&self) -> Option<u16> {
|
||||||
Some(self.crc16)
|
Some(self.crc16())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -822,7 +866,7 @@ impl PusPacket for PusTmZeroCopyWriter<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn crc16(&self) -> Option<u16> {
|
fn opt_crc16(&self) -> Option<u16> {
|
||||||
Some(u16::from_be_bytes(
|
Some(u16::from_be_bytes(
|
||||||
self.raw_tm[self.sp_header().total_len() - 2..self.sp_header().total_len()]
|
self.raw_tm[self.sp_header().total_len() - 2..self.sp_header().total_len()]
|
||||||
.try_into()
|
.try_into()
|
||||||
@ -918,7 +962,19 @@ 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.crc16().unwrap(), &buf);
|
verify_raw_ping_reply(pus_tm.opt_crc16().unwrap(), &buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization_no_source_data_no_table() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let ser_len = pus_tm
|
||||||
|
.write_to_bytes_crc_no_table(&mut buf)
|
||||||
|
.expect("Serialization failed");
|
||||||
|
assert_eq!(ser_len, 22);
|
||||||
|
verify_raw_ping_reply(pus_tm.opt_crc16().unwrap(), &buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -955,9 +1011,9 @@ mod tests {
|
|||||||
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
let tm_vec = pus_tm.to_vec().expect("Serialization failed");
|
let tm_vec = pus_tm.to_vec().expect("Serialization failed");
|
||||||
assert_eq!(tm_vec.len(), 22);
|
assert_eq!(tm_vec.len(), 22);
|
||||||
let (tm_deserialized, size) =
|
let tm_deserialized =
|
||||||
PusTmReader::new(tm_vec.as_slice(), 7).expect("Deserialization failed");
|
PusTmReader::new(tm_vec.as_slice(), 7).expect("Deserialization failed");
|
||||||
assert_eq!(tm_vec.len(), size);
|
assert_eq!(tm_vec.len(), tm_deserialized.total_len());
|
||||||
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
|
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
@ -969,13 +1025,32 @@ 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);
|
||||||
let (tm_deserialized, size) = PusTmReader::new(&buf, 7).expect("Deserialization failed");
|
let tm_deserialized = PusTmReader::new(&buf, 7).expect("Deserialization failed");
|
||||||
assert_eq!(ser_len, size);
|
assert_eq!(ser_len, tm_deserialized.total_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().unwrap(), pus_tm.crc16().unwrap());
|
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap());
|
||||||
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
|
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialization_no_table() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let ser_len = pus_tm
|
||||||
|
.write_to_bytes(&mut buf)
|
||||||
|
.expect("Serialization failed");
|
||||||
|
assert_eq!(ser_len, 22);
|
||||||
|
let tm_deserialized =
|
||||||
|
PusTmReader::new_crc_no_table(&buf, 7).expect("Deserialization failed");
|
||||||
|
assert_eq!(ser_len, tm_deserialized.total_len());
|
||||||
|
assert_eq!(tm_deserialized.user_data(), tm_deserialized.source_data());
|
||||||
|
assert_eq!(tm_deserialized.raw_data(), &buf[..ser_len]);
|
||||||
|
assert_eq!(tm_deserialized.crc16(), pus_tm.opt_crc16().unwrap());
|
||||||
|
verify_ping_reply_with_reader(&tm_deserialized, false, 22, dummy_timestamp());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialization_faulty_crc() {
|
fn test_deserialization_faulty_crc() {
|
||||||
let timestamp = dummy_timestamp();
|
let timestamp = dummy_timestamp();
|
||||||
@ -1042,7 +1117,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.crc16().unwrap(), vec.as_slice());
|
verify_raw_ping_reply(pus_tm.opt_crc16().unwrap(), vec.as_slice());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1152,7 +1227,7 @@ mod tests {
|
|||||||
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
let mut buf = [0; 32];
|
let mut buf = [0; 32];
|
||||||
pus_tm.write_to_bytes(&mut buf).unwrap();
|
pus_tm.write_to_bytes(&mut buf).unwrap();
|
||||||
assert_eq!(pus_tm, PusTmReader::new(&buf, timestamp.len()).unwrap().0);
|
assert_eq!(pus_tm, PusTmReader::new(&buf, timestamp.len()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1172,9 +1247,8 @@ mod tests {
|
|||||||
assert!(!writer.set_apid(MAX_SEQ_COUNT + 1));
|
assert!(!writer.set_apid(MAX_SEQ_COUNT + 1));
|
||||||
writer.finish();
|
writer.finish();
|
||||||
// This performs all necessary checks, including the CRC check.
|
// This performs all necessary checks, including the CRC check.
|
||||||
let (tm_read_back, tm_size_read_back) =
|
let tm_read_back = PusTmReader::new(&buf, 7).expect("Re-creating PUS TM failed");
|
||||||
PusTmReader::new(&buf, 7).expect("Re-creating PUS TM failed");
|
assert_eq!(tm_read_back.total_len(), tm_size);
|
||||||
assert_eq!(tm_size_read_back, tm_size);
|
|
||||||
assert_eq!(tm_read_back.msg_counter(), 100);
|
assert_eq!(tm_read_back.msg_counter(), 100);
|
||||||
assert_eq!(tm_read_back.dest_id(), 55);
|
assert_eq!(tm_read_back.dest_id(), 55);
|
||||||
assert_eq!(tm_read_back.seq_count(), MAX_SEQ_COUNT);
|
assert_eq!(tm_read_back.seq_count(), MAX_SEQ_COUNT);
|
||||||
@ -1222,7 +1296,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.crc16();
|
let crc16 = writer.opt_crc16();
|
||||||
assert!(crc16.is_some());
|
assert!(crc16.is_some());
|
||||||
assert_eq!(crc16.unwrap(), crc16_raw);
|
assert_eq!(crc16.unwrap(), crc16_raw);
|
||||||
writer.finish();
|
writer.finish();
|
||||||
@ -1240,8 +1314,8 @@ mod tests {
|
|||||||
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
let mut buf = [0; 32];
|
let mut buf = [0; 32];
|
||||||
pus_tm.write_to_bytes(&mut buf).unwrap();
|
pus_tm.write_to_bytes(&mut buf).unwrap();
|
||||||
let (tm_0, _) = PusTmReader::new(&buf, timestamp.len()).unwrap();
|
let tm_0 = PusTmReader::new(&buf, timestamp.len()).unwrap();
|
||||||
let (tm_1, _) = PusTmReader::new(&buf, timestamp.len()).unwrap();
|
let tm_1 = PusTmReader::new(&buf, timestamp.len()).unwrap();
|
||||||
assert_eq!(tm_0, tm_1);
|
assert_eq!(tm_0, tm_1);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -62,7 +62,6 @@ extern crate alloc;
|
|||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
use core::{fmt::Debug, hash::Hash};
|
use core::{fmt::Debug, hash::Hash};
|
||||||
use crc::{Crc, CRC_16_IBM_3740};
|
|
||||||
use delegate::delegate;
|
use delegate::delegate;
|
||||||
use zerocopy::{FromBytes, IntoBytes};
|
use zerocopy::{FromBytes, IntoBytes};
|
||||||
|
|
||||||
@ -70,6 +69,7 @@ use zerocopy::{FromBytes, IntoBytes};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod cfdp;
|
pub mod cfdp;
|
||||||
|
pub mod crc;
|
||||||
pub mod ecss;
|
pub mod ecss;
|
||||||
pub mod seq_count;
|
pub mod seq_count;
|
||||||
pub mod time;
|
pub mod time;
|
||||||
@ -81,9 +81,6 @@ mod private {
|
|||||||
|
|
||||||
pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::<crate::zc::SpHeader>();
|
pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::<crate::zc::SpHeader>();
|
||||||
|
|
||||||
/// CRC algorithm used by the PUS standard, the CCSDS TC standard and the CFDP standard.
|
|
||||||
pub const CRC_CCITT_FALSE: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_3740);
|
|
||||||
|
|
||||||
pub const MAX_APID: u16 = 2u16.pow(11) - 1;
|
pub const MAX_APID: u16 = 2u16.pow(11) - 1;
|
||||||
pub const MAX_SEQ_COUNT: u16 = 2u16.pow(14) - 1;
|
pub const MAX_SEQ_COUNT: u16 = 2u16.pow(14) - 1;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user