start making ECSS checksum optional
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,30 +383,41 @@ pub trait WritablePusPacket {
|
|||||||
/// The length here also includes the CRC length.
|
/// The length here also includes the CRC length.
|
||||||
fn len_written(&self) -> usize;
|
fn len_written(&self) -> usize;
|
||||||
|
|
||||||
/// Writes the packet to the given slice without writing the CRC.
|
/// Checksum generation is enabled for the packet.
|
||||||
///
|
fn has_checksum(&self) -> bool;
|
||||||
/// 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
|
/// Writes the packet to the given slice without writing the CRC checksum.
|
||||||
/// uses the [CRC_CCITT_FALSE] to calculate the CRC and write it to the slice.
|
///
|
||||||
|
/// 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<usize, PusError>;
|
||||||
|
|
||||||
|
/// 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<usize, PusError> {
|
fn write_to_bytes(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
let mut curr_idx = self.write_to_bytes_no_crc(slice)?;
|
let mut curr_idx = self.write_to_bytes_no_checksum(slice)?;
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
if self.has_checksum() {
|
||||||
digest.update(&slice[0..curr_idx]);
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes());
|
digest.update(&slice[0..curr_idx]);
|
||||||
curr_idx += 2;
|
slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes());
|
||||||
|
curr_idx += 2;
|
||||||
|
}
|
||||||
Ok(curr_idx)
|
Ok(curr_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// First uses [Self::write_to_bytes_no_crc] to write the packet to the given slice and then
|
/// 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.
|
/// uses the [CRC_CCITT_FALSE_NO_TABLE] to calculate the CRC and write it to the slice if
|
||||||
fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
/// the paket is configured to include a checksum.
|
||||||
let mut curr_idx = self.write_to_bytes_no_crc(slice)?;
|
fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
let mut curr_idx = self.write_to_bytes_no_checksum(slice)?;
|
||||||
digest.update(&slice[0..curr_idx]);
|
if self.has_checksum() {
|
||||||
slice[curr_idx..curr_idx + 2].copy_from_slice(&digest.finalize().to_be_bytes());
|
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
||||||
curr_idx += 2;
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,6 +432,25 @@ 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 {
|
||||||
|
/// Set the CCSDS data length field on construction.
|
||||||
|
pub set_ccsds_len: bool,
|
||||||
|
/// CRC-16-CCITT Checksum is present.
|
||||||
|
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;
|
||||||
|
|||||||
344
src/ecss/tc.rs
344
src/ecss/tc.rs
@@ -6,13 +6,13 @@
|
|||||||
//! ```rust
|
//! ```rust
|
||||||
//! use spacepackets::{CcsdsPacket, SpHeader};
|
//! use spacepackets::{CcsdsPacket, SpHeader};
|
||||||
//! use spacepackets::ecss::{PusPacket, WritablePusPacket};
|
//! use spacepackets::ecss::{PusPacket, WritablePusPacket};
|
||||||
//! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader};
|
//! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader, CreatorConfig};
|
||||||
//!
|
//!
|
||||||
//! // Create a ping telecommand with no user application data
|
//! // Create a ping telecommand with no user application data
|
||||||
//! let pus_tc = PusTcCreator::new_no_app_data(
|
//! let pus_tc = PusTcCreator::new_no_app_data(
|
||||||
//! SpHeader::new_from_apid(0x02),
|
//! SpHeader::new_from_apid(0x02),
|
||||||
//! PusTcSecondaryHeader::new_simple(17, 1),
|
//! PusTcSecondaryHeader::new_simple(17, 1),
|
||||||
//! true
|
//! CreatorConfig::default()
|
||||||
//! );
|
//! );
|
||||||
//! println!("{:?}", pus_tc);
|
//! println!("{:?}", pus_tc);
|
||||||
//! assert_eq!(pus_tc.service(), 17);
|
//! assert_eq!(pus_tc.service(), 17);
|
||||||
@@ -34,9 +34,10 @@
|
|||||||
//! 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, CrcType, PusError, PusPacket, PusVersion,
|
verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, PusVersion,
|
||||||
WritablePusPacket,
|
WritablePusPacket,
|
||||||
};
|
};
|
||||||
use crate::SpHeader;
|
use crate::SpHeader;
|
||||||
@@ -55,8 +56,7 @@ 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 = CCSDS_HEADER_LEN + PUC_TC_SECONDARY_HEADER_LEN;
|
||||||
CCSDS_HEADER_LEN + PUC_TC_SECONDARY_HEADER_LEN + size_of::<CrcType>();
|
|
||||||
const PUS_VERSION: PusVersion = PusVersion::PusC;
|
const PUS_VERSION: PusVersion = PusVersion::PusC;
|
||||||
|
|
||||||
/// Marker trait for PUS telecommand structures.
|
/// Marker trait for PUS telecommand structures.
|
||||||
@@ -234,6 +234,7 @@ pub struct PusTcCreator<'app_data> {
|
|||||||
sp_header: SpHeader,
|
sp_header: SpHeader,
|
||||||
pub sec_header: PusTcSecondaryHeader,
|
pub sec_header: PusTcSecondaryHeader,
|
||||||
app_data: &'app_data [u8],
|
app_data: &'app_data [u8],
|
||||||
|
has_checksum: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'app_data> PusTcCreator<'app_data> {
|
impl<'app_data> PusTcCreator<'app_data> {
|
||||||
@@ -246,15 +247,13 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
/// * `sec_header` - Information contained in the data field header, including the service
|
/// * `sec_header` - Information contained in the data field header, including the service
|
||||||
/// and subservice type
|
/// and subservice type
|
||||||
/// * `app_data` - Custom application data
|
/// * `app_data` - Custom application data
|
||||||
/// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length
|
/// * `packet_config` - Common configuration options for TC packet creation
|
||||||
/// 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
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
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,
|
packet_config: CreatorConfig,
|
||||||
) -> 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();
|
||||||
@@ -262,8 +261,9 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
sp_header,
|
sp_header,
|
||||||
app_data,
|
app_data,
|
||||||
sec_header,
|
sec_header,
|
||||||
|
has_checksum: packet_config.has_checksum,
|
||||||
};
|
};
|
||||||
if set_ccsds_len {
|
if packet_config.set_ccsds_len {
|
||||||
pus_tc.update_ccsds_data_len();
|
pus_tc.update_ccsds_data_len();
|
||||||
}
|
}
|
||||||
pus_tc
|
pus_tc
|
||||||
@@ -277,13 +277,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,
|
packet_config: CreatorConfig,
|
||||||
) -> 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,
|
packet_config,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,9 +291,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,
|
packet_config: CreatorConfig,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(sp_header, sec_header, &[], set_ccsds_len)
|
Self::new(sp_header, sec_header, &[], packet_config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -356,6 +356,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);
|
||||||
@@ -367,9 +372,12 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
let pus_tc_header = zc::PusTcSecondaryHeader::try_from(self.sec_header).unwrap();
|
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(pus_tc_header.as_bytes());
|
||||||
vec.extend_from_slice(self.app_data);
|
vec.extend_from_slice(self.app_data);
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
if self.has_checksum() {
|
||||||
digest.update(&vec[start_idx..start_idx + appended_len - 2]);
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
vec.extend_from_slice(&digest.finalize().to_be_bytes());
|
digest.update(&vec[start_idx..start_idx + appended_len]);
|
||||||
|
vec.extend_from_slice(&digest.finalize().to_be_bytes());
|
||||||
|
appended_len += 2;
|
||||||
|
}
|
||||||
appended_len
|
appended_len
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,13 +393,13 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
slice: &mut [u8],
|
slice: &mut [u8],
|
||||||
) -> Result<usize, ByteConversionError> {
|
) -> Result<usize, ByteConversionError> {
|
||||||
let writer_unfinalized = self.common_write(slice)?;
|
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.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||||
let writer_unfinalized = self.common_write(slice)?;
|
let writer_unfinalized = self.common_write(slice)?;
|
||||||
Ok(writer_unfinalized.finalize_no_crc())
|
Ok(writer_unfinalized.finalize_no_checksum())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common_write<'a>(
|
fn common_write<'a>(
|
||||||
@@ -409,6 +417,7 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
self.sp_header,
|
self.sp_header,
|
||||||
self.sec_header,
|
self.sec_header,
|
||||||
self.app_data.len(),
|
self.app_data.len(),
|
||||||
|
self.has_checksum,
|
||||||
)?;
|
)?;
|
||||||
writer_unfinalized
|
writer_unfinalized
|
||||||
.app_data_mut()
|
.app_data_mut()
|
||||||
@@ -420,11 +429,20 @@ impl<'app_data> PusTcCreator<'app_data> {
|
|||||||
impl WritablePusPacket for PusTcCreator<'_> {
|
impl WritablePusPacket for PusTcCreator<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn len_written(&self) -> usize {
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn has_checksum(&self) -> bool {
|
||||||
|
self.has_checksum()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the raw PUS byte representation to a provided buffer.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,7 +450,7 @@ impl WritablePusPacket for PusTcCreator<'_> {
|
|||||||
Ok(Self::write_to_bytes(self, slice)?)
|
Ok(Self::write_to_bytes(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -457,9 +475,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<'_> {
|
||||||
@@ -496,6 +521,7 @@ pub struct PusTcCreatorWithReservedAppData<'buf> {
|
|||||||
buf: &'buf mut [u8],
|
buf: &'buf mut [u8],
|
||||||
app_data_offset: usize,
|
app_data_offset: usize,
|
||||||
full_len: usize,
|
full_len: usize,
|
||||||
|
has_checksum: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
|
impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
|
||||||
@@ -514,10 +540,14 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
|
|||||||
mut sp_header: SpHeader,
|
mut sp_header: SpHeader,
|
||||||
sec_header: PusTcSecondaryHeader,
|
sec_header: PusTcSecondaryHeader,
|
||||||
app_data_len: usize,
|
app_data_len: usize,
|
||||||
|
has_checksum: bool,
|
||||||
) -> Result<Self, ByteConversionError> {
|
) -> Result<Self, ByteConversionError> {
|
||||||
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();
|
||||||
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() {
|
if len_written > buf.len() {
|
||||||
return Err(ByteConversionError::ToSliceTooSmall {
|
return Err(ByteConversionError::ToSliceTooSmall {
|
||||||
found: buf.len(),
|
found: buf.len(),
|
||||||
@@ -525,7 +555,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'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, app_data_len)
|
Self::write_to_bytes_partially(buf, sp_header, sec_header, app_data_len, has_checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_bytes_partially(
|
fn write_to_bytes_partially(
|
||||||
@@ -533,6 +563,7 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
|
|||||||
sp_header: SpHeader,
|
sp_header: SpHeader,
|
||||||
sec_header: PusTcSecondaryHeader,
|
sec_header: PusTcSecondaryHeader,
|
||||||
app_data_len: usize,
|
app_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])?;
|
||||||
@@ -545,10 +576,14 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
|
|||||||
curr_idx += sec_header_len;
|
curr_idx += sec_header_len;
|
||||||
let app_data_offset = curr_idx;
|
let app_data_offset = curr_idx;
|
||||||
curr_idx += app_data_len;
|
curr_idx += app_data_len;
|
||||||
|
if has_checksum {
|
||||||
|
curr_idx += 2;
|
||||||
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
buf,
|
buf,
|
||||||
app_data_offset,
|
app_data_offset,
|
||||||
full_len: curr_idx + 2,
|
full_len: curr_idx,
|
||||||
|
has_checksum,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,49 +595,74 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> {
|
|||||||
/// Mutable access to the application data buffer.
|
/// Mutable access to the application data buffer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn app_data_mut(&mut self) -> &mut [u8] {
|
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.
|
/// Access to the source data buffer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn app_data(&self) -> &[u8] {
|
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]
|
#[inline]
|
||||||
pub fn app_data_len(&self) -> usize {
|
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.
|
/// Returns the full packet length.
|
||||||
pub fn finalize(self) -> usize {
|
pub fn finalize(self) -> usize {
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
let written_len = self.len_written();
|
||||||
digest.update(&self.buf[0..self.full_len - 2]);
|
if self.has_checksum {
|
||||||
self.buf[self.full_len - 2..self.full_len]
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
.copy_from_slice(&digest.finalize().to_be_bytes());
|
digest.update(&self.buf[0..written_len - 2]);
|
||||||
self.full_len
|
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
|
/// 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.
|
/// Returns the full packet length.
|
||||||
pub fn finalize_crc_no_table(self) -> usize {
|
pub fn finalize_checksum_no_table(self) -> usize {
|
||||||
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
let written_len = self.len_written();
|
||||||
digest.update(&self.buf[0..self.full_len - 2]);
|
if self.has_checksum {
|
||||||
self.buf[self.full_len - 2..self.full_len]
|
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
||||||
.copy_from_slice(&digest.finalize().to_be_bytes());
|
digest.update(&self.buf[0..written_len - 2]);
|
||||||
self.full_len
|
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]
|
#[inline]
|
||||||
pub fn finalize_no_crc(self) -> usize {
|
pub fn finalize_no_checksum(self) -> usize {
|
||||||
self.full_len - 2
|
if self.has_checksum {
|
||||||
|
self.full_len - 2
|
||||||
|
} else {
|
||||||
|
self.full_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,29 +686,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 {
|
||||||
@@ -681,12 +756,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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,7 +790,7 @@ impl<'raw_data> PusTcReader<'raw_data> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn crc16(&self) -> u16 {
|
pub fn crc16(&self) -> Option<u16> {
|
||||||
self.crc16
|
self.crc16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,14 +816,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -796,17 +879,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)
|
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)
|
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)
|
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]
|
||||||
@@ -815,6 +937,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();
|
||||||
@@ -824,11 +954,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();
|
||||||
@@ -837,7 +979,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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -846,11 +988,12 @@ mod tests {
|
|||||||
fn test_serialization_with_trait_2() {
|
fn test_serialization_with_trait_2() {
|
||||||
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_crc_no_table(&pus_tc, test_buf.as_mut_slice())
|
let size =
|
||||||
.expect("Error writing TC to buffer");
|
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!(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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -864,13 +1007,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
|
||||||
@@ -882,10 +1025,10 @@ 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_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");
|
.expect("error writing tc to buffer");
|
||||||
assert_eq!(size, 11);
|
assert_eq!(size, 11);
|
||||||
assert_eq!(test_buf[11], 0);
|
assert_eq!(test_buf[11], 0);
|
||||||
@@ -915,7 +1058,7 @@ mod tests {
|
|||||||
let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
|
let tc_header = PusTcSecondaryHeader::new_simple(17, 1);
|
||||||
let mut test_buf: [u8; 32] = [0; 32];
|
let mut test_buf: [u8; 32] = [0; 32];
|
||||||
let mut pus_tc =
|
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.len_written(), 13);
|
||||||
assert_eq!(pus_tc.app_data_len(), 0);
|
assert_eq!(pus_tc.app_data_len(), 0);
|
||||||
assert_eq!(pus_tc.app_data(), &[]);
|
assert_eq!(pus_tc.app_data(), &[]);
|
||||||
@@ -939,7 +1082,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);
|
||||||
@@ -965,7 +1108,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);
|
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);
|
||||||
@@ -973,7 +1125,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())
|
||||||
@@ -987,7 +1139,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);
|
||||||
@@ -995,9 +1147,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())
|
||||||
@@ -1056,7 +1232,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);
|
||||||
@@ -1088,7 +1264,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
|
||||||
@@ -1229,7 +1405,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]);
|
||||||
|
|||||||
@@ -469,8 +469,13 @@ impl WritablePusPacket for PusTcCreator<'_> {
|
|||||||
CCSDS_HEADER_LEN + self.sec_header.written_len() + self.app_data.len() + 2
|
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.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +483,7 @@ impl WritablePusPacket for PusTcCreator<'_> {
|
|||||||
Ok(Self::write_to_bytes(self, slice)?)
|
Ok(Self::write_to_bytes(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,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)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -785,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -876,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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -889,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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -898,11 +908,12 @@ mod tests {
|
|||||||
fn test_serialization_with_trait_2() {
|
fn test_serialization_with_trait_2() {
|
||||||
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_crc_no_table(&pus_tc, test_buf.as_mut_slice())
|
let size =
|
||||||
.expect("Error writing TC to buffer");
|
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!(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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -916,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())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -937,7 +948,7 @@ mod tests {
|
|||||||
fn test_serialization_no_crc_with_trait() {
|
fn test_serialization_no_crc_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_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");
|
.expect("error writing tc to buffer");
|
||||||
assert_eq!(size, 9);
|
assert_eq!(size, 9);
|
||||||
assert_eq!(test_buf[9], 0);
|
assert_eq!(test_buf[9], 0);
|
||||||
@@ -1039,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);
|
||||||
|
|||||||
509
src/ecss/tm.rs
509
src/ecss/tm.rs
@@ -8,7 +8,7 @@
|
|||||||
//! use spacepackets::time::cds::CdsTime;
|
//! use spacepackets::time::cds::CdsTime;
|
||||||
//! use spacepackets::{CcsdsPacket, SpHeader};
|
//! use spacepackets::{CcsdsPacket, SpHeader};
|
||||||
//! use spacepackets::ecss::{PusPacket, WritablePusPacket};
|
//! use spacepackets::ecss::{PusPacket, WritablePusPacket};
|
||||||
//! use spacepackets::ecss::tm::{PusTmCreator, PusTmReader, PusTmSecondaryHeader};
|
//! use spacepackets::ecss::tm::{PusTmCreator, PusTmReader, PusTmSecondaryHeader, CreatorConfig};
|
||||||
//!
|
//!
|
||||||
//! let mut time_buf: [u8; 7] = [0; 7];
|
//! let mut time_buf: [u8; 7] = [0; 7];
|
||||||
//! let time_now = CdsTime::now_with_u16_days().expect("creating CDS timestamp failed");
|
//! let time_now = CdsTime::now_with_u16_days().expect("creating CDS timestamp failed");
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
//! let ping_tm = PusTmCreator::new_no_source_data(
|
//! let ping_tm = PusTmCreator::new_no_source_data(
|
||||||
//! SpHeader::new_from_apid(0x02),
|
//! SpHeader::new_from_apid(0x02),
|
||||||
//! PusTmSecondaryHeader::new_simple(17, 2, &time_buf),
|
//! PusTmSecondaryHeader::new_simple(17, 2, &time_buf),
|
||||||
//! true
|
//! CreatorConfig::default()
|
||||||
//! );
|
//! );
|
||||||
//! println!("{:?}", ping_tm);
|
//! println!("{:?}", ping_tm);
|
||||||
//! assert_eq!(ping_tm.service(), 17);
|
//! assert_eq!(ping_tm.service(), 17);
|
||||||
@@ -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> {
|
||||||
@@ -287,15 +288,13 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
|
|||||||
/// * `sec_header` - Information contained in the secondary header, including the service
|
/// * `sec_header` - Information contained in the secondary header, including the service
|
||||||
/// and subservice type
|
/// and subservice type
|
||||||
/// * `source_data` - Custom application data
|
/// * `source_data` - Custom application data
|
||||||
/// * `set_ccsds_len` - Can be used to automatically update the CCSDS space packet data length
|
/// * `packet_config` - Common configuration options for TM packet creation
|
||||||
/// 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
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
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 +303,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 +319,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]
|
||||||
@@ -405,13 +410,13 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
|
|||||||
slice: &mut [u8],
|
slice: &mut [u8],
|
||||||
) -> Result<usize, ByteConversionError> {
|
) -> Result<usize, ByteConversionError> {
|
||||||
let writer_unfinalized = self.common_write(slice)?;
|
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.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
pub fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, ByteConversionError> {
|
||||||
let writer_unfinalized = self.common_write(slice)?;
|
let writer_unfinalized = self.common_write(slice)?;
|
||||||
Ok(writer_unfinalized.finalize_no_crc())
|
Ok(writer_unfinalized.finalize_no_checksum())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common_write<'a>(
|
fn common_write<'a>(
|
||||||
@@ -429,6 +434,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 +447,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());
|
||||||
@@ -449,9 +458,11 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> {
|
|||||||
vec.extend_from_slice(sec_header.as_bytes());
|
vec.extend_from_slice(sec_header.as_bytes());
|
||||||
vec.extend_from_slice(self.sec_header.timestamp);
|
vec.extend_from_slice(self.sec_header.timestamp);
|
||||||
vec.extend_from_slice(self.source_data);
|
vec.extend_from_slice(self.source_data);
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
if self.has_checksum {
|
||||||
digest.update(&vec[start_idx..start_idx + appended_len - 2]);
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
vec.extend_from_slice(&digest.finalize().to_be_bytes());
|
digest.update(&vec[start_idx..start_idx + appended_len - 2]);
|
||||||
|
vec.extend_from_slice(&digest.finalize().to_be_bytes());
|
||||||
|
}
|
||||||
Ok(appended_len)
|
Ok(appended_len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -459,12 +470,22 @@ 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.
|
||||||
|
fn has_checksum(&self) -> bool {
|
||||||
|
self.has_checksum
|
||||||
|
}
|
||||||
|
|
||||||
/// Write the raw PUS byte representation to a provided buffer.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +493,7 @@ impl WritablePusPacket for PusTmCreator<'_, '_> {
|
|||||||
Ok(Self::write_to_bytes(self, slice)?)
|
Ok(Self::write_to_bytes(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,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;
|
||||||
@@ -509,7 +535,10 @@ impl PusPacket for PusTmCreator<'_, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -550,6 +579,7 @@ pub struct PusTmCreatorWithReservedSourceData<'buf> {
|
|||||||
buf: &'buf mut [u8],
|
buf: &'buf mut [u8],
|
||||||
source_data_offset: usize,
|
source_data_offset: usize,
|
||||||
full_len: usize,
|
full_len: usize,
|
||||||
|
has_checksum: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
|
impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
|
||||||
@@ -568,11 +598,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(),
|
||||||
@@ -580,7 +614,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(
|
||||||
@@ -588,6 +622,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])?;
|
||||||
@@ -602,10 +637,14 @@ 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,
|
||||||
|
has_checksum,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,28 +656,42 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
|
|||||||
/// Mutable access to the source data buffer.
|
/// Mutable access to the source data buffer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn source_data_mut(&mut self) -> &mut [u8] {
|
pub fn source_data_mut(&mut self) -> &mut [u8] {
|
||||||
&mut self.buf[self.source_data_offset..self.full_len - 2]
|
if self.has_checksum {
|
||||||
|
&mut self.buf[self.source_data_offset..self.full_len - 2]
|
||||||
|
} else {
|
||||||
|
&mut self.buf[self.source_data_offset..self.full_len]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access to the source data buffer.
|
/// Access to the source data buffer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn source_data(&self) -> &[u8] {
|
pub fn source_data(&self) -> &[u8] {
|
||||||
&self.buf[self.source_data_offset..self.full_len - 2]
|
if self.has_checksum {
|
||||||
|
&self.buf[self.source_data_offset..self.full_len - 2]
|
||||||
|
} else {
|
||||||
|
&self.buf[self.source_data_offset..self.full_len]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn source_data_len(&self) -> usize {
|
pub fn source_data_len(&self) -> usize {
|
||||||
self.full_len - 2 - self.source_data_offset
|
let mut len = self.full_len - self.source_data_offset;
|
||||||
|
if self.has_checksum {
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalize the TM packet by calculating and writing the CRC16.
|
/// Finalize the TM packet by calculating and writing the CRC16.
|
||||||
///
|
///
|
||||||
/// Returns the full packet length.
|
/// Returns the full packet length.
|
||||||
pub fn finalize(self) -> usize {
|
pub fn finalize(self) -> usize {
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
if self.has_checksum {
|
||||||
digest.update(&self.buf[0..self.full_len - 2]);
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
self.buf[self.full_len - 2..self.full_len]
|
digest.update(&self.buf[0..self.full_len - 2]);
|
||||||
.copy_from_slice(&digest.finalize().to_be_bytes());
|
self.buf[self.full_len - 2..self.full_len]
|
||||||
|
.copy_from_slice(&digest.finalize().to_be_bytes());
|
||||||
|
}
|
||||||
self.full_len
|
self.full_len
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -646,11 +699,13 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
|
|||||||
/// implementation.
|
/// implementation.
|
||||||
///
|
///
|
||||||
/// Returns the full packet length.
|
/// Returns the full packet length.
|
||||||
pub fn finalize_crc_no_table(self) -> usize {
|
pub fn finalize_checksum_no_table(self) -> usize {
|
||||||
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
if self.has_checksum {
|
||||||
digest.update(&self.buf[0..self.full_len - 2]);
|
let mut digest = CRC_CCITT_FALSE_NO_TABLE.digest();
|
||||||
self.buf[self.full_len - 2..self.full_len]
|
digest.update(&self.buf[0..self.full_len - 2]);
|
||||||
.copy_from_slice(&digest.finalize().to_be_bytes());
|
self.buf[self.full_len - 2..self.full_len]
|
||||||
|
.copy_from_slice(&digest.finalize().to_be_bytes());
|
||||||
|
}
|
||||||
self.full_len
|
self.full_len
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,11 +713,23 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> {
|
|||||||
///
|
///
|
||||||
/// Returns the length WITHOUT the CRC16.
|
/// Returns the length WITHOUT the CRC16.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn finalize_no_crc(self) -> usize {
|
pub fn finalize_no_checksum(self) -> usize {
|
||||||
self.full_len - 2
|
if self.has_checksum {
|
||||||
|
self.full_len - 2
|
||||||
|
} else {
|
||||||
|
self.full_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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.
|
||||||
///
|
///
|
||||||
@@ -684,7 +751,8 @@ 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,
|
// CRC-16-CCITT checksum.
|
||||||
|
checksum: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'raw_data> PusTmReader<'raw_data> {
|
impl<'raw_data> PusTmReader<'raw_data> {
|
||||||
@@ -692,27 +760,51 @@ impl<'raw_data> PusTmReader<'raw_data> {
|
|||||||
/// the instance and the found byte length of the packet. The timestamp length needs to be
|
/// the instance and the found byte length of the packet. The timestamp length needs to be
|
||||||
/// known beforehand.
|
/// known beforehand.
|
||||||
///
|
///
|
||||||
/// This function will check the CRC-16 of the PUS packet and will return an appropriate
|
/// This function will verify the CRC-16-CCITT 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(slice: &'raw_data [u8], timestamp_len: usize) -> Result<Self, PusError> {
|
||||||
|
Self::new_no_checksum_verification(
|
||||||
|
slice,
|
||||||
|
ReaderConfig {
|
||||||
|
timestamp_len,
|
||||||
|
has_checksum: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
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 {
|
||||||
@@ -747,16 +839,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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -776,8 +877,8 @@ impl<'raw_data> PusTmReader<'raw_data> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn crc16(&self) -> u16 {
|
pub fn checksum(&self) -> Option<u16> {
|
||||||
self.crc16
|
self.checksum
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function will return the slice [Self] was constructed from.
|
/// This function will return the slice [Self] was constructed from.
|
||||||
@@ -792,7 +893,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 == other.checksum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,14 +911,19 @@ impl PusPacket for PusTmReader<'_> {
|
|||||||
fn subservice(&self) -> u8;
|
fn subservice(&self) -> u8;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn has_checksum(&self) -> bool {
|
||||||
|
self.checksum.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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -869,6 +975,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> {
|
||||||
@@ -877,9 +984,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();
|
||||||
@@ -889,6 +1000,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)
|
||||||
}
|
}
|
||||||
@@ -953,9 +1065,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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,6 +1106,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]
|
||||||
@@ -999,12 +1118,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()
|
||||||
@@ -1056,18 +1183,48 @@ 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 base_ping_reply_full_ctor_no_checksum<'a, 'b>(timestamp: &'a [u8]) -> PusTmCreator<'a, 'b> {
|
||||||
|
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
|
||||||
|
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
|
||||||
|
PusTmCreator::new_no_source_data(
|
||||||
|
sph,
|
||||||
|
tm_header,
|
||||||
|
CreatorConfig {
|
||||||
|
set_ccsds_len: true,
|
||||||
|
has_checksum: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
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 base_hk_reply_no_checksum<'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 tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp);
|
||||||
|
PusTmCreator::new(
|
||||||
|
sph,
|
||||||
|
tc_header,
|
||||||
|
src_data,
|
||||||
|
CreatorConfig {
|
||||||
|
set_ccsds_len: true,
|
||||||
|
has_checksum: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dummy_timestamp() -> &'static [u8] {
|
fn dummy_timestamp() -> &'static [u8] {
|
||||||
@@ -1080,14 +1237,28 @@ mod tests {
|
|||||||
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
verify_ping_reply(&pus_tm, false, 22, dummy_timestamp());
|
verify_ping_reply(&pus_tm, false, 22, dummy_timestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_basic_no_checksum() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let pus_tm = base_ping_reply_full_ctor_no_checksum(timestamp);
|
||||||
|
verify_ping_reply(&pus_tm, false, 20, dummy_timestamp());
|
||||||
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_basic_simple_api() {
|
fn test_basic_simple_api() {
|
||||||
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]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1100,7 +1271,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, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1110,29 +1281,47 @@ 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(), &[]);
|
||||||
let ser_len = pus_tm.finalize();
|
let ser_len = pus_tm.finalize();
|
||||||
assert_eq!(ser_len, 22);
|
assert_eq!(ser_len, 22);
|
||||||
verify_raw_ping_reply(None, &buf);
|
verify_raw_ping_reply(None, &buf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization_no_source_data_alt_ctor_no_crc() {
|
fn test_serialization_no_source_data_alt_ctor_no_checksum_verification() {
|
||||||
let timestamp = dummy_timestamp();
|
let timestamp = dummy_timestamp();
|
||||||
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);
|
||||||
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(), &[]);
|
||||||
let ser_len = pus_tm.finalize_no_crc();
|
let ser_len = pus_tm.finalize_no_checksum();
|
||||||
assert_eq!(ser_len, 20);
|
assert_eq!(ser_len, 20);
|
||||||
verify_raw_ping_reply_no_crc(&buf);
|
verify_raw_ping_reply_no_checksum(&buf, 22);
|
||||||
|
assert_eq!(buf[20], 0);
|
||||||
|
assert_eq!(buf[21], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization_no_source_data_alt_ctor_no_checksum() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap();
|
||||||
|
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp);
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let mut pus_tm =
|
||||||
|
PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tm_header, 0, false).unwrap();
|
||||||
|
assert_eq!(pus_tm.source_data_len(), 0);
|
||||||
|
assert_eq!(pus_tm.source_data(), &[]);
|
||||||
|
assert_eq!(pus_tm.source_data_mut(), &[]);
|
||||||
|
let ser_len = pus_tm.finalize_no_checksum();
|
||||||
|
assert_eq!(ser_len, 20);
|
||||||
|
verify_raw_ping_reply_no_checksum(&buf, 20);
|
||||||
assert_eq!(buf[20], 0);
|
assert_eq!(buf[20], 0);
|
||||||
assert_eq!(buf[21], 0);
|
assert_eq!(buf[21], 0);
|
||||||
}
|
}
|
||||||
@@ -1146,7 +1335,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, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1174,6 +1363,24 @@ mod tests {
|
|||||||
assert_eq!(buf[20], 1);
|
assert_eq!(buf[20], 1);
|
||||||
assert_eq!(buf[21], 2);
|
assert_eq!(buf[21], 2);
|
||||||
assert_eq!(buf[22], 3);
|
assert_eq!(buf[22], 3);
|
||||||
|
let crc16 = u16::from_be_bytes([buf[23], buf[24]]);
|
||||||
|
assert_eq!(crc16, hk_reply.checksum().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialization_with_source_data_no_checksum() {
|
||||||
|
let src_data = [1, 2, 3];
|
||||||
|
let hk_reply = base_hk_reply_no_checksum(dummy_timestamp(), &src_data);
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let ser_len = hk_reply
|
||||||
|
.write_to_bytes(&mut buf)
|
||||||
|
.expect("Serialization failed");
|
||||||
|
assert_eq!(ser_len, 23);
|
||||||
|
assert_eq!(buf[20], 1);
|
||||||
|
assert_eq!(buf[21], 2);
|
||||||
|
assert_eq!(buf[22], 3);
|
||||||
|
let crc16 = u16::from_be_bytes([buf[23], buf[24]]);
|
||||||
|
assert_eq!(crc16, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1183,7 +1390,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]);
|
||||||
@@ -1203,13 +1410,13 @@ 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]);
|
||||||
let source_data_mut = hk_reply_unwritten.source_data_mut();
|
let source_data_mut = hk_reply_unwritten.source_data_mut();
|
||||||
source_data_mut.copy_from_slice(src_data);
|
source_data_mut.copy_from_slice(src_data);
|
||||||
let ser_len = hk_reply_unwritten.finalize_crc_no_table();
|
let ser_len = hk_reply_unwritten.finalize_checksum_no_table();
|
||||||
assert_eq!(ser_len, 25);
|
assert_eq!(ser_len, 25);
|
||||||
assert_eq!(buf[20], 1);
|
assert_eq!(buf[20], 1);
|
||||||
assert_eq!(buf[21], 2);
|
assert_eq!(buf[21], 2);
|
||||||
@@ -1255,7 +1462,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());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1271,10 +1481,42 @@ 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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialization_with_source_data() {
|
||||||
|
let src_data = [4, 3, 2, 1];
|
||||||
|
let reply = base_hk_reply(dummy_timestamp(), &src_data);
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let ser_len =
|
||||||
|
WritablePusPacket::write_to_bytes(&reply, &mut buf).expect("Serialization failed");
|
||||||
|
assert_eq!(ser_len, 26);
|
||||||
|
let tm_deserialized = PusTmReader::new(&buf, 7).expect("Deserialization failed");
|
||||||
|
assert_eq!(ser_len, tm_deserialized.packet_len());
|
||||||
|
assert_eq!(tm_deserialized.user_data(), src_data);
|
||||||
|
assert_eq!(reply.checksum(), tm_deserialized.checksum());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deserialization_with_source_data_no_checksum() {
|
||||||
|
let src_data = [4, 3, 2, 1];
|
||||||
|
let reply = base_hk_reply_no_checksum(dummy_timestamp(), &src_data);
|
||||||
|
let mut buf: [u8; 32] = [0; 32];
|
||||||
|
let ser_len =
|
||||||
|
WritablePusPacket::write_to_bytes(&reply, &mut buf).expect("Serialization failed");
|
||||||
|
assert_eq!(ser_len, 24);
|
||||||
|
let tm_deserialized =
|
||||||
|
PusTmReader::new_no_checksum(&buf, 7).expect("Deserialization failed");
|
||||||
|
assert_eq!(ser_len, tm_deserialized.packet_len());
|
||||||
|
assert_eq!(tm_deserialized.user_data(), src_data);
|
||||||
|
assert_eq!(reply.checksum(), tm_deserialized.checksum());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialization_no_table() {
|
fn test_deserialization_no_table() {
|
||||||
let timestamp = dummy_timestamp();
|
let timestamp = dummy_timestamp();
|
||||||
@@ -1285,11 +1527,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());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1320,7 +1565,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];
|
||||||
@@ -1359,7 +1611,19 @@ 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(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
fn test_append_to_vec_no_checksum() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let pus_tm = base_ping_reply_full_ctor_no_checksum(timestamp);
|
||||||
|
let mut vec = Vec::new();
|
||||||
|
let res = pus_tm.append_to_vec(&mut vec);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
assert_eq!(res.unwrap(), 20);
|
||||||
|
verify_raw_ping_reply(pus_tm.checksum(), vec.as_slice(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1375,7 +1639,7 @@ mod tests {
|
|||||||
assert_eq!(vec.len(), 26);
|
assert_eq!(vec.len(), 26);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_raw_ping_reply_no_crc(buf: &[u8]) {
|
fn verify_raw_ping_reply_no_checksum(buf: &[u8], expected_len: usize) {
|
||||||
// Secondary header is set -> 0b0000_1001 , APID occupies last bit of first byte
|
// Secondary header is set -> 0b0000_1001 , APID occupies last bit of first byte
|
||||||
assert_eq!(buf[0], 0x09);
|
assert_eq!(buf[0], 0x09);
|
||||||
// Rest of APID 0x123
|
// Rest of APID 0x123
|
||||||
@@ -1383,7 +1647,10 @@ mod tests {
|
|||||||
// Unsegmented is the default, and first byte of 0x234 occupies this byte as well
|
// Unsegmented is the default, and first byte of 0x234 occupies this byte as well
|
||||||
assert_eq!(buf[2], 0xc2);
|
assert_eq!(buf[2], 0xc2);
|
||||||
assert_eq!(buf[3], 0x34);
|
assert_eq!(buf[3], 0x34);
|
||||||
assert_eq!(((buf[4] as u16) << 8) | buf[5] as u16, 15);
|
assert_eq!(
|
||||||
|
(((buf[4] as u16) << 8) | buf[5] as u16) as usize,
|
||||||
|
expected_len - 7
|
||||||
|
);
|
||||||
// SC time ref status is 0
|
// SC time ref status is 0
|
||||||
assert_eq!(buf[6], (PusC as u8) << 4);
|
assert_eq!(buf[6], (PusC as u8) << 4);
|
||||||
assert_eq!(buf[7], 17);
|
assert_eq!(buf[7], 17);
|
||||||
@@ -1398,14 +1665,22 @@ mod tests {
|
|||||||
assert_eq!(&buf[13..20], dummy_timestamp());
|
assert_eq!(&buf[13..20], dummy_timestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_raw_ping_reply(crc16: Option<u16>, buf: &[u8]) {
|
fn verify_raw_ping_reply(crc16: Option<u16>, buf: &[u8], has_checksum: bool) {
|
||||||
verify_raw_ping_reply_no_crc(buf);
|
if !has_checksum {
|
||||||
let mut digest = CRC_CCITT_FALSE.digest();
|
verify_raw_ping_reply_no_checksum(buf, 20);
|
||||||
digest.update(&buf[0..20]);
|
if buf.len() > 20 {
|
||||||
let crc16_calced = digest.finalize();
|
let crc16_read = u16::from_be_bytes([buf[20], buf[21]]);
|
||||||
let crc16_read = u16::from_be_bytes([buf[20], buf[21]]);
|
assert_eq!(crc16_read, 0);
|
||||||
assert_eq!(crc16_read, crc16_calced);
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
verify_raw_ping_reply_no_checksum(buf, 22);
|
||||||
if let Some(crc16) = crc16 {
|
if let Some(crc16) = crc16 {
|
||||||
|
let mut digest = CRC_CCITT_FALSE.digest();
|
||||||
|
digest.update(&buf[0..20]);
|
||||||
|
let crc16_calced = digest.finalize();
|
||||||
|
let crc16_read = u16::from_be_bytes([buf[20], buf[21]]);
|
||||||
|
assert_eq!(crc16_read, crc16_calced);
|
||||||
assert_eq!(((crc16 >> 8) & 0xff) as u8, buf[20]);
|
assert_eq!(((crc16 >> 8) & 0xff) as u8, buf[20]);
|
||||||
assert_eq!((crc16 & 0xff) as u8, buf[21]);
|
assert_eq!((crc16 & 0xff) as u8, buf[21]);
|
||||||
}
|
}
|
||||||
@@ -1486,7 +1761,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);
|
||||||
@@ -1511,7 +1786,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);
|
||||||
@@ -1531,7 +1806,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);
|
||||||
@@ -1545,7 +1820,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();
|
||||||
@@ -1617,9 +1892,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();
|
||||||
@@ -1632,9 +1914,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();
|
||||||
|
|||||||
@@ -508,8 +508,14 @@ impl WritablePusPacket for PusTmCreator<'_, '_> {
|
|||||||
fn len_written(&self) -> usize {
|
fn len_written(&self) -> usize {
|
||||||
CCSDS_HEADER_LEN + self.sec_header.written_len() + self.source_data.len() + 2
|
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.
|
/// Write the raw PUS byte representation to a provided buffer.
|
||||||
fn write_to_bytes_no_crc(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_no_checksum(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
Ok(Self::write_to_bytes_no_crc(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,7 +523,7 @@ impl WritablePusPacket for PusTmCreator<'_, '_> {
|
|||||||
Ok(Self::write_to_bytes(self, slice)?)
|
Ok(Self::write_to_bytes(self, slice)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_bytes_crc_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result<usize, PusError> {
|
||||||
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
Ok(Self::write_to_bytes_crc_no_table(self, slice)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -789,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)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -853,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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1117,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()
|
||||||
@@ -1244,7 +1250,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]
|
||||||
@@ -1262,7 +1268,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]
|
||||||
@@ -1280,7 +1286,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]
|
||||||
@@ -1298,7 +1304,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]
|
||||||
@@ -1344,7 +1350,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]
|
||||||
@@ -1453,7 +1459,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1484,7 +1490,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,
|
||||||
@@ -1556,7 +1562,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1574,7 +1580,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1644,7 +1650,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]
|
||||||
@@ -1881,7 +1887,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
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();
|
||||||
|
|||||||
Reference in New Issue
Block a user