Compare commits
18 Commits
b55fe9f443
...
v0.5.2
Author | SHA1 | Date | |
---|---|---|---|
6a9bd8135d | |||
b6df5fb4d1 | |||
9108a4ec68 | |||
2b33f811eb | |||
5d39cef6a0 | |||
8970ac7bc5 | |||
6c5f454728 | |||
ea4b6c9cba | |||
5e9af9c226 | |||
ad8e50c614 | |||
db1918e2ca | |||
0079e5d758 | |||
34bf9780af | |||
5b021fec22 | |||
be1c97b75a | |||
1db64256fc | |||
a268903105 | |||
0ce2568028 |
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Rust
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
|
||||||
|
# CLion
|
||||||
|
/.idea/*
|
||||||
|
!/.idea/runConfigurations
|
15
CHANGELOG.md
15
CHANGELOG.md
@ -8,6 +8,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
# [unreleased]
|
# [unreleased]
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Added `.gitignore`.
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Correct implementation of Trait `PartialEq` for `PusTc` and `PusTm`. The previous auto-derivation
|
||||||
|
were incorrect because they also compared fields unrelated to the raw byte representation.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Renamed `PusTc` `raw` method to `raw_bytes` and add better docs to avoid confusion.
|
||||||
|
Deprecate `raw` to avoid breaking change.
|
||||||
|
- Added `raw_bytes` method to `PusTm`.
|
||||||
|
|
||||||
# [v0.5.1] 2023-01-22
|
# [v0.5.1] 2023-01-22
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "spacepackets"
|
name = "spacepackets"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.60"
|
rust-version = "1.60"
|
||||||
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
authors = ["Robin Mueller <muellerr@irs.uni-stuttgart.de>"]
|
||||||
@ -15,7 +15,7 @@ categories = ["aerospace", "aerospace::space-protocols", "no-std", "hardware-sup
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
zerocopy = "0.6"
|
zerocopy = "0.6"
|
||||||
crc = "3"
|
crc = "3"
|
||||||
delegate = "0.8"
|
delegate = ">=0.8, <0.10"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1"
|
version = "1"
|
||||||
|
2
NOTICE
2
NOTICE
@ -1,3 +1,3 @@
|
|||||||
Generic implementations for various CCSDS and ECSS packet standards.
|
Generic implementations for various CCSDS and ECSS packet standards.
|
||||||
|
|
||||||
This software contains code developed at the University of Stuttgart.
|
This software contains code developed at the University of Stuttgart's Institute of Space Systems.
|
||||||
|
12
src/ecss.rs
12
src/ecss.rs
@ -1,5 +1,8 @@
|
|||||||
//! Common definitions and helpers required to create PUS TMTC packets according to
|
//! Common definitions and helpers required to create PUS TMTC packets according to
|
||||||
//! [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/)
|
//! [ECSS-E-ST-70-41C](https://ecss.nl/standard/ecss-e-st-70-41c-space-engineering-telemetry-and-telecommand-packet-utilization-15-april-2016/)
|
||||||
|
//!
|
||||||
|
//! You can find the PUS telecommand definitions in the [crate::tc] module and ithe PUS telemetry definitions
|
||||||
|
//! inside the [crate::tm] module.
|
||||||
use crate::{ByteConversionError, CcsdsPacket, SizeMissmatch};
|
use crate::{ByteConversionError, CcsdsPacket, SizeMissmatch};
|
||||||
use core::fmt::{Debug, Display, Formatter};
|
use core::fmt::{Debug, Display, Formatter};
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
@ -119,16 +122,15 @@ impl Display for PusError {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
PusError::VersionNotSupported(v) => {
|
PusError::VersionNotSupported(v) => {
|
||||||
write!(f, "PUS version {:?} not supported", v)
|
write!(f, "PUS version {v:?} not supported")
|
||||||
}
|
}
|
||||||
PusError::IncorrectCrc(crc) => {
|
PusError::IncorrectCrc(crc) => {
|
||||||
write!(f, "crc16 {:#04x} is incorrect", crc)
|
write!(f, "crc16 {crc:#04x} is incorrect")
|
||||||
}
|
}
|
||||||
PusError::RawDataTooShort(size) => {
|
PusError::RawDataTooShort(size) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"deserialization error, provided raw data with size {} too short",
|
"deserialization error, provided raw data with size {size} too short"
|
||||||
size
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
PusError::NoRawData => {
|
PusError::NoRawData => {
|
||||||
@ -138,7 +140,7 @@ impl Display for PusError {
|
|||||||
write!(f, "crc16 was not calculated")
|
write!(f, "crc16 was not calculated")
|
||||||
}
|
}
|
||||||
PusError::ByteConversionError(e) => {
|
PusError::ByteConversionError(e) => {
|
||||||
write!(f, "low level byte conversion error: {}", e)
|
write!(f, "low level byte conversion error: {e}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
59
src/tc.rs
59
src/tc.rs
@ -205,29 +205,35 @@ impl PusTcSecondaryHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This class models a PUS telecommand. It is the primary data structure to generate the raw byte
|
/// This class models the PUS C telecommand packet. It is the primary data structure to generate the
|
||||||
/// representation of a PUS telecommand or to deserialize from one from raw bytes.
|
/// raw byte representation of a PUS telecommand or to deserialize from one from raw bytes.
|
||||||
///
|
///
|
||||||
/// This class also derives the [serde::Serialize] and [serde::Deserialize] trait if the
|
/// This class also derives the [serde::Serialize] and [serde::Deserialize] trait if the
|
||||||
/// [serde] feature is used, which allows to send around TC packets in a raw byte format using a
|
/// [serde] feature is used, which allows to send around TC packets in a raw byte format using a
|
||||||
/// serde provider like [postcard](https://docs.rs/postcard/latest/postcard/).
|
/// serde provider like [postcard](https://docs.rs/postcard/latest/postcard/).
|
||||||
///
|
///
|
||||||
/// There is no spare bytes support yet.
|
/// There is no spare bytes support yet.
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
///
|
||||||
|
/// # Lifetimes
|
||||||
|
///
|
||||||
|
/// * `'raw_data` - If the TC is not constructed from a raw slice, this will be the life time of
|
||||||
|
/// a buffer where the user provided application data will be serialized into. If it
|
||||||
|
/// is, this is the lifetime of the raw byte slice it is constructed from.
|
||||||
|
#[derive(Eq, Copy, Clone, Debug)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct PusTc<'app_data> {
|
pub struct PusTc<'raw_data> {
|
||||||
sp_header: SpHeader,
|
sp_header: SpHeader,
|
||||||
pub sec_header: PusTcSecondaryHeader,
|
pub sec_header: PusTcSecondaryHeader,
|
||||||
/// If this is set to false, a manual call to [PusTc::calc_own_crc16] or
|
/// If this is set to false, a manual call to [PusTc::calc_own_crc16] or
|
||||||
/// [PusTc::update_packet_fields] is necessary for the serialized or cached CRC16 to be valid.
|
/// [PusTc::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,
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
raw_data: Option<&'app_data [u8]>,
|
raw_data: Option<&'raw_data [u8]>,
|
||||||
app_data: Option<&'app_data [u8]>,
|
app_data: Option<&'raw_data [u8]>,
|
||||||
crc16: Option<u16>,
|
crc16: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'app_data> PusTc<'app_data> {
|
impl<'raw_data> PusTc<'raw_data> {
|
||||||
/// Generates a new struct instance.
|
/// Generates a new struct instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@ -243,7 +249,7 @@ impl<'app_data> PusTc<'app_data> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
sp_header: &mut SpHeader,
|
sp_header: &mut SpHeader,
|
||||||
sec_header: PusTcSecondaryHeader,
|
sec_header: PusTcSecondaryHeader,
|
||||||
app_data: Option<&'app_data [u8]>,
|
app_data: Option<&'raw_data [u8]>,
|
||||||
set_ccsds_len: bool,
|
set_ccsds_len: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
sp_header.set_packet_type(PacketType::Tc);
|
sp_header.set_packet_type(PacketType::Tc);
|
||||||
@ -268,7 +274,7 @@ impl<'app_data> PusTc<'app_data> {
|
|||||||
sph: &mut SpHeader,
|
sph: &mut SpHeader,
|
||||||
service: u8,
|
service: u8,
|
||||||
subservice: u8,
|
subservice: u8,
|
||||||
app_data: Option<&'app_data [u8]>,
|
app_data: Option<&'raw_data [u8]>,
|
||||||
set_ccsds_len: bool,
|
set_ccsds_len: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
@ -405,7 +411,7 @@ impl<'app_data> PusTc<'app_data> {
|
|||||||
|
|
||||||
/// Create a [PusTc] instance from a raw slice. On success, it returns a tuple containing
|
/// Create a [PusTc] instance from a raw slice. On success, it returns a tuple containing
|
||||||
/// the instance and the found byte length of the packet.
|
/// the instance and the found byte length of the packet.
|
||||||
pub fn from_bytes(slice: &'app_data [u8]) -> Result<(Self, usize), PusError> {
|
pub fn from_bytes(slice: &'raw_data [u8]) -> Result<(Self, usize), 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(PusError::RawDataTooShort(raw_data_len));
|
return Err(PusError::RawDataTooShort(raw_data_len));
|
||||||
@ -435,11 +441,26 @@ impl<'app_data> PusTc<'app_data> {
|
|||||||
Ok((pus_tc, total_len))
|
Ok((pus_tc, total_len))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&self) -> Option<&'app_data [u8]> {
|
#[deprecated(since = "0.5.2", note = "use raw_bytes() instead")]
|
||||||
|
pub fn raw(&self) -> Option<&'raw_data [u8]> {
|
||||||
|
self.raw_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If [Self] was constructed [Self::from_bytes], this function will return the slice it was
|
||||||
|
/// constructed from. Otherwise, [None] will be returned.
|
||||||
|
pub fn raw_bytes(&self) -> Option<&'raw_data [u8]> {
|
||||||
self.raw_data
|
self.raw_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PusTc<'_> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.sp_header == other.sp_header
|
||||||
|
&& self.sec_header == other.sec_header
|
||||||
|
&& self.app_data == other.app_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//noinspection RsTraitImplementation
|
//noinspection RsTraitImplementation
|
||||||
impl CcsdsPacket for PusTc<'_> {
|
impl CcsdsPacket for PusTc<'_> {
|
||||||
ccsds_impl!();
|
ccsds_impl!();
|
||||||
@ -736,4 +757,20 @@ mod tests {
|
|||||||
assert_eq!(slice[11], 0xee);
|
assert_eq!(slice[11], 0xee);
|
||||||
assert_eq!(slice[12], 0x63);
|
assert_eq!(slice[12], 0x63);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_eq_pus_tc() {
|
||||||
|
// new vs new simple
|
||||||
|
let pus_tc_1 = base_ping_tc_simple_ctor();
|
||||||
|
let pus_tc_2 = base_ping_tc_full_ctor();
|
||||||
|
assert_eq!(pus_tc_1, pus_tc_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_eq_serialized_vs_derialized() {
|
||||||
|
let pus_tc = base_ping_tc_simple_ctor();
|
||||||
|
let mut buf = [0; 32];
|
||||||
|
pus_tc.write_to_bytes(&mut buf).unwrap();
|
||||||
|
assert_eq!(pus_tc, PusTc::from_bytes(&buf).unwrap().0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,13 +84,12 @@ impl Display for CdsError {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
CdsError::InvalidCcsdsDays(days) => {
|
CdsError::InvalidCcsdsDays(days) => {
|
||||||
write!(f, "invalid ccsds days {}", days)
|
write!(f, "invalid ccsds days {days}")
|
||||||
}
|
}
|
||||||
CdsError::InvalidCtorForDaysOfLenInPreamble(length_of_day) => {
|
CdsError::InvalidCtorForDaysOfLenInPreamble(length_of_day) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"wrong constructor for length of day {:?} detected in preamble",
|
"wrong constructor for length of day {length_of_day:?} detected in preamble",
|
||||||
length_of_day
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,16 +103,16 @@ impl Display for CucError {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
CucError::InvalidCounterWidth(w) => {
|
CucError::InvalidCounterWidth(w) => {
|
||||||
write!(f, "invalid cuc counter byte width {}", w)
|
write!(f, "invalid cuc counter byte width {w}")
|
||||||
}
|
}
|
||||||
CucError::InvalidFractionResolution(w) => {
|
CucError::InvalidFractionResolution(w) => {
|
||||||
write!(f, "invalid cuc fractional part byte width {:?}", w)
|
write!(f, "invalid cuc fractional part byte width {w:?}")
|
||||||
}
|
}
|
||||||
CucError::InvalidCounter(w, c) => {
|
CucError::InvalidCounter(w, c) => {
|
||||||
write!(f, "invalid cuc counter {} for width {}", c, w)
|
write!(f, "invalid cuc counter {c} for width {w}")
|
||||||
}
|
}
|
||||||
CucError::InvalidFractions(w, c) => {
|
CucError::InvalidFractions(w, c) => {
|
||||||
write!(f, "invalid cuc fractional part {} for width {:?}", c, w)
|
write!(f, "invalid cuc fractional part {c} for width {w:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,21 +111,20 @@ impl Display for TimestampError {
|
|||||||
TimestampError::InvalidTimeCode(time_code, raw_val) => {
|
TimestampError::InvalidTimeCode(time_code, raw_val) => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"invalid raw time code value {} for time code {:?}",
|
"invalid raw time code value {raw_val} for time code {time_code:?}"
|
||||||
raw_val, time_code
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TimestampError::CdsError(e) => {
|
TimestampError::CdsError(e) => {
|
||||||
write!(f, "cds error {}", e)
|
write!(f, "cds error {e}")
|
||||||
}
|
}
|
||||||
TimestampError::CucError(e) => {
|
TimestampError::CucError(e) => {
|
||||||
write!(f, "cuc error {}", e)
|
write!(f, "cuc error {e}")
|
||||||
}
|
}
|
||||||
TimestampError::ByteConversionError(e) => {
|
TimestampError::ByteConversionError(e) => {
|
||||||
write!(f, "byte conversion error {}", e)
|
write!(f, "byte conversion error {e}")
|
||||||
}
|
}
|
||||||
TimestampError::DateBeforeCcsdsEpoch(e) => {
|
TimestampError::DateBeforeCcsdsEpoch(e) => {
|
||||||
write!(f, "datetime with date before ccsds epoch: {}", e)
|
write!(f, "datetime with date before ccsds epoch: {e}")
|
||||||
}
|
}
|
||||||
TimestampError::CustomEpochNotSupported => {
|
TimestampError::CustomEpochNotSupported => {
|
||||||
write!(f, "custom epochs are not supported")
|
write!(f, "custom epochs are not supported")
|
||||||
|
67
src/tm.rs
67
src/tm.rs
@ -189,9 +189,8 @@ impl<'slice> TryFrom<zc::PusTmSecHeader<'slice>> for PusTmSecondaryHeader<'slice
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This class models a PUS telemetry and which can also be used. It is the primary data
|
/// This class models the PUS C telemetry packet. It is the primary data structure to generate the
|
||||||
/// structure to generate the raw byte representation of PUS telemetry or to
|
/// raw byte representation of PUS telemetry or to deserialize from one from raw bytes.
|
||||||
/// deserialize from one from raw bytes.
|
|
||||||
///
|
///
|
||||||
/// This class also derives the [serde::Serialize] and [serde::Deserialize] trait if the [serde]
|
/// This class also derives the [serde::Serialize] and [serde::Deserialize] trait if the [serde]
|
||||||
/// feature is used which allows to send around TM packets in a raw byte format using a serde
|
/// feature is used which allows to send around TM packets in a raw byte format using a serde
|
||||||
@ -201,23 +200,24 @@ impl<'slice> TryFrom<zc::PusTmSecHeader<'slice>> for PusTmSecondaryHeader<'slice
|
|||||||
///
|
///
|
||||||
/// # Lifetimes
|
/// # Lifetimes
|
||||||
///
|
///
|
||||||
/// * `'src_data` - Life time of a buffer where the user provided time stamp and source data will
|
/// * `'raw_data` - If the TM is not constructed from a raw slice, this will be the life time of
|
||||||
/// be serialized into.
|
/// a buffer where the user provided time stamp and source data will be serialized into. If it
|
||||||
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
|
/// is, this is the lifetime of the raw byte slice it is constructed from.
|
||||||
|
#[derive(Eq, Debug, Copy, Clone)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
pub struct PusTm<'src_data> {
|
pub struct PusTm<'raw_data> {
|
||||||
pub sp_header: SpHeader,
|
pub sp_header: SpHeader,
|
||||||
pub sec_header: PusTmSecondaryHeader<'src_data>,
|
pub sec_header: PusTmSecondaryHeader<'raw_data>,
|
||||||
/// If this is set to false, a manual call to [PusTm::calc_own_crc16] or
|
/// If this is set to false, a manual call to [PusTm::calc_own_crc16] or
|
||||||
/// [PusTm::update_packet_fields] is necessary for the serialized or cached CRC16 to be valid.
|
/// [PusTm::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,
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
raw_data: Option<&'src_data [u8]>,
|
raw_data: Option<&'raw_data [u8]>,
|
||||||
source_data: Option<&'src_data [u8]>,
|
source_data: Option<&'raw_data [u8]>,
|
||||||
crc16: Option<u16>,
|
crc16: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src_data> PusTm<'src_data> {
|
impl<'raw_data> PusTm<'raw_data> {
|
||||||
/// Generates a new struct instance.
|
/// Generates a new struct instance.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
@ -232,8 +232,8 @@ impl<'src_data> PusTm<'src_data> {
|
|||||||
/// the correct value to this field manually
|
/// the correct value to this field manually
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sp_header: &mut SpHeader,
|
sp_header: &mut SpHeader,
|
||||||
sec_header: PusTmSecondaryHeader<'src_data>,
|
sec_header: PusTmSecondaryHeader<'raw_data>,
|
||||||
source_data: Option<&'src_data [u8]>,
|
source_data: Option<&'raw_data [u8]>,
|
||||||
set_ccsds_len: bool,
|
set_ccsds_len: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
sp_header.set_packet_type(PacketType::Tm);
|
sp_header.set_packet_type(PacketType::Tm);
|
||||||
@ -263,11 +263,11 @@ impl<'src_data> PusTm<'src_data> {
|
|||||||
length
|
length
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timestamp(&self) -> Option<&'src_data [u8]> {
|
pub fn timestamp(&self) -> Option<&'raw_data [u8]> {
|
||||||
self.sec_header.timestamp
|
self.sec_header.timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_data(&self) -> Option<&'src_data [u8]> {
|
pub fn source_data(&self) -> Option<&'raw_data [u8]> {
|
||||||
self.source_data
|
self.source_data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +402,7 @@ impl<'src_data> PusTm<'src_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.
|
||||||
pub fn from_bytes(
|
pub fn from_bytes(
|
||||||
slice: &'src_data [u8],
|
slice: &'raw_data [u8],
|
||||||
timestamp_len: usize,
|
timestamp_len: usize,
|
||||||
) -> Result<(Self, usize), PusError> {
|
) -> Result<(Self, usize), PusError> {
|
||||||
let raw_data_len = slice.len();
|
let raw_data_len = slice.len();
|
||||||
@ -442,6 +442,20 @@ impl<'src_data> PusTm<'src_data> {
|
|||||||
verify_crc16_from_raw(raw_data, pus_tm.crc16.expect("CRC16 invalid"))?;
|
verify_crc16_from_raw(raw_data, pus_tm.crc16.expect("CRC16 invalid"))?;
|
||||||
Ok((pus_tm, total_len))
|
Ok((pus_tm, total_len))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If [Self] was constructed [Self::from_bytes], this function will return the slice it was
|
||||||
|
/// constructed from. Otherwise, [None] will be returned.
|
||||||
|
pub fn raw_bytes(&self) -> Option<&'raw_data [u8]> {
|
||||||
|
self.raw_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PusTm<'_> {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.sp_header == other.sp_header
|
||||||
|
&& self.sec_header == other.sec_header
|
||||||
|
&& self.source_data == other.source_data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection RsTraitImplementation
|
//noinspection RsTraitImplementation
|
||||||
@ -486,8 +500,8 @@ mod tests {
|
|||||||
|
|
||||||
fn base_ping_reply_full_ctor(timestamp: &[u8]) -> PusTm {
|
fn base_ping_reply_full_ctor(timestamp: &[u8]) -> PusTm {
|
||||||
let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
|
let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap();
|
||||||
let tc_header = PusTmSecondaryHeader::new_simple(17, 2, ×tamp);
|
let tm_header = PusTmSecondaryHeader::new_simple(17, 2, ×tamp);
|
||||||
PusTm::new(&mut sph, tc_header, None, true)
|
PusTm::new(&mut sph, tm_header, None, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn base_hk_reply<'a>(timestamp: &'a [u8], src_data: &'a [u8]) -> PusTm<'a> {
|
fn base_hk_reply<'a>(timestamp: &'a [u8], src_data: &'a [u8]) -> PusTm<'a> {
|
||||||
@ -681,4 +695,21 @@ mod tests {
|
|||||||
assert_eq!(tm.msg_counter(), 0x0000);
|
assert_eq!(tm.msg_counter(), 0x0000);
|
||||||
assert_eq!(tm.sc_time_ref_status(), 0b0000);
|
assert_eq!(tm.sc_time_ref_status(), 0b0000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_eq_pus_tm() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let pus_tm_1 = base_ping_reply_full_ctor(timestamp);
|
||||||
|
let pus_tm_2 = base_ping_reply_full_ctor(timestamp);
|
||||||
|
assert_eq!(pus_tm_1, pus_tm_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_eq_serialized_vs_derialized() {
|
||||||
|
let timestamp = dummy_timestamp();
|
||||||
|
let pus_tm = base_ping_reply_full_ctor(timestamp);
|
||||||
|
let mut buf = [0; 32];
|
||||||
|
pus_tm.write_to_bytes(&mut buf).unwrap();
|
||||||
|
assert_eq!(pus_tm, PusTm::from_bytes(&buf, timestamp.len()).unwrap().0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user