diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8aa176a..174228b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@1.70.0 + - uses: dtolnay/rust-toolchain@1.83 - run: cargo check --release cross-check: diff --git a/CHANGELOG.md b/CHANGELOG.md index 58453d3..1e44503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). # [unreleased] +- Bump Rust MSRV to v1.83 + ## Changed - CFDP NAK PDU `SegmentRequestIter` is not generic over the file size anymore. Instead, the @@ -22,8 +24,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Renamed `CcsdsSimpleSeqCountProvider` to `SequenceCounterCcsdsSimple` - Renamed `SeqCountProviderSync` to `SequenceCounterSync` - Renamed `PusPacket::opt_crc16` to `PusPacket::checksum` +- Renamed `PacketSequenceCtrl` to `PacketSequenceControl` - 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. +- APID is represented by `arbitrary-int::u11` while the sequence count is represented by + `arbitrary-int::u14`. A lot of corresponding checks were removed because the type now ensure + value validity. +- ACK field changed from `u8` to `AckFlags` structure. +- PUS version raw representation is `u4` now. +- SC time reference status representation is `u4` now. ## Removed @@ -31,6 +40,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Added +- `AckFlags` which is implemented with `bitbybit::bitfield` +- `ApidOutOfRangeError` and `SequenceCountOutOfRangeError` - Added PUS A legacy support for telecommands inside the `ecss.tc_pus_a` module - Added `SequenceCounter::increment_mut` and `SequenceCounter::get_and_increment_mut` - Implemented `SequenceCounter` for `Atomic` unsigned types and references of them diff --git a/Cargo.toml b/Cargo.toml index 5c41682..4071b0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "spacepackets" version = "0.15.0" edition = "2021" -rust-version = "1.70.0" +rust-version = "1.83" authors = ["Robin Mueller "] description = "Generic implementations for various CCSDS and ECSS packet standards" homepage = "https://egit.irs.uni-stuttgart.de/rust/spacepackets" @@ -21,7 +21,9 @@ thiserror = { version = "2", default-features = false } num_enum = { version = ">0.5, <=0.7", default-features = false } num-traits = { version = "0.2", default-features = false } serde = { version = "1", optional = true, default-features = false, features = ["derive"] } +arbitrary-int = { version = "2" } portable-atomic = "1" +bitbybit = "1.4" time = { version = "0.3", default-features = false, optional = true } chrono = { version = "0.4", default-features = false, optional = true } @@ -30,7 +32,8 @@ defmt = { version = "1", default-features = false, optional = true } [features] default = ["std"] std = ["alloc", "chrono/std", "chrono/clock", "thiserror/std"] -serde = ["dep:serde", "chrono?/serde"] +defmt = ["dep:defmt", "arbitrary-int/defmt"] +serde = ["dep:serde", "chrono?/serde", "arbitrary-int/serde"] alloc = ["chrono?/alloc", "defmt?/alloc", "serde?/alloc"] timelib = ["dep:time"] diff --git a/docs.sh b/docs.sh deleted file mode 100755 index 37563d2..0000000 --- a/docs.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" -cargo +nightly doc --all-features --open diff --git a/justfile b/justfile new file mode 100644 index 0000000..704b921 --- /dev/null +++ b/justfile @@ -0,0 +1,17 @@ +all: check clippy fmt build docs + +clippy: + cargo clippy -- -D warnings + +fmt: + cargo fmt --all -- --check + +check: + cargo check --all-features + +build: + cargo build --all-features + +docs: + export RUSTDOCFLAGS="--cfg docsrs --generate-link-to-definition -Z unstable-options" + cargo +nightly doc --all-features diff --git a/src/cfdp/mod.rs b/src/cfdp/mod.rs index 09f2241..5b1a720 100644 --- a/src/cfdp/mod.rs +++ b/src/cfdp/mod.rs @@ -13,36 +13,40 @@ pub const CFDP_VERSION_2_NAME: &str = "CCSDS 727.0-B-5"; /// Currently, only this version is supported. pub const CFDP_VERSION_2: u8 = 0b001; -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum PduType { FileDirective = 0, FileData = 1, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum Direction { TowardsReceiver = 0, TowardsSender = 1, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum TransmissionMode { Acknowledged = 0, Unacknowledged = 1, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum CrcFlag { NoCrc = 0, @@ -68,9 +72,10 @@ impl From for bool { } /// Always 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 P.75) -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum SegmentMetadataFlag { NotPresent = 0, @@ -78,18 +83,20 @@ pub enum SegmentMetadataFlag { } /// Always 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 P.75) -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum SegmentationControl { NoRecordBoundaryPreservation = 0, WithRecordBoundaryPreservation = 1, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u3, exhaustive = false)] #[repr(u8)] pub enum FaultHandlerCode { NoticeOfCancellation = 0b0001, @@ -98,9 +105,10 @@ pub enum FaultHandlerCode { AbandonTransaction = 0b0100, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u4, exhaustive = false)] #[repr(u8)] pub enum ConditionCode { /// This is not an error condition for which a faulty handler override can be specified @@ -121,9 +129,10 @@ pub enum ConditionCode { CancelRequestReceived = 0b1111, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum LargeFileFlag { /// 32 bit maximum file size and FSS size @@ -133,9 +142,10 @@ pub enum LargeFileFlag { } /// Transaction status for the ACK PDU field according to chapter 5.2.4 of the CFDP standard. -#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +#[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u2, exhaustive = true)] #[repr(u8)] pub enum TransactionStatus { /// Transaction is not currently active and the CFDP implementation does not retain a diff --git a/src/ecss/mod.rs b/src/ecss/mod.rs index 966db47..b0dae80 100644 --- a/src/ecss/mod.rs +++ b/src/ecss/mod.rs @@ -9,6 +9,7 @@ use crate::{ }; #[cfg(feature = "alloc")] use alloc::vec::Vec; +use arbitrary_int::u4; use core::fmt::Debug; use core::mem::size_of; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -74,9 +75,11 @@ pub enum PusServiceId { } /// All PUS versions. Only PUS C is supported by this library. -#[derive(PartialEq, Eq, Copy, Clone, Debug)] +#[derive(PartialEq, Eq, Debug, num_enum::TryFromPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u4, exhaustive = false)] +#[repr(u8)] #[non_exhaustive] pub enum PusVersion { EsaPus = 0, @@ -84,14 +87,14 @@ pub enum PusVersion { PusC = 2, } -impl TryFrom for PusVersion { - type Error = u8; +impl TryFrom for PusVersion { + type Error = u4; - fn try_from(value: u8) -> Result { + fn try_from(value: u4) -> Result { match value { - x if x == PusVersion::EsaPus as u8 => Ok(PusVersion::EsaPus), - x if x == PusVersion::PusA as u8 => Ok(PusVersion::PusA), - x if x == PusVersion::PusC as u8 => Ok(PusVersion::PusC), + x if x == PusVersion::EsaPus.raw_value() => Ok(PusVersion::EsaPus), + x if x == PusVersion::PusA.raw_value() => Ok(PusVersion::PusA), + x if x == PusVersion::PusC.raw_value() => Ok(PusVersion::PusC), _ => Err(value), } } @@ -155,7 +158,7 @@ pub enum PfcReal { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum PusError { #[error("PUS version {0:?} not supported")] - VersionNotSupported(u8), + VersionNotSupported(u4), #[error("checksum verification for crc16 {0:#06x} failed")] ChecksumFailure(u16), /// CRC16 needs to be calculated first @@ -168,7 +171,7 @@ pub enum PusError { /// Generic trait to describe common attributes for both PUS Telecommands (TC) and PUS Telemetry /// (TM) packets. All PUS packets are also a special type of [CcsdsPacket]s. pub trait PusPacket: CcsdsPacket { - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; fn service(&self) -> u8; fn subservice(&self) -> u8; fn user_data(&self) -> &[u8]; @@ -261,11 +264,11 @@ macro_rules! ccsds_impl { () => { delegate!(to self.sp_header { #[inline] - fn ccsds_version(&self) -> u8; + fn ccsds_version(&self) -> u3; #[inline] fn packet_id(&self) -> crate::PacketId; #[inline] - fn psc(&self) -> crate::PacketSequenceCtrl; + fn psc(&self) -> crate::PacketSequenceControl; #[inline] fn data_len(&self) -> u16; }); @@ -276,9 +279,9 @@ macro_rules! sp_header_impls { () => { delegate!(to self.sp_header { #[inline] - pub fn set_apid(&mut self, apid: u16) -> bool; + pub fn set_apid(&mut self, apid: u11); #[inline] - pub fn set_seq_count(&mut self, seq_count: u16) -> bool; + pub fn set_seq_count(&mut self, seq_count: u14); #[inline] pub fn set_seq_flags(&mut self, seq_flag: SequenceFlags); }); @@ -407,7 +410,7 @@ pub trait WritablePusPacket { 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_checksum] 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 if /// the paket is configured to include a checksum. fn write_to_bytes_checksum_no_table(&self, slice: &mut [u8]) -> Result { @@ -578,7 +581,8 @@ mod tests { #[test] fn test_pus_error_display() { - let unsupport_version = PusError::VersionNotSupported(super::PusVersion::EsaPus as u8); + let unsupport_version = + PusError::VersionNotSupported(super::PusVersion::EsaPus.raw_value()); let write_str = unsupport_version.to_string(); assert_eq!(write_str, "PUS version 0 not supported") } @@ -614,8 +618,8 @@ mod tests { #[test] fn test_pus_error_eq_impl() { assert_eq!( - PusError::VersionNotSupported(PusVersion::EsaPus as u8), - PusError::VersionNotSupported(PusVersion::EsaPus as u8) + PusError::VersionNotSupported(PusVersion::EsaPus.raw_value()), + PusError::VersionNotSupported(PusVersion::EsaPus.raw_value()) ); } diff --git a/src/ecss/tc.rs b/src/ecss/tc.rs index 7d84a81..21bb4e6 100644 --- a/src/ecss/tc.rs +++ b/src/ecss/tc.rs @@ -7,17 +7,18 @@ //! use spacepackets::{CcsdsPacket, SpHeader}; //! use spacepackets::ecss::{PusPacket, WritablePusPacket}; //! use spacepackets::ecss::tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader, CreatorConfig}; +//! use arbitrary_int::u11; //! //! // Create a ping telecommand with no user application data //! let pus_tc = PusTcCreator::new_no_app_data( -//! SpHeader::new_from_apid(0x02), +//! SpHeader::new_from_apid(u11::new(0x02)), //! PusTcSecondaryHeader::new_simple(17, 1), //! CreatorConfig::default() //! ); //! println!("{:?}", pus_tc); //! assert_eq!(pus_tc.service(), 17); //! assert_eq!(pus_tc.subservice(), 1); -//! assert_eq!(pus_tc.apid(), 0x02); +//! assert_eq!(pus_tc.apid().value(), 0x02); //! //! // Serialize TC into a raw buffer //! let mut test_buf: [u8; 32] = [0; 32]; @@ -31,7 +32,7 @@ //! let pus_tc_deserialized = PusTcReader::new(&test_buf).expect("Deserialization failed"); //! assert_eq!(pus_tc.service(), 17); //! assert_eq!(pus_tc.subservice(), 1); -//! assert_eq!(pus_tc.apid(), 0x02); +//! assert_eq!(pus_tc.apid().value(), 0x02); //! ``` use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; pub use crate::ecss::CreatorConfig; @@ -42,13 +43,17 @@ use crate::ecss::{ }; use crate::SpHeader; use crate::{ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, CCSDS_HEADER_LEN}; +use arbitrary_int::{u11, u14, u3, u4}; use core::mem::size_of; use delegate::delegate; -use num_enum::{IntoPrimitive, TryFromPrimitive}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use zerocopy::{FromBytes, IntoBytes}; +// Is necessary for some reason, possibly bug. +#[cfg(feature = "defmt")] +use arbitrary_int::traits::Integer; + #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -62,33 +67,44 @@ const PUS_VERSION: PusVersion = PusVersion::PusC; /// Marker trait for PUS telecommand structures. pub trait IsPusTelecommand {} -#[derive(Debug, Eq, PartialEq, Copy, Clone, IntoPrimitive, TryFromPrimitive)] +#[bitbybit::bitfield(u4, default = 0b0000, debug, defmt_bitfields(feature = "defmt"))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -enum AckOpts { - Acceptance = 0b1000, - Start = 0b0100, - Progress = 0b0010, - Completion = 0b0001, +#[derive(PartialEq, Eq)] +pub struct AckFlags { + #[bit(3, rw)] + acceptance: bool, + #[bit(2, rw)] + start: bool, + #[bit(1, rw)] + progress: bool, + #[bit(0, rw)] + completion: bool, } -pub const ACK_ALL: u8 = AckOpts::Acceptance as u8 - | AckOpts::Start as u8 - | AckOpts::Progress as u8 - | AckOpts::Completion as u8; +pub const ACK_ALL: AckFlags = AckFlags::builder() + .with_acceptance(true) + .with_start(true) + .with_progress(true) + .with_completion(true) + .build(); + +impl AckFlags { + pub const ALL: Self = ACK_ALL; +} pub trait GenericPusTcSecondaryHeader { - fn pus_version(&self) -> Result; - fn ack_flags(&self) -> u8; + fn pus_version(&self) -> Result; + fn ack_flags(&self) -> AckFlags; fn service(&self) -> u8; fn subservice(&self) -> u8; fn source_id(&self) -> u16; } pub mod zc { - use crate::ecss::tc::GenericPusTcSecondaryHeader; + use crate::ecss::tc::{AckFlags, GenericPusTcSecondaryHeader}; use crate::ecss::{PusError, PusVersion}; + use arbitrary_int::traits::Integer; + use arbitrary_int::u4; use zerocopy::{FromBytes, Immutable, IntoBytes, NetworkEndian, Unaligned, U16}; #[derive(FromBytes, IntoBytes, Immutable, Unaligned)] @@ -104,10 +120,10 @@ pub mod zc { type Error = PusError; fn try_from(value: crate::ecss::tc::PusTcSecondaryHeader) -> Result { if value.version != PusVersion::PusC { - return Err(PusError::VersionNotSupported(value.version as u8)); + return Err(PusError::VersionNotSupported(value.version.raw_value())); } Ok(PusTcSecondaryHeader { - version_ack: ((value.version as u8) << 4) | value.ack, + version_ack: ((value.version as u8) << 4) | value.ack_flags.raw_value().as_u8(), service: value.service, subservice: value.subservice, source_id: U16::from(value.source_id), @@ -117,13 +133,13 @@ pub mod zc { impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { #[inline] - fn pus_version(&self) -> Result { - PusVersion::try_from((self.version_ack >> 4) & 0b1111) + fn pus_version(&self) -> Result { + PusVersion::try_from(u4::new((self.version_ack >> 4) & 0b1111)) } #[inline] - fn ack_flags(&self) -> u8 { - self.version_ack & 0b1111 + fn ack_flags(&self) -> AckFlags { + AckFlags::new_with_raw_value(u4::new(self.version_ack & 0b1111)) } #[inline] @@ -150,19 +166,19 @@ pub struct PusTcSecondaryHeader { pub service: u8, pub subservice: u8, pub source_id: u16, - pub ack: u8, + pub ack_flags: AckFlags, pub version: PusVersion, } impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { Ok(self.version) } #[inline] - fn ack_flags(&self) -> u8 { - self.ack + fn ack_flags(&self) -> AckFlags { + self.ack_flags } #[inline] @@ -189,30 +205,32 @@ impl TryFrom for PusTcSecondaryHeader { service: value.service(), subservice: value.subservice(), source_id: value.source_id(), - ack: value.ack_flags(), + ack_flags: value.ack_flags(), version: PUS_VERSION, }) } } impl PusTcSecondaryHeader { + pub const HEADER_LEN: usize = PUC_TC_SECONDARY_HEADER_LEN; + #[inline] pub fn new_simple(service: u8, subservice: u8) -> Self { PusTcSecondaryHeader { service, subservice, - ack: ACK_ALL, + ack_flags: ACK_ALL, source_id: 0, version: PusVersion::PusC, } } #[inline] - pub fn new(service: u8, subservice: u8, ack: u8, source_id: u16) -> Self { + pub fn new(service: u8, subservice: u8, ack_flags: AckFlags, source_id: u16) -> Self { PusTcSecondaryHeader { service, subservice, - ack: ack & 0b1111, + ack_flags, source_id, version: PusVersion::PusC, } @@ -307,12 +325,8 @@ impl<'app_data> PusTcCreator<'app_data> { } #[inline] - pub fn set_ack_field(&mut self, ack: u8) -> bool { - if ack > 0b1111 { - return false; - } - self.sec_header.ack = ack & 0b1111; - true + pub fn set_ack_flags(&mut self, ack_flags: AckFlags) { + self.sec_header.ack_flags = ack_flags; } #[inline] @@ -462,7 +476,7 @@ impl CcsdsPacket for PusTcCreator<'_> { impl PusPacket for PusTcCreator<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -490,7 +504,7 @@ impl PusPacket for PusTcCreator<'_> { impl GenericPusTcSecondaryHeader for PusTcCreator<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -498,7 +512,7 @@ impl GenericPusTcSecondaryHeader for PusTcCreator<'_> { #[inline] fn source_id(&self) -> u16; #[inline] - fn ack_flags(&self) -> u8; + fn ack_flags(&self) -> AckFlags; }); } @@ -570,9 +584,10 @@ impl<'buf> PusTcCreatorWithReservedAppData<'buf> { curr_idx += CCSDS_HEADER_LEN; let sec_header_len = size_of::(); let sec_header_zc = zc::PusTcSecondaryHeader::try_from(sec_header).unwrap(); + // Unwrap okay, this can not fail. sec_header_zc .write_to(&mut buf[curr_idx..curr_idx + sec_header_len]) - .map_err(|_| ByteConversionError::ZeroCopyToError)?; + .unwrap(); curr_idx += sec_header_len; let app_data_offset = curr_idx; curr_idx += app_data_len; @@ -750,10 +765,11 @@ impl<'raw_data> PusTcReader<'raw_data> { } .into()); } + // Unwrap okay, this can not fail. let sec_header = zc::PusTcSecondaryHeader::read_from_bytes( - &slice[current_idx..current_idx + PUC_TC_SECONDARY_HEADER_LEN], + &slice[current_idx..current_idx + core::mem::size_of::()], ) - .map_err(|_| ByteConversionError::ZeroCopyFromError)?; + .unwrap(); current_idx += PUC_TC_SECONDARY_HEADER_LEN; let raw_data = &slice[0..total_len]; let mut crc16 = None; @@ -809,7 +825,7 @@ impl CcsdsPacket for PusTcReader<'_> { impl PusPacket for PusTcReader<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -834,7 +850,7 @@ impl PusPacket for PusTcReader<'_> { impl GenericPusTcSecondaryHeader for PusTcReader<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -842,7 +858,7 @@ impl GenericPusTcSecondaryHeader for PusTcReader<'_> { #[inline] fn source_id(&self) -> u16; #[inline] - fn ack_flags(&self) -> u8; + fn ack_flags(&self) -> AckFlags; }); } @@ -873,17 +889,18 @@ mod tests { use crate::{CcsdsPacket, SequenceFlags}; use alloc::string::ToString; use alloc::vec::Vec; + use arbitrary_int::traits::Integer; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; 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(u11::new(0x02), u14::new(0x34), 0); let tc_header = PusTcSecondaryHeader::new_simple(17, 1); 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 sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); let tc_header = PusTcSecondaryHeader::new_simple(17, 1); PusTcCreator::new_no_app_data( sph, @@ -896,12 +913,12 @@ mod tests { } 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(u11::new(0x02), u14::new(0x34), 0); PusTcCreator::new_simple(sph, 17, 1, &[], CreatorConfig::default()) } 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(u11::new(0x02), u14::new(0x34), 0); PusTcCreator::new_simple( sph, 17, @@ -918,7 +935,7 @@ mod tests { app_data: &'static [u8], has_checksum: bool, ) -> PusTcCreator<'static> { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); PusTcCreator::new_simple( sph, 17, @@ -1052,7 +1069,7 @@ mod tests { #[test] fn test_deserialization_alt_ctor() { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); let tc_header = PusTcSecondaryHeader::new_simple(17, 1); let mut test_buf: [u8; 32] = [0; 32]; let mut pus_tc = @@ -1105,7 +1122,7 @@ mod tests { #[test] fn test_update_func() { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); let mut tc = PusTcCreator::new_simple( sph, 17, @@ -1278,15 +1295,15 @@ mod tests { fn test_custom_setters() { let mut pus_tc = base_ping_tc_simple_ctor(); let mut test_buf: [u8; 32] = [0; 32]; - pus_tc.set_apid(0x7ff); - pus_tc.set_seq_count(0x3fff); - pus_tc.set_ack_field(0b11); + pus_tc.set_apid(u11::new(0x7ff)); + pus_tc.set_seq_count(u14::new(0x3fff)); + pus_tc.set_ack_flags(AckFlags::new_with_raw_value(u4::new(0b11))); pus_tc.set_source_id(0xffff); pus_tc.set_seq_flags(SequenceFlags::Unsegmented); - assert_eq!(pus_tc.source_id(), 0xffff); - assert_eq!(pus_tc.seq_count(), 0x3fff); - assert_eq!(pus_tc.ack_flags(), 0b11); - assert_eq!(pus_tc.apid(), 0x7ff); + assert_eq!(pus_tc.source_id().value(), 0xffff); + assert_eq!(pus_tc.seq_count().value(), 0x3fff); + assert_eq!(pus_tc.ack_flags().raw_value().value(), 0b11); + assert_eq!(pus_tc.apid().value(), 0x7ff); assert_eq!(pus_tc.sequence_flags(), SequenceFlags::Unsegmented); pus_tc.calc_own_crc16(); pus_tc @@ -1313,7 +1330,7 @@ mod tests { assert!(tc.user_data().is_empty()); } let mut comp_header = - SpHeader::new_for_unseg_tc_checked(0x02, 0x34, exp_full_len as u16 - 7).unwrap(); + SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), exp_full_len as u16 - 7); comp_header.set_sec_header_flag(); assert_eq!(tc.has_checksum(), has_checksum); @@ -1330,7 +1347,7 @@ mod tests { } assert_eq!(tc.len_packed(), exp_full_len); let mut comp_header = - SpHeader::new_for_unseg_tc_checked(0x02, 0x34, exp_full_len as u16 - 7).unwrap(); + SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), exp_full_len as u16 - 7); comp_header.set_sec_header_flag(); assert_eq!(*tc.sp_header(), comp_header); } @@ -1342,9 +1359,9 @@ mod tests { assert_eq!(GenericPusTcSecondaryHeader::subservice(tc), 1); assert!(tc.sec_header_flag()); assert_eq!(PusPacket::pus_version(tc).unwrap(), PusC); - assert_eq!(tc.seq_count(), 0x34); - assert_eq!(tc.source_id(), 0); - assert_eq!(tc.apid(), 0x02); + assert_eq!(tc.seq_count().value(), 0x34); + assert_eq!(tc.source_id().value(), 0); + assert_eq!(tc.apid().value(), 0x02); assert_eq!(tc.ack_flags(), ACK_ALL); assert_eq!(PusPacket::pus_version(tc).unwrap(), PusVersion::PusC); assert_eq!( @@ -1403,13 +1420,6 @@ mod tests { assert_eq!(PusTcReader::new(&buf).unwrap(), pus_tc); } - #[test] - fn test_ack_opts_from_raw() { - let ack_opts_raw = AckOpts::Start as u8; - let ack_opts = AckOpts::try_from(ack_opts_raw).unwrap(); - assert_eq!(ack_opts, AckOpts::Start); - } - #[test] fn test_reader_buf_too_small() { let app_data = &[1, 2, 3, 4]; diff --git a/src/ecss/tc_pus_a.rs b/src/ecss/tc_pus_a.rs index 22a504c..24b4c64 100644 --- a/src/ecss/tc_pus_a.rs +++ b/src/ecss/tc_pus_a.rs @@ -6,17 +6,18 @@ //! use spacepackets::{CcsdsPacket, SpHeader}; //! use spacepackets::ecss::{PusPacket, WritablePusPacket}; //! use spacepackets::ecss::tc_pus_a::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}; +//! use arbitrary_int::u11; //! //! // Create a ping telecommand with no user application data //! let pus_tc = PusTcCreator::new_no_app_data( -//! SpHeader::new_from_apid(0x02), +//! SpHeader::new_from_apid(u11::new(0x02)), //! PusTcSecondaryHeader::new_simple(17, 1), //! true //! ); //! println!("{:?}", pus_tc); //! assert_eq!(pus_tc.service(), 17); //! assert_eq!(pus_tc.subservice(), 1); -//! assert_eq!(pus_tc.apid(), 0x02); +//! assert_eq!(pus_tc.apid().value(), 0x02); //! //! // Serialize TC into a raw buffer //! let mut test_buf: [u8; 32] = [0; 32]; @@ -30,9 +31,10 @@ //! let pus_tc_deserialized = PusTcReader::new(&test_buf, None, 0).expect("Deserialization failed"); //! assert_eq!(pus_tc.service(), 17); //! assert_eq!(pus_tc.subservice(), 1); -//! assert_eq!(pus_tc.apid(), 0x02); +//! assert_eq!(pus_tc.apid().value(), 0x02); //! ``` use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; +use crate::ecss::tc::{AckFlags, ACK_ALL}; use crate::ecss::{ ccsds_impl, crc_from_raw_data, sp_header_impls, user_data_from_raw, verify_crc16_ccitt_false_from_raw_to_pus_error, PusError, PusPacket, PusVersion, @@ -41,6 +43,7 @@ use crate::ecss::{ use crate::util::{UnsignedByteField, UnsignedEnum}; use crate::SpHeader; use crate::{ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, CCSDS_HEADER_LEN}; +use arbitrary_int::{u11, u14, u3, u4}; use core::mem::size_of; use delegate::delegate; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -81,14 +84,9 @@ pub struct InvalidNumberOfSpareBytesError; #[error("invalid version, expected PUS A (1), got {0}")] pub struct VersionError(pub u8); -pub const ACK_ALL: u8 = AckOpts::Acceptance as u8 - | AckOpts::Start as u8 - | AckOpts::Progress as u8 - | AckOpts::Completion as u8; - pub trait GenericPusTcSecondaryHeader { - fn pus_version(&self) -> Result; - fn ack_flags(&self) -> u8; + fn pus_version(&self) -> Result; + fn ack_flags(&self) -> AckFlags; fn service(&self) -> u8; fn subservice(&self) -> u8; fn source_id(&self) -> Option; @@ -102,19 +100,19 @@ pub struct PusTcSecondaryHeader { pub service: u8, pub subservice: u8, pub source_id: Option, - pub ack: u8, + pub ack: AckFlags, pub version: PusVersion, spare_bytes: usize, } impl GenericPusTcSecondaryHeader for PusTcSecondaryHeader { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { Ok(self.version) } #[inline] - fn ack_flags(&self) -> u8 { + fn ack_flags(&self) -> AckFlags { self.ack } @@ -156,14 +154,14 @@ impl PusTcSecondaryHeader { pub fn new( service: u8, subservice: u8, - ack: u8, + ack: AckFlags, source_id: Option, spare_bytes: usize, ) -> Self { PusTcSecondaryHeader { service, subservice, - ack: ack & 0b1111, + ack, source_id, version: PUS_VERSION, spare_bytes, @@ -201,7 +199,7 @@ impl PusTcSecondaryHeader { }); } let mut current_idx = 0; - buf[0] = ((PUS_VERSION as u8) << 4) | self.ack; + buf[0] = ((PUS_VERSION as u8) << 4) | self.ack.raw_value().value(); buf[1] = self.service; buf[2] = self.subservice; current_idx += 3; @@ -232,11 +230,11 @@ impl PusTcSecondaryHeader { }, )); } - let version = (data[0] >> 4) & 0b111; - if version != PusVersion::PusA as u8 { + let version = u4::new((data[0] >> 4) & 0b111); + if version != PusVersion::PusA.raw_value() { return Err(PusError::VersionNotSupported(version)); } - let ack = data[0] & 0b1111; + let ack_flags_raw = u4::new(data[0] & 0b1111); let service = data[1]; let subservice = data[2]; let mut source_id = None; @@ -250,7 +248,7 @@ impl PusTcSecondaryHeader { service, subservice, source_id, - ack, + ack: AckFlags::new_with_raw_value(ack_flags_raw), version: PusVersion::PusA, spare_bytes, }) @@ -345,12 +343,8 @@ impl<'app_data> PusTcCreator<'app_data> { } #[inline] - pub fn set_ack_field(&mut self, ack: u8) -> bool { - if ack > 0b1111 { - return false; - } - self.sec_header.ack = ack & 0b1111; - true + pub fn set_ack_field(&mut self, ack: AckFlags) { + self.sec_header.ack = ack; } #[inline] @@ -495,7 +489,7 @@ impl CcsdsPacket for PusTcCreator<'_> { impl PusPacket for PusTcCreator<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -516,7 +510,7 @@ impl PusPacket for PusTcCreator<'_> { impl GenericPusTcSecondaryHeader for PusTcCreator<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -524,7 +518,7 @@ impl GenericPusTcSecondaryHeader for PusTcCreator<'_> { #[inline] fn source_id(&self) -> Option; #[inline] - fn ack_flags(&self) -> u8; + fn ack_flags(&self) -> AckFlags; #[inline] fn spare_bytes(&self) -> usize; }); @@ -730,8 +724,7 @@ impl<'raw_data> PusTcReader<'raw_data> { .into()); } let sec_header = - PusTcSecondaryHeader::from_bytes(&slice[current_idx..], source_id_size, spare_bytes) - .map_err(|_| ByteConversionError::ZeroCopyFromError)?; + PusTcSecondaryHeader::from_bytes(&slice[current_idx..], source_id_size, spare_bytes)?; current_idx += sec_header.written_len(); let raw_data = &slice[0..total_len]; Ok(Self { @@ -787,7 +780,7 @@ impl PusPacket for PusTcReader<'_> { #[inline] fn subservice(&self) -> u8; #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; }); #[inline] @@ -809,7 +802,7 @@ impl PusPacket for PusTcReader<'_> { impl GenericPusTcSecondaryHeader for PusTcReader<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -817,7 +810,7 @@ impl GenericPusTcSecondaryHeader for PusTcReader<'_> { #[inline] fn source_id(&self) -> Option; #[inline] - fn ack_flags(&self) -> u8; + fn ack_flags(&self) -> AckFlags; #[inline] fn spare_bytes(&self) -> usize; }); @@ -852,22 +845,23 @@ mod tests { use crate::{CcsdsPacket, SequenceFlags}; use alloc::string::ToString; use alloc::vec::Vec; + use arbitrary_int::{u11, u14}; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; 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(u11::new(0x02), u14::new(0x34), 0); let tc_header = PusTcSecondaryHeader::new_simple(17, 1); PusTcCreator::new_no_app_data(sph, tc_header, true) } 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(u11::new(0x02), u14::new(0x34), 0); PusTcCreator::new_simple(sph, 17, 1, &[], true) } fn base_ping_tc_simple_ctor_with_app_data(app_data: &'static [u8]) -> PusTcCreator<'static> { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); PusTcCreator::new_simple(sph, 17, 1, app_data, true) } @@ -974,7 +968,7 @@ mod tests { #[test] fn test_deserialization_alt_ctor() { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); let tc_header = PusTcSecondaryHeader::new_simple(17, 1); let mut test_buf: [u8; 32] = [0; 32]; let mut pus_tc = @@ -1027,7 +1021,7 @@ mod tests { #[test] fn test_update_func() { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); let mut tc = PusTcCreator::new_simple(sph, 17, 1, &[], false); assert_eq!(tc.data_len(), 0); tc.update_ccsds_data_len(); @@ -1168,16 +1162,16 @@ mod tests { fn test_custom_setters() { let mut pus_tc = base_ping_tc_simple_ctor(); let mut test_buf: [u8; 32] = [0; 32]; - pus_tc.set_apid(0x7ff); - pus_tc.set_seq_count(0x3fff); - pus_tc.set_ack_field(0b11); + pus_tc.set_apid(u11::new(0x7ff)); + pus_tc.set_seq_count(u14::new(0x3fff)); + pus_tc.set_ack_field(AckFlags::new_with_raw_value(u4::new(0b11))); let source_id = UnsignedByteFieldU16::new(0xffff).into(); pus_tc.set_source_id(Some(source_id)); pus_tc.set_seq_flags(SequenceFlags::Unsegmented); assert_eq!(pus_tc.source_id(), Some(source_id)); - assert_eq!(pus_tc.seq_count(), 0x3fff); - assert_eq!(pus_tc.ack_flags(), 0b11); - assert_eq!(pus_tc.apid(), 0x7ff); + assert_eq!(pus_tc.seq_count().value(), 0x3fff); + assert_eq!(pus_tc.ack_flags().raw_value().value(), 0b11); + assert_eq!(pus_tc.apid().value(), 0x7ff); assert_eq!(pus_tc.sequence_flags(), SequenceFlags::Unsegmented); pus_tc.calc_own_crc16(); pus_tc @@ -1199,7 +1193,7 @@ mod tests { assert!(tc.user_data().is_empty()); } let mut comp_header = - SpHeader::new_for_unseg_tc_checked(0x02, 0x34, exp_full_len as u16 - 7).unwrap(); + SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), exp_full_len as u16 - 7); comp_header.set_sec_header_flag(); assert_eq!(*tc.sp_header(), comp_header); } @@ -1211,7 +1205,7 @@ mod tests { } assert_eq!(tc.len_packed(), exp_full_len); let mut comp_header = - SpHeader::new_for_unseg_tc_checked(0x02, 0x34, exp_full_len as u16 - 7).unwrap(); + SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), exp_full_len as u16 - 7); comp_header.set_sec_header_flag(); assert_eq!(*tc.sp_header(), comp_header); } @@ -1223,9 +1217,9 @@ mod tests { assert_eq!(GenericPusTcSecondaryHeader::subservice(tc), 1); assert!(tc.sec_header_flag()); assert_eq!(PusPacket::pus_version(tc).unwrap(), PusVersion::PusA); - assert_eq!(tc.seq_count(), 0x34); + assert_eq!(tc.seq_count().value(), 0x34); assert!(tc.source_id().is_none()); - assert_eq!(tc.apid(), 0x02); + assert_eq!(tc.apid().value(), 0x02); assert_eq!(tc.ack_flags(), ACK_ALL); assert_eq!(PusPacket::pus_version(tc).unwrap(), PusVersion::PusA); assert_eq!( @@ -1329,9 +1323,9 @@ mod tests { #[test] fn test_with_source_id_and_spare_bytes() { - let sph = SpHeader::new_for_unseg_tc_checked(0x02, 0x34, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tc(u11::new(0x02), u14::new(0x34), 0); let source_id = UnsignedByteFieldU8::new(5).into(); - let tc_header = PusTcSecondaryHeader::new(17, 1, 0b1111, Some(source_id), 2); + let tc_header = PusTcSecondaryHeader::new(17, 1, AckFlags::ALL, Some(source_id), 2); let creator = PusTcCreator::new(sph, tc_header, &[1, 2, 3], true); assert_eq!(creator.len_written(), 17); let mut buf: [u8; 32] = [0; 32]; diff --git a/src/ecss/tm.rs b/src/ecss/tm.rs index 03575ca..eb11e39 100644 --- a/src/ecss/tm.rs +++ b/src/ecss/tm.rs @@ -9,6 +9,7 @@ //! use spacepackets::{CcsdsPacket, SpHeader}; //! use spacepackets::ecss::{PusPacket, WritablePusPacket}; //! use spacepackets::ecss::tm::{PusTmCreator, PusTmReader, PusTmSecondaryHeader, CreatorConfig}; +//! use arbitrary_int::u11; //! //! let mut time_buf: [u8; 7] = [0; 7]; //! let time_now = CdsTime::now_with_u16_days().expect("creating CDS timestamp failed"); @@ -17,14 +18,14 @@ //! //! // Create a ping telemetry with no user source data //! let ping_tm = PusTmCreator::new_no_source_data( -//! SpHeader::new_from_apid(0x02), +//! SpHeader::new_from_apid(u11::new(0x02)), //! PusTmSecondaryHeader::new_simple(17, 2, &time_buf), //! CreatorConfig::default() //! ); //! println!("{:?}", ping_tm); //! assert_eq!(ping_tm.service(), 17); //! assert_eq!(ping_tm.subservice(), 2); -//! assert_eq!(ping_tm.apid(), 0x02); +//! assert_eq!(ping_tm.apid().value(), 0x02); //! //! // Serialize TM into a raw buffer //! let mut test_buf: [u8; 32] = [0; 32]; @@ -39,7 +40,7 @@ //! assert_eq!(written_size, ping_tm_reader.packet_len()); //! assert_eq!(ping_tm_reader.service(), 17); //! assert_eq!(ping_tm_reader.subservice(), 2); -//! assert_eq!(ping_tm_reader.apid(), 0x02); +//! assert_eq!(ping_tm_reader.apid().value(), 0x02); //! assert_eq!(ping_tm_reader.timestamp(), &time_buf); //! ``` use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; @@ -51,8 +52,10 @@ use crate::ecss::{ }; use crate::{ ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN, - MAX_APID, MAX_SEQ_COUNT, + MAX_APID, }; +use arbitrary_int::traits::Integer; +use arbitrary_int::{u11, u14, u3, u4}; use core::mem::size_of; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -75,8 +78,8 @@ pub const PUS_TM_MIN_SEC_HEADER_LEN: usize = 7; pub const PUS_TM_MIN_LEN_WITHOUT_SOURCE_DATA: usize = CCSDS_HEADER_LEN + PUS_TM_MIN_SEC_HEADER_LEN; pub trait GenericPusTmSecondaryHeader { - fn pus_version(&self) -> Result; - fn sc_time_ref_status(&self) -> u8; + fn pus_version(&self) -> Result; + fn sc_time_ref_status(&self) -> u4; fn service(&self) -> u8; fn subservice(&self) -> u8; fn msg_counter(&self) -> u16; @@ -86,6 +89,7 @@ pub trait GenericPusTmSecondaryHeader { pub mod zc { use super::GenericPusTmSecondaryHeader; use crate::ecss::{PusError, PusVersion}; + use arbitrary_int::{traits::Integer as _, u4}; use zerocopy::{FromBytes, Immutable, IntoBytes, NetworkEndian, Unaligned, U16}; #[derive(FromBytes, IntoBytes, Immutable, Unaligned)] @@ -107,11 +111,13 @@ pub mod zc { type Error = PusError; fn try_from(header: crate::ecss::tm::PusTmSecondaryHeader) -> Result { if header.pus_version != PusVersion::PusC { - return Err(PusError::VersionNotSupported(header.pus_version as u8)); + return Err(PusError::VersionNotSupported(u4::new( + header.pus_version as u8, + ))); } Ok(PusTmSecHeaderWithoutTimestamp { pus_version_and_sc_time_ref_status: ((header.pus_version as u8) << 4) - | header.sc_time_ref_status, + | header.sc_time_ref_status.as_u8(), service: header.service, subservice: header.subservice, msg_counter: U16::from(header.msg_counter), @@ -122,13 +128,15 @@ pub mod zc { impl GenericPusTmSecondaryHeader for PusTmSecHeaderWithoutTimestamp { #[inline] - fn pus_version(&self) -> Result { - PusVersion::try_from((self.pus_version_and_sc_time_ref_status >> 4) & 0b1111) + fn pus_version(&self) -> Result { + PusVersion::try_from(u4::new( + (self.pus_version_and_sc_time_ref_status >> 4) & 0b1111, + )) } #[inline] - fn sc_time_ref_status(&self) -> u8 { - self.pus_version_and_sc_time_ref_status & 0b1111 + fn sc_time_ref_status(&self) -> u4 { + u4::new(self.pus_version_and_sc_time_ref_status & 0b1111) } #[inline] @@ -158,7 +166,7 @@ pub mod zc { #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PusTmSecondaryHeader<'stamp> { pus_version: PusVersion, - pub sc_time_ref_status: u8, + pub sc_time_ref_status: u4, pub service: u8, pub subservice: u8, pub msg_counter: u16, @@ -188,7 +196,7 @@ impl<'stamp> PusTmSecondaryHeader<'stamp> { ) -> Self { PusTmSecondaryHeader { pus_version: PusVersion::PusC, - sc_time_ref_status: 0, + sc_time_ref_status: u4::new(0), service, subservice, msg_counter, @@ -200,12 +208,12 @@ impl<'stamp> PusTmSecondaryHeader<'stamp> { impl GenericPusTmSecondaryHeader for PusTmSecondaryHeader<'_> { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { Ok(self.pus_version) } #[inline] - fn sc_time_ref_status(&self) -> u8 { + fn sc_time_ref_status(&self) -> u4 { self.sc_time_ref_status } @@ -362,8 +370,8 @@ impl<'time, 'src_data> PusTmCreator<'time, 'src_data> { } #[inline] - pub fn set_sc_time_ref_status(&mut self, sc_time_ref_status: u8) { - self.sec_header.sc_time_ref_status = sc_time_ref_status & 0b1111; + pub fn set_sc_time_ref_status(&mut self, sc_time_ref_status: u4) { + self.sec_header.sc_time_ref_status = sc_time_ref_status; } sp_header_impls!(); @@ -513,7 +521,7 @@ impl CcsdsPacket for PusTmCreator<'_, '_> { impl PusPacket for PusTmCreator<'_, '_> { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { Ok(self.sec_header.pus_version) } @@ -546,7 +554,7 @@ impl PusPacket for PusTmCreator<'_, '_> { impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -556,7 +564,7 @@ impl GenericPusTmSecondaryHeader for PusTmCreator<'_, '_> { #[inline] fn msg_counter(&self) -> u16; #[inline] - fn sc_time_ref_status(&self) -> u8; + fn sc_time_ref_status(&self) -> u4; }); } @@ -629,9 +637,10 @@ impl<'buf> PusTmCreatorWithReservedSourceData<'buf> { curr_idx += CCSDS_HEADER_LEN; let sec_header_len = size_of::(); let sec_header_zc = zc::PusTmSecHeaderWithoutTimestamp::try_from(sec_header).unwrap(); + // Unwrap okay, this can not fail. sec_header_zc .write_to(&mut buf[curr_idx..curr_idx + sec_header_len]) - .map_err(|_| ByteConversionError::ZeroCopyToError)?; + .unwrap(); curr_idx += sec_header_len; buf[curr_idx..curr_idx + sec_header.timestamp.len()].copy_from_slice(sec_header.timestamp); curr_idx += sec_header.timestamp.len(); @@ -832,10 +841,12 @@ impl<'raw_data> PusTmReader<'raw_data> { } .into()); } + let sec_header_len = core::mem::size_of::(); + // Unwrap okay, this can not fail. let sec_header_zc = zc::PusTmSecHeaderWithoutTimestamp::read_from_bytes( - &slice[current_idx..current_idx + PUS_TM_MIN_SEC_HEADER_LEN], + &slice[current_idx..current_idx + sec_header_len], ) - .map_err(|_| ByteConversionError::ZeroCopyFromError)?; + .unwrap(); current_idx += PUS_TM_MIN_SEC_HEADER_LEN; let zc_sec_header_wrapper = zc::PusTmSecHeader { zc_header: sec_header_zc, @@ -904,7 +915,7 @@ impl CcsdsPacket for PusTmReader<'_> { impl PusPacket for PusTmReader<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -930,7 +941,7 @@ impl PusPacket for PusTmReader<'_> { impl GenericPusTmSecondaryHeader for PusTmReader<'_> { delegate!(to self.sec_header { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] fn service(&self) -> u8; #[inline] @@ -940,7 +951,7 @@ impl GenericPusTmSecondaryHeader for PusTmReader<'_> { #[inline] fn msg_counter(&self) -> u16; #[inline] - fn sc_time_ref_status(&self) -> u8; + fn sc_time_ref_status(&self) -> u4; }); } @@ -1008,13 +1019,11 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { /// Set the sequence count. Returns false and does not update the value if the passed value /// exceeds [MAX_APID]. #[inline] - pub fn set_apid(&mut self, apid: u16) -> bool { - if apid > MAX_APID { - return false; - } + pub fn set_apid(&mut self, apid: u11) -> bool { // Clear APID part of the raw packet ID - let updated_apid = - ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16) & !MAX_APID) | apid; + let updated_apid = ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16) + & !MAX_APID.as_u16()) + | apid.as_u16(); self.raw_tm[0..2].copy_from_slice(&updated_apid.to_be_bytes()); true } @@ -1049,15 +1058,10 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { .unwrap() } - /// Set the sequence count. Returns false and does not update the value if the passed value - /// exceeds [MAX_SEQ_COUNT]. #[inline] - pub fn set_seq_count(&mut self, seq_count: u16) -> bool { - if seq_count > MAX_SEQ_COUNT { - return false; - } - let new_psc = - (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000) | seq_count; + pub fn set_seq_count(&mut self, seq_count: u14) -> bool { + let new_psc = (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000) + | seq_count.as_u16(); self.raw_tm[2..4].copy_from_slice(&new_psc.to_be_bytes()); true } @@ -1075,7 +1079,7 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { impl CcsdsPacket for PusTmZeroCopyWriter<'_> { #[inline] - fn ccsds_version(&self) -> u8 { + fn ccsds_version(&self) -> u3 { self.sp_header().ccsds_version() } @@ -1085,7 +1089,7 @@ impl CcsdsPacket for PusTmZeroCopyWriter<'_> { } #[inline] - fn psc(&self) -> crate::PacketSequenceCtrl { + fn psc(&self) -> crate::PacketSequenceControl { self.sp_header().psc() } @@ -1097,7 +1101,7 @@ impl CcsdsPacket for PusTmZeroCopyWriter<'_> { impl PusPacket for PusTmZeroCopyWriter<'_> { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { self.sec_header_without_timestamp().pus_version() } @@ -1144,9 +1148,9 @@ impl GenericPusTmSecondaryHeader for PusTmZeroCopyWriter<'_> { delegate! { to self.sec_header_without_timestamp() { #[inline] - fn pus_version(&self) -> Result; + fn pus_version(&self) -> Result; #[inline] - fn sc_time_ref_status(&self) -> u8; + fn sc_time_ref_status(&self) -> u4; #[inline] fn msg_counter(&self) -> u16; #[inline] @@ -1170,24 +1174,24 @@ mod tests { use alloc::string::ToString; use super::*; - use crate::ecss::PusVersion::PusC; use crate::time::cds::CdsTime; #[cfg(feature = "serde")] use crate::time::CcsdsTimeProvider; use crate::SpHeader; + use crate::{ecss::PusVersion::PusC, MAX_SEQ_COUNT}; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; const DUMMY_DATA: &[u8] = &[0, 1, 2]; 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(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); 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 sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); PusTmCreator::new_no_source_data( sph, @@ -1199,13 +1203,13 @@ mod tests { ) } 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(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); 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> { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp); PusTmCreator::new(sph, tc_header, src_data, CreatorConfig::default()) } @@ -1214,7 +1218,7 @@ mod tests { 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(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp); PusTmCreator::new( sph, @@ -1247,7 +1251,7 @@ mod tests { #[test] fn test_basic_simple_api() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = PusTmCreator::new_simple( @@ -1278,7 +1282,7 @@ mod tests { #[test] fn test_serialization_no_source_data_alt_ctor() { let timestamp = dummy_timestamp(); - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let mut buf: [u8; 32] = [0; 32]; let mut pus_tm = @@ -1294,7 +1298,7 @@ mod tests { #[test] fn test_serialization_no_source_data_alt_ctor_no_checksum_verification() { let timestamp = dummy_timestamp(); - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let mut buf: [u8; 32] = [0; 32]; let mut pus_tm = @@ -1312,7 +1316,7 @@ mod tests { #[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 sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let mut buf: [u8; 32] = [0; 32]; let mut pus_tm = @@ -1388,7 +1392,7 @@ mod tests { fn test_serialization_with_source_data_alt_ctor() { let src_data = &[1, 2, 3]; let mut buf: [u8; 32] = [0; 32]; - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp()); let mut hk_reply_unwritten = PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3, true).unwrap(); @@ -1408,7 +1412,7 @@ mod tests { fn test_serialization_with_source_data_alt_ctor_no_table() { let src_data = &[1, 2, 3]; let mut buf: [u8; 32] = [0; 32]; - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp()); let mut hk_reply_unwritten = PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3, true).unwrap(); @@ -1428,14 +1432,14 @@ mod tests { fn test_setters() { let timestamp = dummy_timestamp(); let mut pus_tm = base_ping_reply_full_ctor(timestamp); - pus_tm.set_sc_time_ref_status(0b1010); + pus_tm.set_sc_time_ref_status(u4::new(0b1010)); pus_tm.set_dest_id(0x7fff); pus_tm.set_msg_counter(0x1f1f); - assert_eq!(pus_tm.sc_time_ref_status(), 0b1010); + assert_eq!(pus_tm.sc_time_ref_status().value(), 0b1010); assert_eq!(pus_tm.dest_id(), 0x7fff); assert_eq!(pus_tm.msg_counter(), 0x1f1f); - assert!(pus_tm.set_apid(0x7ff)); - assert_eq!(pus_tm.apid(), 0x7ff); + pus_tm.set_apid(u11::new(0x7ff)); + assert_eq!(pus_tm.apid().value(), 0x7ff); } #[test] @@ -1564,7 +1568,7 @@ mod tests { #[test] fn test_manual_field_update() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp()); let mut tm = PusTmCreator::new_no_source_data( sph, @@ -1730,8 +1734,8 @@ mod tests { assert!(!tm.user_data().is_empty()); } assert_eq!(PusPacket::pus_version(tm).unwrap(), PusC); - assert_eq!(tm.apid(), 0x123); - assert_eq!(tm.seq_count(), 0x234); + assert_eq!(tm.apid().value(), 0x123); + assert_eq!(tm.seq_count().value(), 0x234); assert_eq!(PusPacket::pus_version(tm).unwrap(), PusVersion::PusC); assert_eq!( GenericPusTmSecondaryHeader::pus_version(tm).unwrap(), @@ -1740,7 +1744,7 @@ mod tests { assert_eq!(tm.data_len(), exp_full_len as u16 - 7); assert_eq!(tm.dest_id(), 0x0000); assert_eq!(tm.msg_counter(), 0x0000); - assert_eq!(tm.sc_time_ref_status(), 0b0000); + assert_eq!(tm.sc_time_ref_status().value(), 0b0000); } #[test] @@ -1773,8 +1777,6 @@ mod tests { writer.set_msg_count(100); writer.set_seq_count(MAX_SEQ_COUNT); writer.set_apid(MAX_APID); - assert!(!writer.set_apid(MAX_APID + 1)); - assert!(!writer.set_apid(MAX_SEQ_COUNT + 1)); writer.finish(); // This performs all necessary checks, including the CRC check. let tm_read_back = PusTmReader::new(&buf, 7).expect("Re-creating PUS TM failed"); @@ -1895,7 +1897,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serialization_creator_serde() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = PusTmCreator::new_simple( @@ -1917,7 +1919,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serialization_reader_serde() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = PusTmCreator::new_simple( diff --git a/src/ecss/tm_pus_a.rs b/src/ecss/tm_pus_a.rs index 4c9e7c7..aeffc1b 100644 --- a/src/ecss/tm_pus_a.rs +++ b/src/ecss/tm_pus_a.rs @@ -13,6 +13,7 @@ //! PusTmSecondaryHeader, //! SecondaryHeaderParameters //! }; +//! use arbitrary_int::u11; //! //! let mut time_buf: [u8; 7] = [0; 7]; //! let time_now = CdsTime::now_with_u16_days().expect("creating CDS timestamp failed"); @@ -21,14 +22,14 @@ //! //! // Create a ping telemetry with no user source data //! let ping_tm = PusTmCreator::new_no_source_data( -//! SpHeader::new_from_apid(0x02), +//! SpHeader::new_from_apid(u11::new(0x02)), //! PusTmSecondaryHeader::new_simple(17, 2, &time_buf), //! true //! ); //! println!("{:?}", ping_tm); //! assert_eq!(ping_tm.service(), 17); //! assert_eq!(ping_tm.subservice(), 2); -//! assert_eq!(ping_tm.apid(), 0x02); +//! assert_eq!(ping_tm.apid().value(), 0x02); //! //! // Serialize TM into a raw buffer //! let mut test_buf: [u8; 32] = [0; 32]; @@ -43,7 +44,7 @@ //! assert_eq!(written_size, ping_tm_reader.packet_len()); //! assert_eq!(ping_tm_reader.service(), 17); //! assert_eq!(ping_tm_reader.subservice(), 2); -//! assert_eq!(ping_tm_reader.apid(), 0x02); +//! assert_eq!(ping_tm_reader.apid().value(), 0x02); //! assert_eq!(ping_tm_reader.timestamp(), &time_buf); //! ``` use crate::crc::{CRC_CCITT_FALSE, CRC_CCITT_FALSE_NO_TABLE}; @@ -55,8 +56,10 @@ use crate::ecss::{ use crate::util::{UnsignedByteField, UnsignedEnum}; use crate::{ ByteConversionError, CcsdsPacket, PacketType, SequenceFlags, SpHeader, CCSDS_HEADER_LEN, - MAX_APID, MAX_SEQ_COUNT, + MAX_APID, }; +use arbitrary_int::traits::Integer; +use arbitrary_int::{u11, u14, u3, u4}; use core::mem::size_of; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; @@ -162,13 +165,13 @@ impl<'stamp> PusTmSecondaryHeader<'stamp> { } .into()); } - let pus_version = PusVersion::try_from((buf[0] >> 4) & 0x0F); + let pus_version = PusVersion::try_from(u4::new((buf[0] >> 4) & 0x0F)); if let Err(version_raw) = pus_version { return Err(PusError::VersionNotSupported(version_raw)); } let pus_version = pus_version.unwrap(); if pus_version != PusVersion::PusA { - return Err(PusError::VersionNotSupported(pus_version as u8)); + return Err(PusError::VersionNotSupported(pus_version.raw_value())); } let mut msg_counter = None; let mut current_idx = 3; @@ -543,7 +546,7 @@ impl CcsdsPacket for PusTmCreator<'_, '_> { impl PusPacket for PusTmCreator<'_, '_> { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { Ok(self.sec_header.pus_version) } @@ -842,7 +845,7 @@ impl CcsdsPacket for PusTmReader<'_> { impl PusPacket for PusTmReader<'_> { #[inline] - fn pus_version(&self) -> Result { + fn pus_version(&self) -> Result { Ok(self.sec_header.pus_version) } @@ -958,15 +961,12 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { /// Set the sequence count. Returns false and does not update the value if the passed value /// exceeds [MAX_APID]. #[inline] - pub fn set_apid(&mut self, apid: u16) -> bool { - if apid > MAX_APID { - return false; - } + pub fn set_apid(&mut self, apid: u11) { // Clear APID part of the raw packet ID - let updated_apid = - ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16) & !MAX_APID) | apid; + let updated_apid = ((((self.raw_tm[0] as u16) << 8) | self.raw_tm[1] as u16) + & !MAX_APID.as_u16()) + | apid.as_u16(); self.raw_tm[0..2].copy_from_slice(&updated_apid.to_be_bytes()); - true } pub fn dest_id(&self) -> Result, ByteConversionError> { @@ -1054,17 +1054,11 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { crate::zc::SpHeader::read_from_bytes(&self.raw_tm[0..CCSDS_HEADER_LEN]).unwrap() } - /// Set the sequence count. Returns false and does not update the value if the passed value - /// exceeds [MAX_SEQ_COUNT]. #[inline] - pub fn set_seq_count(&mut self, seq_count: u16) -> bool { - if seq_count > MAX_SEQ_COUNT { - return false; - } - let new_psc = - (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000) | seq_count; + pub fn set_seq_count(&mut self, seq_count: u14) { + let new_psc = (u16::from_be_bytes(self.raw_tm[2..4].try_into().unwrap()) & 0xC000) + | seq_count.as_u16(); self.raw_tm[2..4].copy_from_slice(&new_psc.to_be_bytes()); - true } /// This method has to be called after modifying fields to ensure the CRC16 of the telemetry @@ -1078,7 +1072,7 @@ impl<'raw> PusTmZeroCopyWriter<'raw> { impl CcsdsPacket for PusTmZeroCopyWriter<'_> { #[inline] - fn ccsds_version(&self) -> u8 { + fn ccsds_version(&self) -> u3 { self.sp_header().ccsds_version() } @@ -1088,7 +1082,7 @@ impl CcsdsPacket for PusTmZeroCopyWriter<'_> { } #[inline] - fn psc(&self) -> crate::PacketSequenceCtrl { + fn psc(&self) -> crate::PacketSequenceControl { self.sp_header().psc() } @@ -1100,8 +1094,8 @@ impl CcsdsPacket for PusTmZeroCopyWriter<'_> { impl PusPacket for PusTmZeroCopyWriter<'_> { #[inline] - fn pus_version(&self) -> Result { - PusVersion::try_from(self.raw_tm[6]) + fn pus_version(&self) -> Result { + PusVersion::try_from(u4::new((self.raw_tm[6] >> 4) & 0b1111)) } #[inline] @@ -1138,8 +1132,8 @@ mod tests { use super::*; use crate::time::cds::CdsTime; - use crate::SpHeader; use crate::{ecss::PusVersion::PusA, util::UnsignedByteFieldU16}; + use crate::{SpHeader, MAX_SEQ_COUNT}; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; @@ -1151,7 +1145,7 @@ mod tests { timestamp: &'a [u8], dest_id: Option, ) -> PusTmCreator<'a, 'b> { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let mut tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); tm_header.dest_id = dest_id; PusTmCreator::new_no_source_data(sph, tm_header, true) @@ -1163,19 +1157,19 @@ mod tests { dest_id: Option, 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(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new(17, 2, msg_counter, dest_id, timestamp, 0); PusTmCreator::new(sph, tm_header, data, true) } fn ping_reply_with_data<'a, 'b>(data: &'b [u8], 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(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); PusTmCreator::new(sph, tm_header, data, true) } 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(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, timestamp); PusTmCreator::new(sph, tc_header, src_data, true) } @@ -1193,7 +1187,7 @@ mod tests { #[test] fn test_basic_simple_api() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = @@ -1310,7 +1304,7 @@ mod tests { #[test] fn test_serialization_no_source_data_alt_ctor() { let timestamp = dummy_timestamp(); - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let mut buf: [u8; 32] = [0; 32]; let mut pus_tm = @@ -1326,7 +1320,7 @@ mod tests { #[test] fn test_serialization_no_source_data_alt_ctor_no_crc() { let timestamp = dummy_timestamp(); - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tm_header = PusTmSecondaryHeader::new_simple(17, 2, timestamp); let mut buf: [u8; 32] = [0; 32]; let mut pus_tm = @@ -1384,7 +1378,7 @@ mod tests { fn test_serialization_with_source_data_alt_ctor() { let src_data = &[1, 2, 3]; let mut buf: [u8; 32] = [0; 32]; - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp()); let mut hk_reply_unwritten = PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3).unwrap(); @@ -1404,7 +1398,7 @@ mod tests { fn test_serialization_with_source_data_alt_ctor_no_table() { let src_data = &[1, 2, 3]; let mut buf: [u8; 32] = [0; 32]; - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(3, 5, dummy_timestamp()); let mut hk_reply_unwritten = PusTmCreatorWithReservedSourceData::new(&mut buf, sph, tc_header, 3).unwrap(); @@ -1429,8 +1423,8 @@ mod tests { pus_tm.set_msg_counter(Some(0x1f)); assert_eq!(pus_tm.dest_id(), Some(u16_dest_id)); assert_eq!(pus_tm.msg_counter(), Some(0x1f)); - assert!(pus_tm.set_apid(0x7ff)); - assert_eq!(pus_tm.apid(), 0x7ff); + pus_tm.set_apid(u11::new(0x7ff)); + assert_eq!(pus_tm.apid().value(), 0x7ff); } #[test] @@ -1609,7 +1603,7 @@ mod tests { #[test] fn test_manual_field_update() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, dummy_timestamp()); let mut tm = PusTmCreator::new_no_source_data(sph, tc_header, false); tm.calc_crc_on_serialization = false; @@ -1770,8 +1764,8 @@ mod tests { if has_user_data { assert!(!tm.user_data().is_empty()); } - assert_eq!(tm.apid(), 0x123); - assert_eq!(tm.seq_count(), 0x234); + assert_eq!(tm.apid().value(), 0x123); + assert_eq!(tm.seq_count().value(), 0x234); assert_eq!(PusPacket::pus_version(tm).unwrap(), PusVersion::PusA); assert_eq!( GenericPusTmSecondaryHeader::pus_version(tm), @@ -1813,8 +1807,6 @@ mod tests { .expect("Creating zero copy writer failed"); writer.set_seq_count(MAX_SEQ_COUNT); writer.set_apid(MAX_APID); - assert!(!writer.set_apid(MAX_APID + 1)); - assert!(!writer.set_apid(MAX_SEQ_COUNT + 1)); writer.finish(); // This performs all necessary checks, including the CRC check. let tm_read_back = @@ -1956,7 +1948,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serialization_creator_serde() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = @@ -1971,7 +1963,7 @@ mod tests { #[test] #[cfg(feature = "serde")] fn test_serialization_reader_serde() { - let sph = SpHeader::new_for_unseg_tm_checked(0x123, 0x234, 0).unwrap(); + let sph = SpHeader::new_for_unseg_tm(u11::new(0x123), u14::new(0x234), 0); let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = diff --git a/src/lib.rs b/src/lib.rs index 267a6d9..adb2af5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,9 @@ //! //! ```rust //! use spacepackets::SpHeader; -//! let sp_header = SpHeader::new_for_unseg_tc_checked(0x42, 12, 1).expect("error creating CCSDS TC header"); +//! use arbitrary_int::{u11, u14}; +//! +//! let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(12), 1); //! println!("{:?}", sp_header); //! let mut ccsds_buf: [u8; 32] = [0; 32]; //! sp_header.write_to_be_bytes(&mut ccsds_buf).expect("Writing CCSDS TC header failed"); @@ -61,6 +63,7 @@ extern crate alloc; #[cfg(any(feature = "std", test))] extern crate std; +use arbitrary_int::{prelude::*, u11, u14}; use core::{fmt::Debug, hash::Hash}; use delegate::delegate; use zerocopy::{FromBytes, IntoBytes}; @@ -82,8 +85,20 @@ mod private { pub const CCSDS_HEADER_LEN: usize = core::mem::size_of::(); -pub const MAX_APID: u16 = 2u16.pow(11) - 1; -pub const MAX_SEQ_COUNT: u16 = 2u16.pow(14) - 1; +pub const MAX_APID: u11 = u11::MAX; +pub const MAX_SEQ_COUNT: u14 = u14::MAX; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[error("apid is out of range, maximum value is {MAX_APID}")] +pub struct ApidOutOfRangeError(u16); + +#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[error("apid is out of range, maximum value is {MAX_SEQ_COUNT}")] +pub struct SequenceCountOutOfRangeError(u16); /// Generic error type when converting to and from raw byte slices. #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] @@ -96,6 +111,12 @@ pub enum ByteConversionError { /// The provider buffer is too small. Returns the passed slice length and expected minimum size #[error("source slice with size {found} too small, expected at least {expected} bytes")] FromSliceTooSmall { found: usize, expected: usize }, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ZeroCopyError { /// The [zerocopy] library failed to write to bytes #[error("zerocopy serialization error")] ZeroCopyToError, @@ -105,33 +126,25 @@ pub enum ByteConversionError { } /// CCSDS packet type enumeration. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u1, exhaustive = true)] +#[repr(u8)] pub enum PacketType { Tm = 0, Tc = 1, } -impl TryFrom for PacketType { - type Error = (); - - fn try_from(value: u8) -> Result { - match value { - x if x == PacketType::Tm as u8 => Ok(PacketType::Tm), - x if x == PacketType::Tc as u8 => Ok(PacketType::Tc), - _ => Err(()), - } - } -} - pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType { PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap() } -#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[derive(Debug, PartialEq, Eq, num_enum::TryFromPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[bitbybit::bitenum(u2, exhaustive = true)] +#[repr(u8)] pub enum SequenceFlags { ContinuationSegment = 0b00, FirstSegment = 0b01, @@ -139,22 +152,6 @@ pub enum SequenceFlags { Unsegmented = 0b11, } -impl TryFrom for SequenceFlags { - type Error = (); - - fn try_from(value: u8) -> Result { - match value { - x if x == SequenceFlags::ContinuationSegment as u8 => { - Ok(SequenceFlags::ContinuationSegment) - } - x if x == SequenceFlags::FirstSegment as u8 => Ok(SequenceFlags::FirstSegment), - x if x == SequenceFlags::LastSegment as u8 => Ok(SequenceFlags::LastSegment), - x if x == SequenceFlags::Unsegmented as u8 => Ok(SequenceFlags::Unsegmented), - _ => Err(()), - } - } -} - /// Abstraction for the CCSDS Packet ID, which forms the last thirteen bits /// of the first two bytes in the CCSDS primary header. #[derive(Debug, Eq, Copy, Clone)] @@ -163,7 +160,7 @@ impl TryFrom for SequenceFlags { pub struct PacketId { pub ptype: PacketType, pub sec_header_flag: bool, - apid: u16, + pub apid: u11, } impl PartialEq for PacketId { @@ -200,7 +197,7 @@ impl Default for PacketId { PacketId { ptype: PacketType::Tm, sec_header_flag: false, - apid: 0, + apid: u11::new(0), } } } @@ -209,34 +206,21 @@ impl PacketId { /// This constructor will panic if the passed APID exceeds [MAX_APID]. /// Use the checked constructor variants to avoid panics. #[inline] - pub const fn new_for_tc(sec_header: bool, apid: u16) -> Self { + pub const fn new_for_tc(sec_header: bool, apid: u11) -> Self { Self::new(PacketType::Tc, sec_header, apid) } /// This constructor will panic if the passed APID exceeds [MAX_APID]. /// Use the checked constructor variants to avoid panics. #[inline] - pub const fn new_for_tm(sec_header: bool, apid: u16) -> Self { + pub const fn new_for_tm(sec_header: bool, apid: u11) -> Self { Self::new(PacketType::Tm, sec_header, apid) } - #[inline] - pub fn new_for_tc_checked(sec_header: bool, apid: u16) -> Option { - Self::new_checked(PacketType::Tc, sec_header, apid) - } - - #[inline] - pub fn new_for_tm_checked(sec_header: bool, apid: u16) -> Option { - Self::new_checked(PacketType::Tm, sec_header, apid) - } - /// This constructor will panic if the passed APID exceeds [MAX_APID]. /// Use the checked variants to avoid panics. #[inline] - pub const fn new(ptype: PacketType, sec_header: bool, apid: u16) -> Self { - if apid > MAX_APID { - panic!("APID too large"); - } + pub const fn new(ptype: PacketType, sec_header: bool, apid: u11) -> Self { PacketId { ptype, sec_header_flag: sec_header, @@ -244,34 +228,22 @@ impl PacketId { } } - #[inline] - pub fn new_checked(ptype: PacketType, sec_header_flag: bool, apid: u16) -> Option { - if apid > MAX_APID { - return None; - } - Some(PacketId::new(ptype, sec_header_flag, apid)) - } - /// Set a new Application Process ID (APID). If the passed number is invalid, the APID will /// not be set and false will be returned. The maximum allowed value for the 11-bit field is /// 2047 #[inline] - pub fn set_apid(&mut self, apid: u16) -> bool { - if apid > MAX_APID { - return false; - } + pub fn set_apid(&mut self, apid: u11) { self.apid = apid; - true } #[inline] - pub fn apid(&self) -> u16 { + pub const fn apid(&self) -> u11 { self.apid } #[inline] - pub fn raw(&self) -> u16 { - ((self.ptype as u16) << 12) | ((self.sec_header_flag as u16) << 11) | self.apid + pub const fn raw(&self) -> u16 { + ((self.ptype as u16) << 12) | ((self.sec_header_flag as u16) << 11) | self.apid.value() } } @@ -280,7 +252,7 @@ impl From for PacketId { PacketId { ptype: PacketType::try_from(((raw_id >> 12) & 0b1) as u8).unwrap(), sec_header_flag: ((raw_id >> 11) & 0b1) != 0, - apid: raw_id & 0x7FF, + apid: u11::new(raw_id & 0x7FF), } } } @@ -290,61 +262,31 @@ impl From for PacketId { #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PacketSequenceCtrl { +pub struct PacketSequenceControl { pub seq_flags: SequenceFlags, - seq_count: u16, + pub seq_count: u14, } -impl PacketSequenceCtrl { - /// This constructor panics if the sequence count exceeds [MAX_SEQ_COUNT]. - /// Use [Self::new_checked] to avoid panics. +impl PacketSequenceControl { #[inline] - pub const fn new(seq_flags: SequenceFlags, seq_count: u16) -> PacketSequenceCtrl { - if seq_count > MAX_SEQ_COUNT { - panic!("Sequence count too large"); - } - PacketSequenceCtrl { + pub const fn new(seq_flags: SequenceFlags, seq_count: u14) -> PacketSequenceControl { + PacketSequenceControl { seq_flags, seq_count, } } - /// Returns [None] if the passed sequence count exceeds [MAX_SEQ_COUNT]. #[inline] - pub fn new_checked(seq_flags: SequenceFlags, seq_count: u16) -> Option { - if seq_count > MAX_SEQ_COUNT { - return None; - } - Some(PacketSequenceCtrl::new(seq_flags, seq_count)) - } - - #[inline] - 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. - #[inline] - pub fn set_seq_count(&mut self, ssc: u16) -> bool { - if ssc > MAX_SEQ_COUNT { - return false; - } - self.seq_count = ssc; - true - } - - #[inline] - pub fn seq_count(&self) -> u16 { - self.seq_count + pub const fn raw(&self) -> u16 { + ((self.seq_flags as u16) << 14) | self.seq_count.value() } } -impl From for PacketSequenceCtrl { +impl From for PacketSequenceControl { fn from(raw_id: u16) -> Self { - PacketSequenceCtrl { + PacketSequenceControl { seq_flags: SequenceFlags::try_from(((raw_id >> 14) & 0b11) as u8).unwrap(), - seq_count: raw_id & SSC_MASK, + seq_count: u14::new(raw_id & SSC_MASK), } } } @@ -369,9 +311,9 @@ const VERSION_MASK: u16 = 0xE000; /// 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 ccsds_version(&self) -> u3; fn packet_id(&self) -> PacketId; - fn psc(&self) -> PacketSequenceCtrl; + fn psc(&self) -> PacketSequenceControl; /// Retrieve data length field fn data_len(&self) -> u16; @@ -419,12 +361,12 @@ pub trait CcsdsPacket { /// Retrieve Application Process ID. #[inline] - fn apid(&self) -> u16 { + fn apid(&self) -> u11 { self.packet_id().apid } #[inline] - fn seq_count(&self) -> u16 { + fn seq_count(&self) -> u14 { self.psc().seq_count } @@ -439,9 +381,9 @@ pub trait CcsdsPacket { pub trait CcsdsPrimaryHeader { fn from_composite_fields( packet_id: PacketId, - psc: PacketSequenceCtrl, + psc: PacketSequenceControl, data_len: u16, - version: Option, + version: Option, ) -> Self; } @@ -459,9 +401,9 @@ pub trait CcsdsPrimaryHeader { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SpHeader { - pub version: u8, + pub version: u3, pub packet_id: PacketId, - pub psc: PacketSequenceCtrl, + pub psc: PacketSequenceControl, pub data_len: u16, } @@ -473,11 +415,11 @@ impl Default for SpHeader { #[inline] fn default() -> Self { SpHeader { - version: 0, + version: u3::new(0), packet_id: PacketId::default(), - psc: PacketSequenceCtrl { + psc: PacketSequenceControl { seq_flags: SequenceFlags::Unsegmented, - seq_count: 0, + seq_count: u14::new(0), }, data_len: 0, } @@ -486,9 +428,9 @@ impl Default for SpHeader { impl SpHeader { #[inline] - pub const fn new(packet_id: PacketId, psc: PacketSequenceCtrl, data_len: u16) -> Self { + pub const fn new(packet_id: PacketId, psc: PacketSequenceControl, data_len: u16) -> Self { Self { - version: 0, + version: u3::new(0), packet_id, psc, data_len, @@ -500,32 +442,18 @@ impl SpHeader { /// /// This constructor will panic if the APID exceeds [MAX_APID]. #[inline] - pub const fn new_from_apid(apid: u16) -> Self { + pub const fn new_from_apid(apid: u11) -> Self { SpHeader { - version: 0, + version: u3::new(0b000), packet_id: PacketId::new(PacketType::Tm, false, apid), - psc: PacketSequenceCtrl { + psc: PacketSequenceControl { seq_flags: SequenceFlags::Unsegmented, - seq_count: 0, + seq_count: u14::new(0), }, data_len: 0, } } - /// Checked variant of [Self::new_from_apid]. - #[inline] - pub fn new_from_apid_checked(apid: u16) -> Option { - Some(SpHeader { - version: 0, - packet_id: PacketId::new_checked(PacketType::Tm, false, apid)?, - psc: PacketSequenceCtrl { - seq_flags: SequenceFlags::Unsegmented, - seq_count: 0, - }, - data_len: 0, - }) - } - /// This constructor panics if the passed APID exceeds [MAX_APID] or the passed packet sequence /// count exceeds [MAX_SEQ_COUNT]. /// @@ -534,77 +462,25 @@ impl SpHeader { pub const fn new_from_fields( ptype: PacketType, sec_header: bool, - apid: u16, + apid: u11, seq_flags: SequenceFlags, - seq_count: u16, + seq_count: u14, 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::new(seq_flags, seq_count), + psc: PacketSequenceControl::new(seq_flags, seq_count), packet_id: PacketId::new(ptype, sec_header, apid), data_len, - version: 0, + version: u3::new(0b000), } } - /// 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. - #[inline] - pub fn new_from_fields_checked( - 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; - } - Some(SpHeader::new_from_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. The secondary header flag field is set to false. - #[inline] - pub fn new_for_tm_checked( - apid: u16, - seq_flags: SequenceFlags, - seq_count: u16, - data_len: u16, - ) -> Option { - Self::new_from_fields_checked(PacketType::Tm, false, apid, seq_flags, 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. - #[inline] - pub fn new_for_tc_checked( - apid: u16, - seq_flags: SequenceFlags, - seq_count: u16, - data_len: u16, - ) -> Option { - Self::new_from_fields_checked(PacketType::Tc, false, apid, seq_flags, seq_count, data_len) - } - /// This is an unchecked constructor which can panic on invalid input. #[inline] pub const fn new_for_tm( - apid: u16, + apid: u11, seq_flags: SequenceFlags, - seq_count: u16, + seq_count: u14, data_len: u16, ) -> Self { Self::new_from_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len) @@ -613,31 +489,19 @@ impl SpHeader { /// This is an unchecked constructor which can panic on invalid input. #[inline] pub const fn new_for_tc( - apid: u16, + apid: u11, seq_flags: SequenceFlags, - seq_count: u16, + seq_count: u14, data_len: u16, ) -> Self { Self::new_from_fields(PacketType::Tc, false, apid, seq_flags, seq_count, data_len) } - /// Variant of [SpHeader::new_for_tm_checked] which sets the sequence flag field to [SequenceFlags::Unsegmented] - #[inline] - pub fn new_for_unseg_tm_checked(apid: u16, seq_count: u16, data_len: u16) -> Option { - Self::new_for_tm_checked(apid, SequenceFlags::Unsegmented, seq_count, data_len) - } - - /// Variant of [SpHeader::new_for_tc_checked] which sets the sequence flag field to [SequenceFlags::Unsegmented] - #[inline] - pub fn new_for_unseg_tc_checked(apid: u16, seq_count: u16, data_len: u16) -> Option { - Self::new_for_tc_checked(apid, SequenceFlags::Unsegmented, seq_count, data_len) - } - /// Variant of [SpHeader::new_for_tc] which sets the sequence flag field to [SequenceFlags::Unsegmented]. /// /// This is an unchecked constructor which can panic on invalid input. #[inline] - pub const fn new_for_unseg_tc(apid: u16, seq_count: u16, data_len: u16) -> Self { + pub const fn new_for_unseg_tc(apid: u11, seq_count: u14, data_len: u16) -> Self { Self::new_for_tc(apid, SequenceFlags::Unsegmented, seq_count, data_len) } @@ -645,24 +509,20 @@ impl SpHeader { /// /// This is an unchecked constructor which can panic on invalid input. #[inline] - pub const fn new_for_unseg_tm(apid: u16, seq_count: u16, data_len: u16) -> Self { + pub const fn new_for_unseg_tm(apid: u11, seq_count: u14, data_len: u16) -> Self { Self::new_for_tm(apid, SequenceFlags::Unsegmented, seq_count, data_len) } delegate! { to self.packet_id { - /// Returns [false] and fails if the APID exceeds [MAX_APID] #[inline] - pub fn set_apid(&mut self, apid: u16) -> bool; + pub fn set_apid(&mut self, apid: u11); } } - delegate! { - to self.psc { - /// Returns [false] and fails if the sequence count exceeds [MAX_SEQ_COUNT] - #[inline] - pub fn set_seq_count(&mut self, seq_count: u16) -> bool; - } + #[inline] + pub fn set_seq_count(&mut self, seq_count: u14) { + self.psc.seq_count = seq_count; } #[inline] @@ -695,8 +555,8 @@ impl SpHeader { expected: CCSDS_HEADER_LEN, }); } - let zc_header = zc::SpHeader::read_from_bytes(&buf[0..CCSDS_HEADER_LEN]) - .map_err(|_| ByteConversionError::ZeroCopyFromError)?; + // Unwrap okay, this can not fail. + let zc_header = zc::SpHeader::read_from_bytes(&buf[0..CCSDS_HEADER_LEN]).unwrap(); Ok((Self::from(zc_header), &buf[CCSDS_HEADER_LEN..])) } @@ -713,9 +573,8 @@ impl SpHeader { }); } let zc_header: zc::SpHeader = zc::SpHeader::from(*self); - zc_header - .write_to(&mut buf[0..CCSDS_HEADER_LEN]) - .map_err(|_| ByteConversionError::ZeroCopyToError)?; + // Unwrap okay, this can not fail. + zc_header.write_to(&mut buf[0..CCSDS_HEADER_LEN]).unwrap(); Ok(&mut buf[CCSDS_HEADER_LEN..]) } @@ -731,7 +590,7 @@ impl SpHeader { impl CcsdsPacket for SpHeader { #[inline] - fn ccsds_version(&self) -> u8 { + fn ccsds_version(&self) -> u3 { self.version } @@ -741,7 +600,7 @@ impl CcsdsPacket for SpHeader { } #[inline] - fn psc(&self) -> PacketSequenceCtrl { + fn psc(&self) -> PacketSequenceControl { self.psc } @@ -755,11 +614,11 @@ impl CcsdsPrimaryHeader for SpHeader { #[inline] fn from_composite_fields( packet_id: PacketId, - psc: PacketSequenceCtrl, + psc: PacketSequenceControl, data_len: u16, - version: Option, + version: Option, ) -> Self { - let mut version_to_set = 0b000; + let mut version_to_set = u3::new(0b000); if let Some(version) = version { version_to_set = version; } @@ -775,7 +634,9 @@ impl CcsdsPrimaryHeader for SpHeader { sph_from_other!(SpHeader, crate::zc::SpHeader); pub mod zc { - use crate::{CcsdsPacket, CcsdsPrimaryHeader, PacketId, PacketSequenceCtrl, VERSION_MASK}; + use crate::{CcsdsPacket, CcsdsPrimaryHeader, PacketId, PacketSequenceControl, VERSION_MASK}; + use arbitrary_int::traits::Integer; + use arbitrary_int::u3; use zerocopy::byteorder::NetworkEndian; use zerocopy::{FromBytes, Immutable, IntoBytes, Unaligned, U16}; @@ -790,13 +651,13 @@ pub mod zc { impl SpHeader { pub fn new( packet_id: PacketId, - psc: PacketSequenceCtrl, + psc: PacketSequenceControl, data_len: u16, - version: Option, + version: Option, ) -> Self { let mut version_packet_id = packet_id.raw(); if let Some(version) = version { - version_packet_id = ((version as u16) << 13) | packet_id.raw() + version_packet_id = (version.as_u16() << 13) | packet_id.raw() } SpHeader { version_packet_id: U16::from(version_packet_id), @@ -808,8 +669,8 @@ pub mod zc { impl CcsdsPacket for SpHeader { #[inline] - fn ccsds_version(&self) -> u8 { - ((self.version_packet_id.get() >> 13) as u8) & 0b111 + fn ccsds_version(&self) -> u3 { + u3::new(((self.version_packet_id.get() >> 13) as u8) & 0b111) } #[inline] @@ -818,8 +679,8 @@ pub mod zc { } #[inline] - fn psc(&self) -> PacketSequenceCtrl { - PacketSequenceCtrl::from(self.psc_raw()) + fn psc(&self) -> PacketSequenceControl { + PacketSequenceControl::from(self.psc_raw()) } #[inline] @@ -841,9 +702,9 @@ pub mod zc { impl CcsdsPrimaryHeader for SpHeader { fn from_composite_fields( packet_id: PacketId, - psc: PacketSequenceCtrl, + psc: PacketSequenceControl, data_len: u16, - version: Option, + version: Option, ) -> Self { SpHeader::new(packet_id, psc, data_len, version) } @@ -861,13 +722,13 @@ pub(crate) mod tests { #[cfg(feature = "serde")] use crate::CcsdsPrimaryHeader; use crate::{ - packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceCtrl, PacketType, + packet_type_in_raw_packet_id, zc, CcsdsPacket, PacketId, PacketSequenceControl, PacketType, }; use crate::{SequenceFlags, SpHeader}; use alloc::vec; + use arbitrary_int::{prelude::*, u11, u14}; #[cfg(feature = "serde")] use core::fmt::Debug; - use num_traits::pow; #[cfg(feature = "serde")] use postcard::{from_bytes, to_allocvec}; #[cfg(feature = "serde")] @@ -875,12 +736,12 @@ pub(crate) mod tests { use zerocopy::FromBytes; const CONST_SP: SpHeader = SpHeader::new( - PacketId::new_for_tc(true, 0x36), - PacketSequenceCtrl::new(SequenceFlags::ContinuationSegment, 0x88), + PacketId::new_for_tc(true, u11::new(0x36)), + PacketSequenceControl::new(SequenceFlags::ContinuationSegment, u14::new(0x88)), 0x90, ); - const PACKET_ID_TM: PacketId = PacketId::new_for_tm(true, 0x22); + const PACKET_ID_TM: PacketId = PacketId::new_for_tm(true, u11::new(0x22)); #[cfg(feature = "serde")] pub(crate) fn generic_serde_test( @@ -894,10 +755,10 @@ pub(crate) mod tests { #[test] #[allow(clippy::assertions_on_constants)] fn verify_const_packet_id() { - assert_eq!(PACKET_ID_TM.apid(), 0x22); + assert_eq!(PACKET_ID_TM.apid().value(), 0x22); assert!(PACKET_ID_TM.sec_header_flag); assert_eq!(PACKET_ID_TM.ptype, PacketType::Tm); - let const_tc_id = PacketId::new_for_tc(true, 0x23); + let const_tc_id = PacketId::new_for_tc(true, u11::new(0x23)); assert_eq!(const_tc_id.ptype, PacketType::Tc); } @@ -905,39 +766,33 @@ pub(crate) mod tests { 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.apid.value(), 0x000); assert!(!id_default.sec_header_flag); } #[test] fn test_packet_id_ctors() { - let packet_id = PacketId::new_checked(PacketType::Tc, true, 0x1ff); - assert!(packet_id.is_some()); - let packet_id = packet_id.unwrap(); - assert_eq!(packet_id.apid(), 0x1ff); + let packet_id = PacketId::new(PacketType::Tc, true, u11::new(0x1ff)); + assert_eq!(packet_id.apid().value(), 0x1ff); assert_eq!(packet_id.ptype, PacketType::Tc); assert!(packet_id.sec_header_flag); - let packet_id_tc = PacketId::new_for_tc_checked(true, 0x1ff); - assert!(packet_id_tc.is_some()); - let packet_id_tc = packet_id_tc.unwrap(); + let packet_id_tc = PacketId::new_for_tc(true, u11::new(0x1ff)); assert_eq!(packet_id_tc, packet_id); - let packet_id_tm = PacketId::new_for_tm_checked(true, 0x2ff); - assert!(packet_id_tm.is_some()); - let packet_id_tm = packet_id_tm.unwrap(); + let packet_id_tm = PacketId::new_for_tm(true, u11::new(0x2ff)); assert!(packet_id_tm.sec_header_flag); assert_eq!(packet_id_tm.ptype, PacketType::Tm); - assert_eq!(packet_id_tm.apid, 0x2ff); + assert_eq!(packet_id_tm.apid, u11::new(0x2ff)); } #[test] fn verify_const_sp_header() { assert!(CONST_SP.sec_header_flag()); - assert_eq!(CONST_SP.apid(), 0x36); + assert_eq!(CONST_SP.apid().value(), 0x36); assert_eq!( CONST_SP.sequence_flags(), SequenceFlags::ContinuationSegment ); - assert_eq!(CONST_SP.seq_count(), 0x88); + assert_eq!(CONST_SP.seq_count().value(), 0x88); assert_eq!(CONST_SP.data_len, 0x90); } @@ -971,8 +826,7 @@ pub(crate) mod tests { #[test] fn test_packet_id() { - let packet_id = - PacketId::new_checked(PacketType::Tm, false, 0x42).expect("Packet ID creation failed"); + let packet_id = PacketId::new(PacketType::Tm, false, u11::new(0x42)); assert_eq!(packet_id.raw(), 0x0042); let packet_id_from_raw = PacketId::from(packet_id.raw()); assert_eq!( @@ -980,113 +834,79 @@ pub(crate) mod tests { PacketType::Tm ); assert_eq!(packet_id_from_raw, packet_id); - let packet_id_from_new = PacketId::new_checked(PacketType::Tm, false, 0x42).unwrap(); + let packet_id_from_new = PacketId::new(PacketType::Tm, false, u11::new(0x42)); assert_eq!(packet_id_from_new, packet_id); } - #[test] - fn test_invalid_packet_id() { - let packet_id_invalid = PacketId::new_checked(PacketType::Tc, true, 0xFFFF); - assert!(packet_id_invalid.is_none()); - } - - #[test] - fn test_invalid_apid_setter() { - let mut packet_id = - PacketId::new_checked(PacketType::Tm, false, 0x42).expect("Packet ID creation failed"); - assert!(!packet_id.set_apid(0xffff)); - } - - #[test] - fn test_invalid_seq_count() { - let mut psc = PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77) - .expect("PSC creation failed"); - assert_eq!(psc.seq_count(), 77); - assert!(!psc.set_seq_count(0xffff)); - } - #[test] fn test_packet_seq_ctrl() { - let mut psc = PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77) - .expect("PSC creation failed"); + let psc = PacketSequenceControl::new(SequenceFlags::ContinuationSegment, u14::new(77)); assert_eq!(psc.raw(), 77); - let psc_from_raw = PacketSequenceCtrl::from(psc.raw()); + let psc_from_raw = PacketSequenceControl::from(psc.raw()); assert_eq!(psc_from_raw, psc); - // Fails because SSC is limited to 14 bits - assert!(!psc.set_seq_count(2u16.pow(15))); - assert_eq!(psc.raw(), 77); - - let psc_invalid = PacketSequenceCtrl::new_checked(SequenceFlags::FirstSegment, 0xFFFF); - assert!(psc_invalid.is_none()); - let psc_from_new = - PacketSequenceCtrl::new_checked(SequenceFlags::ContinuationSegment, 77).unwrap(); - assert_eq!(psc_from_new, psc); } #[test] #[cfg(feature = "serde")] fn test_serde_sph() { - let sp_header = - SpHeader::new_for_unseg_tc_checked(0x42, 12, 0).expect("Error creating SP header"); - assert_eq!(sp_header.ccsds_version(), 0b000); + let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(12), 0); + assert_eq!(sp_header.ccsds_version().value(), 0b000); assert!(sp_header.is_tc()); assert!(!sp_header.sec_header_flag()); assert_eq!(sp_header.ptype(), PacketType::Tc); - assert_eq!(sp_header.seq_count(), 12); - assert_eq!(sp_header.apid(), 0x42); + assert_eq!(sp_header.seq_count().value(), 12); + assert_eq!(sp_header.apid().value(), 0x42); assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented); assert_eq!(sp_header.data_len(), 0); let output = to_allocvec(&sp_header).unwrap(); let sp_header: SpHeader = from_bytes(&output).unwrap(); - assert_eq!(sp_header.version, 0b000); + assert_eq!(sp_header.version.value(), 0b000); assert!(!sp_header.packet_id.sec_header_flag); assert_eq!(sp_header.ptype(), PacketType::Tc); - assert_eq!(sp_header.seq_count(), 12); - assert_eq!(sp_header.apid(), 0x42); + assert_eq!(sp_header.seq_count().value(), 12); + assert_eq!(sp_header.apid().value(), 0x42); assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented); assert_eq!(sp_header.packet_id_raw(), 0x1042); assert_eq!(sp_header.psc_raw(), 0xC00C); - assert_eq!(sp_header.ccsds_version(), 0b000); + assert_eq!(sp_header.ccsds_version().value(), 0b000); assert_eq!(sp_header.data_len, 0); - let sp_header = - SpHeader::new_for_unseg_tm_checked(0x7, 22, 36).expect("Error creating SP header"); - assert_eq!(sp_header.ccsds_version(), 0b000); + let sp_header = SpHeader::new_for_unseg_tm(u11::new(0x7), u14::new(22), 36); + assert_eq!(sp_header.ccsds_version().value(), 0b000); assert!(sp_header.is_tm()); assert!(!sp_header.sec_header_flag()); assert_eq!(sp_header.ptype(), PacketType::Tm); - assert_eq!(sp_header.seq_count(), 22); - assert_eq!(sp_header.apid(), 0x07); + assert_eq!(sp_header.seq_count().value(), 22); + assert_eq!(sp_header.apid().value(), 0x07); assert_eq!(sp_header.sequence_flags(), SequenceFlags::Unsegmented); assert_eq!(sp_header.packet_id_raw(), 0x0007); assert_eq!(sp_header.psc_raw(), 0xC016); assert_eq!(sp_header.data_len(), 36); - assert_eq!(sp_header.ccsds_version(), 0b000); + assert_eq!(sp_header.ccsds_version().value(), 0b000); let from_comp_fields = SpHeader::from_composite_fields( - PacketId::new(PacketType::Tc, true, 0x42), - PacketSequenceCtrl::new(SequenceFlags::Unsegmented, 0x7), + PacketId::new(PacketType::Tc, true, u11::new(0x42)), + PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0x7)), 0, None, ); assert_eq!(from_comp_fields.ptype(), PacketType::Tc); - assert_eq!(from_comp_fields.apid(), 0x42); + assert_eq!(from_comp_fields.apid().value(), 0x42); assert!(from_comp_fields.sec_header_flag()); assert_eq!( from_comp_fields.sequence_flags(), SequenceFlags::Unsegmented ); - assert_eq!(from_comp_fields.seq_count(), 0x7); + assert_eq!(from_comp_fields.seq_count().value(), 0x7); assert_eq!(from_comp_fields.data_len(), 0); } #[test] fn test_setters() { - let sp_header = SpHeader::new_for_tc_checked(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); + let mut sp_header = + SpHeader::new_for_tc(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0); + sp_header.set_apid(u11::new(0x12)); + assert_eq!(sp_header.apid().as_u16(), 0x12); sp_header.set_sec_header_flag(); assert!(sp_header.sec_header_flag()); sp_header.clear_sec_header_flag(); @@ -1094,59 +914,54 @@ pub(crate) mod tests { 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); + sp_header.set_seq_count(u14::new(0x45)); + assert_eq!(sp_header.seq_count().as_u16(), 0x45); } #[test] fn test_tc_ctor() { - let sp_header = SpHeader::new_for_tc_checked(0x42, SequenceFlags::Unsegmented, 25, 0); - assert!(sp_header.is_some()); - let sp_header = sp_header.unwrap(); + let sp_header = + SpHeader::new_for_tc(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0); verify_sp_fields(PacketType::Tc, &sp_header); } #[test] fn test_tc_ctor_unseg() { - let sp_header = SpHeader::new_for_unseg_tc_checked(0x42, 25, 0); - assert!(sp_header.is_some()); - let sp_header = sp_header.unwrap(); + let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(25), 0); verify_sp_fields(PacketType::Tc, &sp_header); } #[test] fn test_tc_ctor_unseg_const() { - let sp_header = SpHeader::new_for_unseg_tc(0x42, 25, 0); + let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(25), 0); verify_sp_fields(PacketType::Tc, &sp_header); } #[test] fn test_tm_ctor() { - let sp_header = SpHeader::new_for_tm_checked(0x42, SequenceFlags::Unsegmented, 25, 0); - assert!(sp_header.is_some()); - let sp_header = sp_header.unwrap(); + let sp_header = + SpHeader::new_for_tm(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0); verify_sp_fields(PacketType::Tm, &sp_header); } #[test] fn test_tm_ctor_const() { - let sp_header = SpHeader::new_for_tm(0x42, SequenceFlags::Unsegmented, 25, 0); + let sp_header = + SpHeader::new_for_tm(u11::new(0x42), SequenceFlags::Unsegmented, u14::new(25), 0); verify_sp_fields(PacketType::Tm, &sp_header); } #[test] fn test_tm_ctor_unseg() { - let sp_header = SpHeader::new_for_unseg_tm_checked(0x42, 25, 0); - assert!(sp_header.is_some()); - let sp_header = sp_header.unwrap(); + let sp_header = SpHeader::new_for_unseg_tm(u11::new(0x42), u14::new(25), 0); 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.apid().value(), 0x42); + assert_eq!(sp_header.seq_count(), u14::new(25)); assert_eq!(sp_header.data_len(), 0); } @@ -1154,12 +969,11 @@ pub(crate) mod tests { fn test_zc_sph() { use zerocopy::IntoBytes; - let sp_header = SpHeader::new_for_unseg_tc_checked(0x7FF, pow(2, 14) - 1, 0) - .expect("Error creating SP header"); + let sp_header = SpHeader::new_for_unseg_tc(u11::MAX, u14::MAX, 0); assert_eq!(sp_header.ptype(), PacketType::Tc); - assert_eq!(sp_header.apid(), 0x7FF); + assert_eq!(sp_header.apid().value(), 0x7FF); assert_eq!(sp_header.data_len(), 0); - assert_eq!(sp_header.ccsds_version(), 0b000); + assert_eq!(sp_header.ccsds_version().value(), 0b000); assert!(sp_header.is_tc()); let sp_header_zc = zc::SpHeader::from(sp_header); let slice = sp_header_zc.as_bytes(); @@ -1196,9 +1010,9 @@ pub(crate) mod tests { let sp_header = zc::SpHeader::read_from_bytes(slice); assert!(sp_header.is_ok()); let sp_header = sp_header.unwrap(); - assert_eq!(sp_header.ccsds_version(), 0b000); + assert_eq!(sp_header.ccsds_version().value(), 0b000); assert_eq!(sp_header.packet_id_raw(), 0x17FF); - assert_eq!(sp_header.apid(), 0x7FF); + assert_eq!(sp_header.apid().value(), 0x7FF); assert_eq!(sp_header.ptype(), PacketType::Tc); assert_eq!(sp_header.data_len(), 0); } @@ -1223,15 +1037,8 @@ pub(crate) mod tests { #[test] fn sp_header_from_apid() { - let sp_header = SpHeader::new_from_apid(0x03); - assert_eq!(sp_header.apid(), 0x03); - assert_eq!(sp_header.data_len(), 0); - } - - #[test] - fn sp_header_from_apid_checked() { - let sp_header = SpHeader::new_from_apid_checked(0x03).unwrap(); - assert_eq!(sp_header.apid(), 0x03); + let sp_header = SpHeader::new_from_apid(u11::new(0x03)); + assert_eq!(sp_header.apid().value(), 0x03); assert_eq!(sp_header.data_len(), 0); } @@ -1249,7 +1056,7 @@ pub(crate) mod tests { #[test] fn test_sp_header_as_vec() { - let sp_header = SpHeader::new_for_unseg_tc(0x42, 25, 1); + let sp_header = SpHeader::new_for_unseg_tc(u11::new(0x42), u14::new(25), 1); let sp_header_as_vec = sp_header.to_vec(); let sp_header_read_back = SpHeader::from_be_bytes(&sp_header_as_vec) .expect("Error reading back SP header") diff --git a/src/seq_count.rs b/src/seq_count.rs index ad14395..4c2aa82 100644 --- a/src/seq_count.rs +++ b/src/seq_count.rs @@ -1,4 +1,5 @@ use crate::MAX_SEQ_COUNT; +use arbitrary_int::traits::Integer; use core::cell::Cell; use paste::paste; @@ -101,7 +102,7 @@ pub struct SequenceCounterCcsdsSimple { impl Default for SequenceCounterCcsdsSimple { fn default() -> Self { Self { - provider: SequenceCounterSimple::new_custom_max_val_u16(MAX_SEQ_COUNT), + provider: SequenceCounterSimple::new_custom_max_val_u16(MAX_SEQ_COUNT.as_u16()), } } } @@ -341,7 +342,7 @@ mod tests { #[test] fn test_ccsds_counter_overflow() { let ccsds_counter = SequenceCounterCcsdsSimple::default(); - for _ in 0..MAX_SEQ_COUNT + 1 { + for _ in 0..MAX_SEQ_COUNT.value() + 1 { ccsds_counter.increment(); } assert_eq!(ccsds_counter.get(), 0); diff --git a/src/time/cds.rs b/src/time/cds.rs index b67f7cc..81f10ab 100644 --- a/src/time/cds.rs +++ b/src/time/cds.rs @@ -82,6 +82,7 @@ pub enum LengthOfDaySegment { #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SubmillisPrecision { Absent = 0b00, Microseconds = 0b01,