From 938c4ba770a3968c8d5a852a3fa87727aad86c6b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Sun, 4 Dec 2022 12:17:36 +0100 Subject: [PATCH 01/10] make serde dependency optional --- Cargo.toml | 6 +++++- src/ecss.rs | 4 +++- src/lib.rs | 31 +++++++++++++++++++++++++------ src/tc.rs | 10 +++++++--- src/time.rs | 1 + src/tm.rs | 9 ++++++--- 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bec8709..7f28de4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ delegate = "0.8" [dependencies.serde] version = "1.0" +optional = true default-features = false features = ["derive"] @@ -32,8 +33,11 @@ default-features = false [dev-dependencies.postcard] version = "1.0" +[dev-dependencies.serde_json] +version = "1.0" + [features] -default = ["std"] +default = ["std", "serde"] std = ["chrono/std", "chrono/clock", "alloc"] alloc = ["postcard/alloc"] diff --git a/src/ecss.rs b/src/ecss.rs index a3cfb42..5df40dc 100644 --- a/src/ecss.rs +++ b/src/ecss.rs @@ -4,6 +4,7 @@ use crate::{ByteConversionError, CcsdsPacket, SizeMissmatch}; use core::fmt::Debug; use core::mem::size_of; use crc::{Crc, CRC_16_IBM_3740}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; pub type CrcType = u16; @@ -13,7 +14,8 @@ pub const CRC_CCITT_FALSE: Crc = Crc::::new(&CRC_16_IBM_3740); pub const CCSDS_HEADER_LEN: usize = size_of::(); /// All PUS versions. Only PUS C is supported by this library. -#[derive(PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Debug)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PusVersion { EsaPus = 0, PusA = 1, diff --git a/src/lib.rs b/src/lib.rs index f9b8840..63f219f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,7 @@ extern crate std; use crate::ecss::CCSDS_HEADER_LEN; use delegate::delegate; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; pub mod ecss; @@ -62,12 +63,14 @@ pub const MAX_APID: u16 = 2u16.pow(11) - 1; pub const MAX_SEQ_COUNT: u16 = 2u16.pow(14) - 1; #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SizeMissmatch { pub found: usize, pub expected: usize, } #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum ByteConversionError { /// The passed slice is too small. Returns the passed slice length and expected minimum size ToSliceTooSmall(SizeMissmatch), @@ -78,7 +81,8 @@ pub enum ByteConversionError { ZeroCopyFromError, } -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PacketType { Tm = 0, Tc = 1, @@ -100,7 +104,8 @@ pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType { PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap() } -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum SequenceFlags { ContinuationSegment = 0b00, FirstSegment = 0b01, @@ -124,7 +129,8 @@ impl TryFrom for SequenceFlags { } } -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PacketId { pub ptype: PacketType, pub sec_header_flag: bool, @@ -171,7 +177,8 @@ impl From for PacketId { } } -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PacketSequenceCtrl { pub seq_flags: SequenceFlags, seq_count: u16, @@ -318,7 +325,8 @@ pub trait CcsdsPrimaryHeader { /// 13 bits of the first two bytes of the raw header /// * `psc` - Packet Sequence Control, occupies the third and fourth byte of the raw header /// * `data_len` - Data length field occupies the fifth and the sixth byte of the raw header -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SpHeader { pub version: u8, pub packet_id: PacketId, @@ -550,6 +558,7 @@ mod tests { packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceCtrl, PacketType, SequenceFlags, }; + #[cfg(feature = "alloc")] use alloc::vec; #[cfg(not(feature = "std"))] use num::pow; @@ -558,6 +567,7 @@ mod tests { use postcard::from_bytes; #[cfg(feature = "alloc")] use postcard::to_allocvec; + use std::println; #[test] fn test_seq_flag_helpers() { @@ -640,7 +650,7 @@ mod tests { } #[test] - #[cfg(feature = "std")] + #[cfg(all(feature = "std", feature = "serde"))] fn test_serde_sph() { let sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); assert_eq!(sp_header.ccsds_version(), 0b000); @@ -763,4 +773,13 @@ mod tests { assert_eq!(sp_header.ptype(), PacketType::Tc); assert_eq!(sp_header.data_len(), 0); } + + #[test] + #[cfg(feature = "serde")] + fn test_serde_serialization() { + let sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); + let as_str = + serde_json::to_string(&sp_header).expect("Converting SP header to JSON string failed"); + println!("{:?}", as_str); + } } diff --git a/src/tc.rs b/src/tc.rs index a177ae8..b4d3a18 100644 --- a/src/tc.rs +++ b/src/tc.rs @@ -41,6 +41,7 @@ use crate::{ }; use core::mem::size_of; use delegate::delegate; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use zerocopy::AsBytes; @@ -136,7 +137,8 @@ pub mod zc { } } -#[derive(PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Debug)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PusTcSecondaryHeader { pub service: u8, pub subservice: u8, @@ -211,14 +213,15 @@ impl PusTcSecondaryHeader { /// [postcard](https://docs.rs/postcard/latest/postcard/). /// /// There is no spare bytes support yet. -#[derive(PartialEq, Eq, Copy, Clone, Serialize, Deserialize, Debug)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PusTc<'slice> { sp_header: SpHeader, pub sec_header: PusTcSecondaryHeader, /// 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. pub calc_crc_on_serialization: bool, - #[serde(skip)] + #[cfg_attr(feature = "serde", serde(skip))] raw_data: Option<&'slice [u8]>, app_data: Option<&'slice [u8]>, crc16: Option, @@ -480,6 +483,7 @@ mod tests { use crate::tc::{PusTc, PusTcSecondaryHeader, PusTcSecondaryHeaderT}; use crate::{ByteConversionError, SpHeader}; use crate::{CcsdsPacket, SequenceFlags}; + #[cfg(feature = "alloc")] use alloc::vec::Vec; fn base_ping_tc_full_ctor() -> PusTc<'static> { diff --git a/src/time.rs b/src/time.rs index 3d70783..20b5acd 100644 --- a/src/time.rs +++ b/src/time.rs @@ -272,6 +272,7 @@ mod tests { use super::*; use crate::time::TimestampError::{InvalidTimeCode, OtherPacketError}; use crate::ByteConversionError::{FromSliceTooSmall, ToSliceTooSmall}; + #[cfg(feature = "alloc")] use alloc::format; use chrono::{Datelike, Timelike}; diff --git a/src/tm.rs b/src/tm.rs index da40589..517ec5c 100644 --- a/src/tm.rs +++ b/src/tm.rs @@ -9,6 +9,7 @@ use crate::{ CCSDS_HEADER_LEN, }; use core::mem::size_of; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use zerocopy::AsBytes; @@ -104,7 +105,8 @@ pub mod zc { } } -#[derive(PartialEq, Eq, Serialize, Deserialize, Copy, Clone, Debug)] +#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PusTmSecondaryHeader<'slice> { pus_version: PusVersion, pub sc_time_ref_status: u8, @@ -198,14 +200,15 @@ impl<'slice> TryFrom> for PusTmSecondaryHeader<'slice /// [postcard](https://docs.rs/postcard/latest/postcard/). /// /// There is no spare bytes support yet. -#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct PusTm<'slice> { pub sp_header: SpHeader, pub sec_header: PusTmSecondaryHeader<'slice>, /// 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. pub calc_crc_on_serialization: bool, - #[serde(skip)] + #[cfg_attr(feature = "serde", serde(skip))] raw_data: Option<&'slice [u8]>, source_data: Option<&'slice [u8]>, crc16: Option, From aeb2e806b8b296c32aa162d1b431567283729dcd Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 17:11:44 +0100 Subject: [PATCH 02/10] move improvements --- CHANGELOG.md | 2 ++ Cargo.toml | 8 ++--- src/ecss.rs | 3 ++ src/lib.rs | 82 ++++++++++++++++++++++++++++------------------------ src/tc.rs | 26 ++++++++--------- src/time.rs | 45 +++++++++++++++++----------- src/tm.rs | 9 +++--- 7 files changed, 97 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 173148b..0e9270b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +## Changed + # [v0.3.1] 03.12.2022 - Small fix for faulty docs.rs build diff --git a/Cargo.toml b/Cargo.toml index 7f28de4..88ae8aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spacepackets" -version = "0.3.1" +version = "0.4.0" edition = "2021" authors = ["Robin Mueller "] description = "Generic implementations for various CCSDS and ECSS packet standards" @@ -33,12 +33,10 @@ default-features = false [dev-dependencies.postcard] version = "1.0" -[dev-dependencies.serde_json] -version = "1.0" - [features] -default = ["std", "serde"] +default = ["std", "dep:serde"] std = ["chrono/std", "chrono/clock", "alloc"] +serde = ["chrono/serde"] alloc = ["postcard/alloc"] [package.metadata.docs.rs] diff --git a/src/ecss.rs b/src/ecss.rs index 5df40dc..06e40f4 100644 --- a/src/ecss.rs +++ b/src/ecss.rs @@ -37,6 +37,7 @@ impl TryFrom for PusVersion { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PacketTypeCodes { Boolean = 1, Enumerated = 2, @@ -53,6 +54,7 @@ pub enum PacketTypeCodes { } #[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum PusError { VersionNotSupported(PusVersion), IncorrectCrc(u16), @@ -214,6 +216,7 @@ impl ToBeBytes for u64 { } #[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct GenericEcssEnumWrapper { val: TYPE, } diff --git a/src/lib.rs b/src/lib.rs index 63f219f..b45401b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,13 +138,22 @@ pub struct PacketId { } impl PacketId { - pub fn new(ptype: PacketType, sec_header_flag: bool, apid: u16) -> Option { - let mut pid = PacketId { + const fn const_new(ptype: PacketType, sec_header_flag: bool, apid: u16) -> PacketId { + if apid > MAX_APID { + panic!("APID too large"); + } + PacketId { ptype, sec_header_flag, - apid: 0, - }; - pid.set_apid(apid).then_some(pid) + apid, + } + } + + pub fn new(ptype: PacketType, sec_header_flag: bool, apid: u16) -> Option { + if apid > MAX_APID { + return None; + } + Some(PacketId::const_new(ptype, sec_header_flag, apid)) } /// Set a new Application Process ID (APID). If the passed number is invalid, the APID will @@ -185,20 +194,31 @@ pub struct PacketSequenceCtrl { } impl PacketSequenceCtrl { - /// Returns [None] if the passed sequence count exceeds [MAX_SEQ_COUNT] - pub fn new(seq_flags: SequenceFlags, seq_count: u16) -> Option { - let mut psc = PacketSequenceCtrl { + /// const variant of [PacketSequenceCtrl::new], but panics if the sequence count exceeds + /// [MAX_SEQ_COUNT]. + const fn const_new(seq_flags: SequenceFlags, seq_count: u16) -> PacketSequenceCtrl { + if seq_count > MAX_SEQ_COUNT { + panic!("Sequence count too large"); + } + PacketSequenceCtrl { seq_flags, - seq_count: 0, - }; - psc.set_seq_count(seq_count).then_some(psc) + seq_count, + } + } + + /// Returns [None] if the passed sequence count exceeds [MAX_SEQ_COUNT]. + pub fn new(seq_flags: SequenceFlags, seq_count: u16) -> Option { + if seq_count > MAX_SEQ_COUNT { + return None; + } + Some(PacketSequenceCtrl::const_new(seq_flags, seq_count)) } pub fn raw(&self) -> u16 { ((self.seq_flags as u16) << 14) | self.seq_count } /// Set a new sequence count. If the passed number is invalid, the sequence count will not be - /// set and false will be returned. The maximum allowed value for the 14-bit field is 16383 + /// set and false will be returned. The maximum allowed value for the 14-bit field is 16383. pub fn set_seq_count(&mut self, ssc: u16) -> bool { if ssc > MAX_SEQ_COUNT { return false; @@ -239,7 +259,7 @@ macro_rules! sph_from_other { const SSC_MASK: u16 = 0x3FFF; const VERSION_MASK: u16 = 0xE000; -/// Generic trait to access fields of a CCSDS space packet header according to CCSDS 133.0-B-2 +/// Generic trait to access fields of a CCSDS space packet header according to CCSDS 133.0-B-2. pub trait CcsdsPacket { fn ccsds_version(&self) -> u8; fn packet_id(&self) -> PacketId; @@ -253,7 +273,7 @@ pub trait CcsdsPacket { } /// Retrieve 13 bit Packet Identification field. Can usually be retrieved with a bitwise AND - /// of the first 2 bytes with 0x1FFF + /// of the first 2 bytes with 0x1FFF. #[inline] fn packet_id_raw(&self) -> u16 { self.packet_id().raw() @@ -264,8 +284,8 @@ pub trait CcsdsPacket { self.psc().raw() } + /// Retrieve Packet Type (TM: 0, TC: 1). #[inline] - /// Retrieve Packet Type (TM: 0, TC: 1) fn ptype(&self) -> PacketType { // This call should never fail because only 0 and 1 can be passed to the try_from call self.packet_id().ptype @@ -282,13 +302,13 @@ pub trait CcsdsPacket { } /// Retrieve the secondary header flag. Returns true if a secondary header is present - /// and false if it is not + /// and false if it is not. #[inline] fn sec_header_flag(&self) -> bool { self.packet_id().sec_header_flag } - /// Retrieve Application Process ID + /// Retrieve Application Process ID. #[inline] fn apid(&self) -> u16 { self.packet_id().apid @@ -316,7 +336,7 @@ pub trait CcsdsPrimaryHeader { ) -> Self; } -/// Space Packet Primary Header according to CCSDS 133.0-B-2 +/// Space Packet Primary Header according to CCSDS 133.0-B-2. /// /// # Arguments /// @@ -351,6 +371,7 @@ impl Default for SpHeader { } } } + impl SpHeader { /// Create a new Space Packet Header instance which can be used to create generic /// Space Packets. This will return [None] if the APID or sequence count argument @@ -549,25 +570,19 @@ pub mod zc { sph_from_other!(SpHeader, crate::SpHeader); } -#[cfg(test)] +#[cfg(all(test, feature = "std"))] mod tests { - #[cfg(feature = "std")] + #[cfg(feature = "serde")] use crate::CcsdsPrimaryHeader; use crate::SpHeader; use crate::{ packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceCtrl, PacketType, SequenceFlags, }; - #[cfg(feature = "alloc")] use alloc::vec; - #[cfg(not(feature = "std"))] - use num::pow; - #[cfg(feature = "std")] use num_traits::pow; - use postcard::from_bytes; - #[cfg(feature = "alloc")] - use postcard::to_allocvec; - use std::println; + #[cfg(feature = "serde")] + use postcard::{from_bytes, to_allocvec}; #[test] fn test_seq_flag_helpers() { @@ -650,7 +665,7 @@ mod tests { } #[test] - #[cfg(all(feature = "std", feature = "serde"))] + #[cfg(feature = "serde")] fn test_serde_sph() { let sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); assert_eq!(sp_header.ccsds_version(), 0b000); @@ -773,13 +788,4 @@ mod tests { assert_eq!(sp_header.ptype(), PacketType::Tc); assert_eq!(sp_header.data_len(), 0); } - - #[test] - #[cfg(feature = "serde")] - fn test_serde_serialization() { - let sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); - let as_str = - serde_json::to_string(&sp_header).expect("Converting SP header to JSON string failed"); - println!("{:?}", as_str); - } } diff --git a/src/tc.rs b/src/tc.rs index b4d3a18..d3aafec 100644 --- a/src/tc.rs +++ b/src/tc.rs @@ -67,7 +67,7 @@ pub const ACK_ALL: u8 = AckOpts::Acceptance as u8 | AckOpts::Progress as u8 | AckOpts::Completion as u8; -pub trait PusTcSecondaryHeaderT { +pub trait GenericPusTcSecondaryHeader { fn pus_version(&self) -> PusVersion; fn ack_flags(&self) -> u8; fn service(&self) -> u8; @@ -77,7 +77,7 @@ pub trait PusTcSecondaryHeaderT { pub mod zc { use crate::ecss::{PusError, PusVersion}; - use crate::tc::PusTcSecondaryHeaderT; + use crate::tc::GenericPusTcSecondaryHeader; use zerocopy::{AsBytes, FromBytes, NetworkEndian, Unaligned, U16}; #[derive(FromBytes, AsBytes, Unaligned)] @@ -104,7 +104,7 @@ pub mod zc { } } - impl PusTcSecondaryHeaderT for PusTcSecondaryHeader { + impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { fn pus_version(&self) -> PusVersion { PusVersion::try_from(self.version_ack >> 4 & 0b1111).unwrap_or(PusVersion::Invalid) } @@ -147,7 +147,7 @@ pub struct PusTcSecondaryHeader { pub version: PusVersion, } -impl PusTcSecondaryHeaderT for PusTcSecondaryHeader { +impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { fn pus_version(&self) -> PusVersion { self.version } @@ -263,7 +263,7 @@ impl<'slice> PusTc<'slice> { } /// Simplified version of the [PusTc::new] function which allows to only specify service and - /// subservice instead of the full PUS TC secondary header + /// subservice instead of the full PUS TC secondary header. pub fn new_simple( sph: &mut SpHeader, service: u8, @@ -306,7 +306,7 @@ impl<'slice> PusTc<'slice> { /// used. /// If this was not done or the application data is set or changed after construction, /// this function needs to be called to ensure that the data length field of the CCSDS header - /// is set correctly + /// is set correctly. pub fn update_ccsds_data_len(&mut self) { self.sp_header.data_len = self.len_packed() as u16 - size_of::() as u16 - 1; @@ -326,7 +326,7 @@ impl<'slice> PusTc<'slice> { self.crc16 = Some(digest.finalize()) } - /// This helper function calls both [PusTc.update_ccsds_data_len] and [PusTc.calc_own_crc16] + /// This helper function calls both [PusTc.update_ccsds_data_len] and [PusTc.calc_own_crc16]. pub fn update_packet_fields(&mut self) { self.update_ccsds_data_len(); self.calc_own_crc16(); @@ -404,7 +404,7 @@ impl<'slice> PusTc<'slice> { } /// 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: &'slice [u8]) -> Result<(Self, usize), PusError> { let raw_data_len = slice.len(); if raw_data_len < PUS_TC_MIN_LEN_WITHOUT_APP_DATA { @@ -465,7 +465,7 @@ impl PusPacket for PusTc<'_> { } //noinspection RsTraitImplementation -impl PusTcSecondaryHeaderT for PusTc<'_> { +impl GenericPusTcSecondaryHeader for PusTc<'_> { delegate!(to self.sec_header { fn pus_version(&self) -> PusVersion; fn service(&self) -> u8; @@ -475,15 +475,14 @@ impl PusTcSecondaryHeaderT for PusTc<'_> { }); } -#[cfg(test)] +#[cfg(all(test, feature = "std"))] mod tests { use crate::ecss::PusVersion::PusC; use crate::ecss::{PusError, PusPacket}; use crate::tc::ACK_ALL; - use crate::tc::{PusTc, PusTcSecondaryHeader, PusTcSecondaryHeaderT}; + use crate::tc::{GenericPusTcSecondaryHeader, PusTc, PusTcSecondaryHeader}; use crate::{ByteConversionError, SpHeader}; use crate::{CcsdsPacket, SequenceFlags}; - #[cfg(feature = "alloc")] use alloc::vec::Vec; fn base_ping_tc_full_ctor() -> PusTc<'static> { @@ -564,7 +563,6 @@ mod tests { } #[test] - #[cfg(feature = "alloc")] fn test_vec_ser_deser() { let pus_tc = base_ping_tc_simple_ctor(); let mut test_vec = Vec::new(); @@ -629,7 +627,7 @@ mod tests { } #[test] - fn test_write_buf_too_msall() { + fn test_write_buf_too_small() { let pus_tc = base_ping_tc_simple_ctor(); let mut test_buf = [0; 12]; let res = pus_tc.write_to_bytes(test_buf.as_mut_slice()); diff --git a/src/time.rs b/src/time.rs index 20b5acd..3fd0872 100644 --- a/src/time.rs +++ b/src/time.rs @@ -10,11 +10,15 @@ use crate::time::CcsdsTimeCodes::Cds; #[cfg(feature = "std")] use std::time::{SystemTime, SystemTimeError}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + pub const CDS_SHORT_LEN: usize = 7; pub const DAYS_CCSDS_TO_UNIX: i32 = -4383; pub const SECONDS_PER_DAY: u32 = 86400; #[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum CcsdsTimeCodes { None = 0, CucCcsdsEpoch = 0b001, @@ -23,7 +27,7 @@ pub enum CcsdsTimeCodes { Ccs = 0b101, } -const CDS_SHORT_P_FIELD: u8 = (CcsdsTimeCodes::Cds as u8) << 4; +const CDS_SHORT_P_FIELD: u8 = (Cds as u8) << 4; impl TryFrom for CcsdsTimeCodes { type Error = (); @@ -41,6 +45,7 @@ impl TryFrom for CcsdsTimeCodes { } #[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum TimestampError { /// Contains tuple where first value is the expected time code and the second /// value is the found raw value @@ -83,7 +88,7 @@ pub trait TimeReader { Self: Sized; } -/// Trait for generic CCSDS time providers +/// Trait for generic CCSDS time providers. pub trait CcsdsTimeProvider { fn len_as_bytes(&self) -> usize; @@ -112,12 +117,12 @@ pub trait CcsdsTimeProvider { /// timestamp_now.write_to_bytes(&mut raw_stamp).unwrap(); /// assert_eq!((raw_stamp[0] >> 4) & 0b111, Cds as u8); /// ``` -#[derive(Debug, Copy, Clone, Default)] +#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct CdsShortTimeProvider { ccsds_days: u16, ms_of_day: u32, unix_seconds: i64, - date_time: Option>, } impl CdsShortTimeProvider { @@ -126,7 +131,6 @@ impl CdsShortTimeProvider { ccsds_days, ms_of_day, unix_seconds: 0, - date_time: None, }; let unix_days_seconds = ccsds_to_unix_days(ccsds_days as i32) as i64 * SECONDS_PER_DAY as i64; @@ -146,7 +150,6 @@ impl CdsShortTimeProvider { as u16, ms_of_day: ms_of_day as u32, unix_seconds: 0, - date_time: None, }; Ok(provider.setup(unix_days_seconds as i64, ms_of_day)) } @@ -165,7 +168,6 @@ impl CdsShortTimeProvider { fn setup(mut self, unix_days_seconds: i64, ms_of_day: u64) -> Self { self.calc_unix_seconds(unix_days_seconds, ms_of_day); - self.calc_date_time((ms_of_day % 1000) as u32); self } @@ -193,14 +195,13 @@ impl CdsShortTimeProvider { } } - fn calc_date_time(&mut self, ms_since_last_second: u32) { + fn calc_date_time(&self, ms_since_last_second: u32) -> Option> { assert!(ms_since_last_second < 1000, "Invalid MS since last second"); let ns_since_last_sec = ms_since_last_second * 1e6 as u32; if let LocalResult::Single(val) = Utc.timestamp_opt(self.unix_seconds, ns_since_last_sec) { - self.date_time = Some(val); - } else { - self.date_time = None; + return Some(val); } + None } } @@ -222,7 +223,7 @@ impl CcsdsTimeProvider for CdsShortTimeProvider { } fn date_time(&self) -> Option> { - self.date_time + self.calc_date_time((self.ms_of_day % 1000) as u32) } } @@ -267,14 +268,16 @@ impl TimeReader for CdsShortTimeProvider { } } -#[cfg(test)] +#[cfg(all(test, feature = "std"))] mod tests { use super::*; use crate::time::TimestampError::{InvalidTimeCode, OtherPacketError}; use crate::ByteConversionError::{FromSliceTooSmall, ToSliceTooSmall}; - #[cfg(feature = "alloc")] use alloc::format; use chrono::{Datelike, Timelike}; + use postcard::from_bytes; + #[cfg(feature = "serde")] + use postcard::to_allocvec; #[test] fn test_creation() { @@ -282,7 +285,6 @@ mod tests { assert_eq!(ccsds_to_unix_days(0), DAYS_CCSDS_TO_UNIX); } - #[cfg(feature = "std")] #[test] fn test_get_current_time() { let sec_floats = seconds_since_epoch(); @@ -430,7 +432,6 @@ mod tests { assert_eq!(read_stamp.ms_of_day, u32::MAX - 1); } - #[cfg(feature = "std")] #[test] fn test_time_now() { let timestamp_now = CdsShortTimeProvider::from_now().unwrap(); @@ -456,7 +457,17 @@ mod tests { generic_dt_property_equality_check(dt.minute(), compare_stamp.minute(), 0, 59); } - #[cfg(feature = "std")] + #[test] + #[cfg(feature = "serde")] + fn test_serialization() { + let stamp_now = CdsShortTimeProvider::from_now().expect("Error retrieving time"); + let val = to_allocvec(&stamp_now).expect("Serializing timestamp failed"); + assert!(val.len() > 0); + let stamp_deser: CdsShortTimeProvider = + from_bytes(&val).expect("Stamp deserialization failed"); + assert_eq!(stamp_deser, stamp_now); + } + fn generic_dt_property_equality_check(first: u32, second: u32, start: u32, end: u32) { if second < first { assert_eq!(second, start); diff --git a/src/tm.rs b/src/tm.rs index 517ec5c..3c3fc3d 100644 --- a/src/tm.rs +++ b/src/tm.rs @@ -22,7 +22,7 @@ pub const PUC_TM_MIN_SEC_HEADER_LEN: usize = 7; pub const PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA: usize = CCSDS_HEADER_LEN + PUC_TM_MIN_SEC_HEADER_LEN + size_of::(); -pub trait PusTmSecondaryHeaderT { +pub trait GenericPusTmSecondaryHeader { fn pus_version(&self) -> PusVersion; fn sc_time_ref_status(&self) -> u8; fn service(&self) -> u8; @@ -32,6 +32,7 @@ pub trait PusTmSecondaryHeaderT { } pub mod zc { + use super::GenericPusTmSecondaryHeader; use crate::ecss::{PusError, PusVersion}; use zerocopy::{AsBytes, FromBytes, NetworkEndian, Unaligned, U16}; @@ -77,7 +78,7 @@ pub mod zc { } } - impl super::PusTmSecondaryHeaderT for PusTmSecHeaderWithoutTimestamp { + impl GenericPusTmSecondaryHeader for PusTmSecHeaderWithoutTimestamp { fn pus_version(&self) -> PusVersion { PusVersion::try_from(self.pus_version_and_sc_time_ref_status >> 4 & 0b1111) .unwrap_or(PusVersion::Invalid) @@ -149,7 +150,7 @@ impl<'slice> PusTmSecondaryHeader<'slice> { } } -impl PusTmSecondaryHeaderT for PusTmSecondaryHeader<'_> { +impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> { fn pus_version(&self) -> PusVersion { self.pus_version } @@ -455,7 +456,7 @@ impl PusPacket for PusTm<'_> { } //noinspection RsTraitImplementation -impl PusTmSecondaryHeaderT for PusTm<'_> { +impl GenericPusTmSecondaryHeader for PusTm<'_> { delegate!(to self.sec_header { fn pus_version(&self) -> PusVersion; fn service(&self) -> u8; From d28ea7d4da9f629ebb13a776c9005abb47d9b9f0 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 17:18:10 +0100 Subject: [PATCH 03/10] add docs for new feature --- CHANGELOG.md | 2 ++ README.md | 1 + src/lib.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e9270b..21d70b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Changed +- `serde` support is now optional behind the `serde` feature + # [v0.3.1] 03.12.2022 - Small fix for faulty docs.rs build diff --git a/README.md b/README.md index 1c53c87..a4420c7 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Default features: - [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which operate on containers like [`alloc::vec::Vec`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html). Enabled by the `std` feature. + - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s # Examples diff --git a/src/lib.rs b/src/lib.rs index b45401b..569b693 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ //! - [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which operate on containers //! like [`alloc::vec::Vec`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html). //! Enabled by the `std` feature. +//! - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s //! //! ## Module //! From 1969a26f14fa761d0e0ffc46dc37098e7190e34b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 17:22:51 +0100 Subject: [PATCH 04/10] bump changelog --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21d70b3..637a21d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Changed -- `serde` support is now optional behind the `serde` feature +- `serde` support is now optional and behind the `serde` feature +- `PusTcSecondaryHeaderT` trait renamed to `GenericPusTcSecondaryHeader` +- `PusTmSecondaryHeaderT` trait renamed to `GenericPusTmSecondaryHeader` + +## Added + +- `serde` `Serialize` and `Deserialize` added to all types +- `const_new` constructors for `PacketId` and `PacketSeqCtrl` +- Added `PartialEq` and `Eq` `derive`s to `CdsShortTimeProvider` # [v0.3.1] 03.12.2022 From 54bb4bdaaa39ce02469c687829472be2475c0485 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 18:25:30 +0100 Subject: [PATCH 05/10] new helper functions for CCSDS SP construction --- src/lib.rs | 206 +++++++++++++++++++++++++++++++++++++++++----------- src/tc.rs | 12 +-- src/time.rs | 3 +- src/tm.rs | 6 +- 4 files changed, 173 insertions(+), 54 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 569b693..53cf4ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,13 +33,13 @@ //! //! This module contains helpers and data structures to generate Space Packets according to the //! [CCSDS 133.0-B-2](https://public.ccsds.org/Pubs/133x0b2e1.pdf). This includes the -//! [SpHeader] class to generate the Space Packet Header component common to all space packets +//! [SpHeader] class to generate the Space Packet Header component common to all space packets. //! //! ## Example //! //! ```rust //! use spacepackets::SpHeader; -//! let sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); +//! let sp_header = SpHeader::tc_unseg(0x42, 12, 0).expect("Error creating SP header"); //! println!("{:?}", sp_header); //! ``` #![no_std] @@ -138,14 +138,40 @@ pub struct PacketId { apid: u16, } +impl Default for PacketId { + fn default() -> Self { + PacketId { + ptype: PacketType::Tm, + sec_header_flag: false, + apid: 0 + } + } +} + impl PacketId { - const fn const_new(ptype: PacketType, sec_header_flag: bool, apid: u16) -> PacketId { + pub const fn const_tc(sec_header: bool, apid: u16) -> Self { + Self::const_new(PacketType::Tc, sec_header, apid) + } + + pub const fn const_tm(sec_header: bool, apid: u16) -> Self { + Self::const_new(PacketType::Tm, sec_header, apid) + } + + pub fn tc(sec_header: bool, apid: u16) -> Option { + Self::new(PacketType::Tc, sec_header, apid) + } + + pub fn tm(sec_header: bool, apid: u16) -> Option { + Self::new(PacketType::Tm, sec_header, apid) + } + + pub const fn const_new(ptype: PacketType, sec_header: bool, apid: u16) -> Self { if apid > MAX_APID { panic!("APID too large"); } PacketId { ptype, - sec_header_flag, + sec_header_flag: sec_header, apid, } } @@ -341,7 +367,8 @@ pub trait CcsdsPrimaryHeader { /// /// # Arguments /// -/// * `version` - CCSDS version field, occupies the first 3 bits of the raw header +/// * `version` - CCSDS version field, occupies the first 3 bits of the raw header. Will generally +/// be set to 0b000 in all constructors provided by this crate. /// * `packet_id` - Packet Identifier, which can also be used as a start marker. Occupies the last /// 13 bits of the first two bytes of the raw header /// * `psc` - Packet Sequence Control, occupies the third and fourth byte of the raw header @@ -356,56 +383,96 @@ pub struct SpHeader { } impl Default for SpHeader { + /// The default function sets the sequence flag field to [SequenceFlags::Unsegmented]. The data + /// length field is set to 1, which denotes an empty space packets. fn default() -> Self { SpHeader { version: 0, - packet_id: PacketId { - ptype: PacketType::Tm, - apid: 0, - sec_header_flag: false, - }, + packet_id: PacketId::default(), psc: PacketSequenceCtrl { seq_flags: SequenceFlags::Unsegmented, seq_count: 0, }, - data_len: 0, + data_len: 1, } } } impl SpHeader { - /// Create a new Space Packet Header instance which can be used to create generic - /// Space Packets. This will return [None] if the APID or sequence count argument - /// exceed [MAX_APID] or [MAX_SEQ_COUNT] respectively. - pub fn new( + pub const fn new( + packet_id: PacketId, + psc: PacketSequenceCtrl, + data_len: u16 + ) -> Self { + Self { + version: 0, + packet_id, + psc, + data_len + } + } + + /// const variant of the [SpHeader::new_fron_single_fields] function. Panics if the passed + /// APID exceeds [MAX_APID] or the passed packet sequence count exceeds [MAX_SEQ_COUNT]. + const fn const_new_from_single_fields( ptype: PacketType, sec_header: bool, apid: u16, + seq_flags: SequenceFlags, + seq_count: u16, + data_len: u16 + ) -> Self { + if seq_count > MAX_SEQ_COUNT { + panic!("Sequence count is too large"); + } + if apid > MAX_APID { + panic!("APID is too large"); + } + Self { + psc: PacketSequenceCtrl::const_new(seq_flags, seq_count), + packet_id: PacketId::const_new(ptype, sec_header, apid), + data_len, + version: 0 + } + } + + /// Create a new Space Packet Header instance which can be used to create generic + /// Space Packets. This will return [None] if the APID or sequence count argument + /// exceed [MAX_APID] or [MAX_SEQ_COUNT] respectively. The version field is set to 0b000. + pub fn new_from_single_fields( + ptype: PacketType, + sec_header: bool, + apid: u16, + seq_flags: SequenceFlags, seq_count: u16, data_len: u16, ) -> Option { if seq_count > MAX_SEQ_COUNT || apid > MAX_APID { return None; } - let mut header = SpHeader::default(); - header.packet_id.sec_header_flag = sec_header; - header.packet_id.apid = apid; - header.packet_id.ptype = ptype; - header.psc.seq_count = seq_count; - header.data_len = data_len; - Some(header) + Some(SpHeader::const_new_from_single_fields(ptype, sec_header, apid, seq_flags, seq_count, data_len)) } - /// Helper function for telemetry space packet headers. The packet type field will be - /// set accordingly. - pub fn tm(apid: u16, seq_count: u16, data_len: u16) -> Option { - Self::new(PacketType::Tm, false, apid, seq_count, data_len) + /// Helper function for telemetry space packet headers. The packet type field will be + /// set accordingly. The secondary header flag field is set to false. + pub fn tm(apid: u16, seq_flags: SequenceFlags, seq_count: u16, data_len: u16) -> Option { + Self::new_from_single_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len) } - /// Helper function for telecommand space packet headers. The packet type field will be - /// set accordingly. - pub fn tc(apid: u16, seq_count: u16, data_len: u16) -> Option { - Self::new(PacketType::Tc, false, apid, seq_count, data_len) + /// Helper function for telemetry space packet headers. The packet type field will be + /// set accordingly. The secondary header flag field is set to false. + pub fn tc(apid: u16, seq_flags: SequenceFlags, seq_count: u16, data_len: u16) -> Option { + Self::new_from_single_fields(PacketType::Tc, false, apid, seq_flags, seq_count, data_len) + } + + /// Variant of [SpHeader::tm] which sets the sequence flag field to [SequenceFlags::Unsegmented] + pub fn tm_unseg(apid: u16, seq_count: u16, data_len: u16) -> Option { + Self::tm(apid, SequenceFlags::Unsegmented, seq_count, data_len) + } + + /// Variant of [SpHeader::tc] which sets the sequence flag field to [SequenceFlags::Unsegmented] + pub fn tc_unseg(apid: u16, seq_count: u16, data_len: u16) -> Option { + Self::tc(apid, SequenceFlags::Unsegmented, seq_count, data_len) } //noinspection RsTraitImplementation @@ -575,16 +642,30 @@ pub mod zc { mod tests { #[cfg(feature = "serde")] use crate::CcsdsPrimaryHeader; - use crate::SpHeader; + use crate::{SequenceFlags, SpHeader}; use crate::{ packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceCtrl, PacketType, - SequenceFlags, }; use alloc::vec; use num_traits::pow; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; + const CONST_SP: SpHeader = SpHeader::new( + PacketId::const_tc(true, 0x36), + PacketSequenceCtrl::const_new(SequenceFlags::ContinuationSegment, 0x88), + 0x90 + ); + + #[test] + fn verify_const_sp_header() { + assert_eq!(CONST_SP.sec_header_flag(), true); + assert_eq!(CONST_SP.apid(), 0x36); + assert_eq!(CONST_SP.sequence_flags(), SequenceFlags::ContinuationSegment); + assert_eq!(CONST_SP.seq_count(), 0x88); + assert_eq!(CONST_SP.data_len, 0x90); + } + #[test] fn test_seq_flag_helpers() { assert_eq!( @@ -593,8 +674,7 @@ mod tests { ); assert_eq!( SequenceFlags::try_from(0b01).expect("SEQ flag creation failed"), - SequenceFlags::FirstSegment - ); + SequenceFlags::FirstSegment); assert_eq!( SequenceFlags::try_from(0b10).expect("SEQ flag creation failed"), SequenceFlags::LastSegment @@ -668,7 +748,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serde_sph() { - let sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); + let sp_header = SpHeader::tc_unseg(0x42, 12, 0).expect("Error creating SP header"); assert_eq!(sp_header.ccsds_version(), 0b000); assert!(sp_header.is_tc()); assert!(!sp_header.sec_header_flag()); @@ -690,7 +770,7 @@ mod tests { assert_eq!(sp_header.ccsds_version(), 0b000); assert_eq!(sp_header.data_len, 0); - let sp_header = SpHeader::tm(0x7, 22, 36).expect("Error creating SP header"); + let sp_header = SpHeader::tm_unseg(0x7, 22, 36).expect("Error creating SP header"); assert_eq!(sp_header.ccsds_version(), 0b000); assert!(sp_header.is_tm()); assert!(!sp_header.sec_header_flag()); @@ -721,28 +801,68 @@ mod tests { } #[test] - fn test_sp_header_setters() { - let mut sp_header = SpHeader::tc(0x42, 12, 0).expect("Error creating SP header"); - assert_eq!(sp_header.apid(), 0x42); + fn test_setters() { + let sp_header = SpHeader::tc(0x42, SequenceFlags::Unsegmented, 25, 0); + assert!(sp_header.is_some()); + let mut sp_header = sp_header.unwrap(); sp_header.set_apid(0x12); assert_eq!(sp_header.apid(), 0x12); - sp_header.set_sec_header_flag(); assert!(sp_header.sec_header_flag()); sp_header.clear_sec_header_flag(); assert!(!sp_header.sec_header_flag()); - sp_header.set_seq_count(0x45); - assert_eq!(sp_header.seq_count(), 0x45); assert_eq!(sp_header.ptype(), PacketType::Tc); sp_header.set_packet_type(PacketType::Tm); assert_eq!(sp_header.ptype(), PacketType::Tm); + sp_header.set_seq_count(0x45); + assert_eq!(sp_header.seq_count(), 0x45); + } + + #[test] + fn test_tc_ctor() { + let sp_header = SpHeader::tc(0x42, SequenceFlags::Unsegmented, 25, 0); + assert!(sp_header.is_some()); + let sp_header = sp_header.unwrap(); + verify_sp_fields(PacketType::Tc, &sp_header); + } + + #[test] + fn test_tc_ctor_unseg() { + let sp_header = SpHeader::tc_unseg(0x42, 25, 0); + assert!(sp_header.is_some()); + let sp_header = sp_header.unwrap(); + verify_sp_fields(PacketType::Tc, &sp_header); + } + + #[test] + fn test_tm_ctor() { + let sp_header = SpHeader::tm(0x42, SequenceFlags::Unsegmented, 25, 0); + assert!(sp_header.is_some()); + let sp_header = sp_header.unwrap(); + verify_sp_fields(PacketType::Tm, &sp_header); + } + + #[test] + fn test_tm_ctor_unseg() { + let sp_header = SpHeader::tm_unseg(0x42, 25, 0); + assert!(sp_header.is_some()); + let sp_header = sp_header.unwrap(); + verify_sp_fields(PacketType::Tm, &sp_header); + } + + fn verify_sp_fields(ptype: PacketType, sp_header: &SpHeader) { + assert_eq!(sp_header.ptype(), ptype); + assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented); + assert_eq!(sp_header.apid(), 0x42); + assert_eq!(sp_header.seq_count(), 25); + assert_eq!(sp_header.data_len(), 0); } #[test] fn test_zc_sph() { use zerocopy::AsBytes; - let sp_header = SpHeader::tc(0x7FF, pow(2, 14) - 1, 0).expect("Error creating SP header"); + let sp_header = SpHeader::tc_unseg(0x7FF, pow(2, 14) - 1, 0).expect("Error creating SP header"); assert_eq!(sp_header.ptype(), PacketType::Tc); assert_eq!(sp_header.apid(), 0x7FF); assert_eq!(sp_header.data_len(), 0); diff --git a/src/tc.rs b/src/tc.rs index d3aafec..f8de0aa 100644 --- a/src/tc.rs +++ b/src/tc.rs @@ -9,7 +9,7 @@ //! use spacepackets::ecss::PusPacket; //! //! // Create a ping telecommand with no user application data -//! let mut sph = SpHeader::tc(0x02, 0x34, 0).unwrap(); +//! let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap(); //! let tc_header = PusTcSecondaryHeader::new_simple(17, 1); //! let pus_tc = PusTc::new(&mut sph, tc_header, None, true); //! println!("{:?}", pus_tc); @@ -486,18 +486,18 @@ mod tests { use alloc::vec::Vec; fn base_ping_tc_full_ctor() -> PusTc<'static> { - let mut sph = SpHeader::tc(0x02, 0x34, 0).unwrap(); + let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap(); let tc_header = PusTcSecondaryHeader::new_simple(17, 1); PusTc::new(&mut sph, tc_header, None, true) } fn base_ping_tc_simple_ctor() -> PusTc<'static> { - let mut sph = SpHeader::tc(0x02, 0x34, 0).unwrap(); + let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap(); PusTc::new_simple(&mut sph, 17, 1, None, true) } fn base_ping_tc_simple_ctor_with_app_data(app_data: &'static [u8]) -> PusTc<'static> { - let mut sph = SpHeader::tc(0x02, 0x34, 0).unwrap(); + let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap(); PusTc::new_simple(&mut sph, 17, 1, Some(app_data), true) } @@ -537,7 +537,7 @@ mod tests { #[test] fn test_update_func() { - let mut sph = SpHeader::tc(0x02, 0x34, 0).unwrap(); + let mut sph = SpHeader::tc_unseg(0x02, 0x34, 0).unwrap(); let mut tc = PusTc::new_simple(&mut sph, 17, 1, None, false); tc.calc_crc_on_serialization = false; assert_eq!(tc.data_len(), 0); @@ -700,7 +700,7 @@ mod tests { assert_eq!(tc.apid(), 0x02); assert_eq!(tc.ack_flags(), ACK_ALL); assert_eq!(tc.len_packed(), exp_full_len); - let mut comp_header = SpHeader::tc(0x02, 0x34, exp_full_len as u16 - 7).unwrap(); + let mut comp_header = SpHeader::tc_unseg(0x02, 0x34, exp_full_len as u16 - 7).unwrap(); comp_header.set_sec_header_flag(); assert_eq!(tc.sp_header, comp_header); } diff --git a/src/time.rs b/src/time.rs index 3fd0872..4f9bbf1 100644 --- a/src/time.rs +++ b/src/time.rs @@ -275,9 +275,8 @@ mod tests { use crate::ByteConversionError::{FromSliceTooSmall, ToSliceTooSmall}; use alloc::format; use chrono::{Datelike, Timelike}; - use postcard::from_bytes; #[cfg(feature = "serde")] - use postcard::to_allocvec; + use postcard::{to_allocvec, from_bytes}; #[test] fn test_creation() { diff --git a/src/tm.rs b/src/tm.rs index 3c3fc3d..220094b 100644 --- a/src/tm.rs +++ b/src/tm.rs @@ -474,13 +474,13 @@ mod tests { use crate::SpHeader; fn base_ping_reply_full_ctor(time_stamp: &[u8]) -> PusTm { - let mut sph = SpHeader::tm(0x123, 0x234, 0).unwrap(); + let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, &time_stamp); PusTm::new(&mut sph, tc_header, None, true) } fn base_hk_reply<'a>(time_stamp: &'a [u8], src_data: &'a [u8]) -> PusTm<'a> { - let mut sph = SpHeader::tm(0x123, 0x234, 0).unwrap(); + let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, &time_stamp); PusTm::new(&mut sph, tc_header, Some(src_data), true) } @@ -552,7 +552,7 @@ mod tests { #[test] fn test_manual_field_update() { - let mut sph = SpHeader::tm(0x123, 0x234, 0).unwrap(); + let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_time_stamp()); let mut tm = PusTm::new(&mut sph, tc_header, None, false); tm.calc_crc_on_serialization = false; From f7c688d8dbcbb095401f6c47e08995afbd7d87b7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 18:26:38 +0100 Subject: [PATCH 06/10] line break --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 53cf4ef..3e7dd18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,8 @@ //! - [`alloc`](https://doc.rust-lang.org/alloc/): Enables features which operate on containers //! like [`alloc::vec::Vec`](https://doc.rust-lang.org/beta/alloc/vec/struct.Vec.html). //! Enabled by the `std` feature. -//! - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and `Deserialize` `derive`s +//! - [`serde`](https://serde.rs/): Adds `serde` support for most types by adding `Serialize` and +//! `Deserialize` `derive`s //! //! ## Module //! From 322a56335ed4fbb07e83ae01c71938c3a8b48d49 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 19:56:21 +0100 Subject: [PATCH 07/10] add tests for new functionality --- src/lib.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 3e7dd18..52c0b10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -658,6 +658,45 @@ mod tests { 0x90 ); + const PACKET_ID_TM: PacketId = PacketId::const_tm(true, 0x22); + + #[test] + fn verify_const_packet_id() { + assert_eq!(PACKET_ID_TM.apid(), 0x22); + assert_eq!(PACKET_ID_TM.sec_header_flag, true); + assert_eq!(PACKET_ID_TM.ptype, PacketType::Tm); + let const_tc_id = PacketId::const_tc(true, 0x23); + assert_eq!(const_tc_id.ptype, PacketType::Tc); + } + + #[test] + fn test_default_packet_id() { + let id_default = PacketId::default(); + assert_eq!(id_default.ptype, PacketType::Tm); + assert_eq!(id_default.apid, 0x000); + assert_eq!(id_default.sec_header_flag, false); + } + + #[test] + fn test_packet_id_ctors() { + let packet_id = PacketId::new(PacketType::Tc, true, 0x1ff); + assert!(packet_id.is_some()); + let packet_id = packet_id.unwrap(); + assert_eq!(packet_id.apid(), 0x1ff); + assert_eq!(packet_id.ptype, PacketType::Tc); + assert_eq!(packet_id.sec_header_flag, true); + let packet_id_tc = PacketId::tc(true, 0x1ff); + assert!(packet_id_tc.is_some()); + let packet_id_tc = packet_id_tc.unwrap(); + assert_eq!(packet_id_tc, packet_id); + let packet_id_tm = PacketId::tm(true, 0x2ff); + assert!(packet_id_tm.is_some()); + let packet_id_tm = packet_id_tm.unwrap(); + assert_eq!(packet_id_tm.sec_header_flag, true); + assert_eq!(packet_id_tm.ptype, PacketType::Tm); + assert_eq!(packet_id_tm.apid, 0x2ff); + } + #[test] fn verify_const_sp_header() { assert_eq!(CONST_SP.sec_header_flag(), true); From 098a534199e54a16d58644a77cda75706ab2175f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 19:57:51 +0100 Subject: [PATCH 08/10] bump changelog --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 637a21d..6e2be24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `serde` support is now optional and behind the `serde` feature - `PusTcSecondaryHeaderT` trait renamed to `GenericPusTcSecondaryHeader` - `PusTmSecondaryHeaderT` trait renamed to `GenericPusTmSecondaryHeader` +- `SpHeader`: Former `tc` and `tm` methods now named `tc_unseg` and `tm_unseg`. + Former `new` method now called `new_from_single_fields` ## Added - `serde` `Serialize` and `Deserialize` added to all types -- `const_new` constructors for `PacketId` and `PacketSeqCtrl` +- Added `const` constructors for `PacketId`, `PacketSeqCtrl` and + `SpHeader` - Added `PartialEq` and `Eq` `derive`s to `CdsShortTimeProvider` # [v0.3.1] 03.12.2022 From 13be7ca1e7b7cca8a9604fcbbf4bd8791ee02ac7 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 19:58:53 +0100 Subject: [PATCH 09/10] do not push version just yet --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 88ae8aa..6058e82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "spacepackets" -version = "0.4.0" +version = "0.3.1" edition = "2021" authors = ["Robin Mueller "] description = "Generic implementations for various CCSDS and ECSS packet standards" From 3a71b00198566d009f4f08e69cf61d48ccc14bcd Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 4 Dec 2022 20:00:49 +0100 Subject: [PATCH 10/10] cargo fmt --- src/lib.rs | 33 ++++++++++++++++++--------------- src/time.rs | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 52c0b10..d8da91e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,7 +144,7 @@ impl Default for PacketId { PacketId { ptype: PacketType::Tm, sec_header_flag: false, - apid: 0 + apid: 0, } } } @@ -400,16 +400,12 @@ impl Default for SpHeader { } impl SpHeader { - pub const fn new( - packet_id: PacketId, - psc: PacketSequenceCtrl, - data_len: u16 - ) -> Self { + pub const fn new(packet_id: PacketId, psc: PacketSequenceCtrl, data_len: u16) -> Self { Self { version: 0, packet_id, psc, - data_len + data_len, } } @@ -421,7 +417,7 @@ impl SpHeader { apid: u16, seq_flags: SequenceFlags, seq_count: u16, - data_len: u16 + data_len: u16, ) -> Self { if seq_count > MAX_SEQ_COUNT { panic!("Sequence count is too large"); @@ -433,7 +429,7 @@ impl SpHeader { psc: PacketSequenceCtrl::const_new(seq_flags, seq_count), packet_id: PacketId::const_new(ptype, sec_header, apid), data_len, - version: 0 + version: 0, } } @@ -451,7 +447,9 @@ impl SpHeader { if seq_count > MAX_SEQ_COUNT || apid > MAX_APID { return None; } - Some(SpHeader::const_new_from_single_fields(ptype, sec_header, apid, seq_flags, seq_count, data_len)) + Some(SpHeader::const_new_from_single_fields( + ptype, sec_header, apid, seq_flags, seq_count, data_len, + )) } /// Helper function for telemetry space packet headers. The packet type field will be @@ -643,10 +641,10 @@ pub mod zc { mod tests { #[cfg(feature = "serde")] use crate::CcsdsPrimaryHeader; - use crate::{SequenceFlags, SpHeader}; use crate::{ packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceCtrl, PacketType, }; + use crate::{SequenceFlags, SpHeader}; use alloc::vec; use num_traits::pow; #[cfg(feature = "serde")] @@ -655,7 +653,7 @@ mod tests { const CONST_SP: SpHeader = SpHeader::new( PacketId::const_tc(true, 0x36), PacketSequenceCtrl::const_new(SequenceFlags::ContinuationSegment, 0x88), - 0x90 + 0x90, ); const PACKET_ID_TM: PacketId = PacketId::const_tm(true, 0x22); @@ -701,7 +699,10 @@ mod tests { fn verify_const_sp_header() { assert_eq!(CONST_SP.sec_header_flag(), true); assert_eq!(CONST_SP.apid(), 0x36); - assert_eq!(CONST_SP.sequence_flags(), SequenceFlags::ContinuationSegment); + assert_eq!( + CONST_SP.sequence_flags(), + SequenceFlags::ContinuationSegment + ); assert_eq!(CONST_SP.seq_count(), 0x88); assert_eq!(CONST_SP.data_len, 0x90); } @@ -714,7 +715,8 @@ mod tests { ); assert_eq!( SequenceFlags::try_from(0b01).expect("SEQ flag creation failed"), - SequenceFlags::FirstSegment); + SequenceFlags::FirstSegment + ); assert_eq!( SequenceFlags::try_from(0b10).expect("SEQ flag creation failed"), SequenceFlags::LastSegment @@ -902,7 +904,8 @@ mod tests { fn test_zc_sph() { use zerocopy::AsBytes; - let sp_header = SpHeader::tc_unseg(0x7FF, pow(2, 14) - 1, 0).expect("Error creating SP header"); + let sp_header = + SpHeader::tc_unseg(0x7FF, pow(2, 14) - 1, 0).expect("Error creating SP header"); assert_eq!(sp_header.ptype(), PacketType::Tc); assert_eq!(sp_header.apid(), 0x7FF); assert_eq!(sp_header.data_len(), 0); diff --git a/src/time.rs b/src/time.rs index 4f9bbf1..0ae8141 100644 --- a/src/time.rs +++ b/src/time.rs @@ -276,7 +276,7 @@ mod tests { use alloc::format; use chrono::{Datelike, Timelike}; #[cfg(feature = "serde")] - use postcard::{to_allocvec, from_bytes}; + use postcard::{from_bytes, to_allocvec}; #[test] fn test_creation() {