diff --git a/CHANGELOG.md b/CHANGELOG.md index d4581aa..0d67710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - `CdsCommon` renamed to `CdsBase` - Simplified CDS short timestamp, contains one less field which reduced serialization length. +- Renamed `UnsignedEnum::value` to `UnsignedEnum::value_raw`, `value` is reserved for the `const` + value getter. +- Renamed `CcsdsPrimaryHeader::from_composite_fields` to + `CcsdsPrimaryHeader::new_from_composite_fields` ## Added diff --git a/src/cfdp/lv.rs b/src/cfdp/lv.rs index b3bb74a..6c7040c 100644 --- a/src/cfdp/lv.rs +++ b/src/cfdp/lv.rs @@ -8,6 +8,7 @@ use std::string::String; use super::TlvLvDataTooLargeError; +/// Minmum length of a CFDP length-value structure in bytes. pub const MIN_LV_LEN: usize = 1; /// Generic CFDP length-value (LV) abstraction as specified in CFDP 5.1.8. @@ -63,8 +64,10 @@ pub(crate) fn generic_len_check_deserialization( } impl<'data> Lv<'data> { + /// Minimum length of a LV structure in bytes. pub const MIN_LEN: usize = MIN_LV_LEN; + /// Generic constructor. #[inline] pub fn new(data: &[u8]) -> Result, TlvLvDataTooLargeError> { if data.len() > u8::MAX as usize { @@ -118,6 +121,7 @@ impl<'data> Lv<'data> { self.data.len() == 0 } + /// Raw value part of the LV. #[inline] pub fn value(&self) -> &[u8] { self.data diff --git a/src/cfdp/mod.rs b/src/cfdp/mod.rs index 5b1a720..23ad656 100644 --- a/src/cfdp/mod.rs +++ b/src/cfdp/mod.rs @@ -13,43 +13,55 @@ 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; +/// PDU type. #[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 { + /// File directive PDU. FileDirective = 0, + /// File data PDU. FileData = 1, } +/// PDU direction. #[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 { + /// Going towards the file receiver. TowardsReceiver = 0, + /// Going towards the file sender. TowardsSender = 1, } +/// PDU transmission mode. #[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 (class 1) transfer. Acknowledged = 0, + /// Unacknowledged (class 2) transfer. Unacknowledged = 1, } +/// CRC flag. #[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 { + /// No CRC for the packet. NoCrc = 0, + /// Packet has CRC. WithCrc = 1, } @@ -78,7 +90,9 @@ impl From for bool { #[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum SegmentMetadataFlag { + /// Segment metadata not present. NotPresent = 0, + /// Segment metadata present. Present = 1, } @@ -89,22 +103,30 @@ pub enum SegmentMetadataFlag { #[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum SegmentationControl { + /// No record boundary preservation. NoRecordBoundaryPreservation = 0, + /// With record boundary preservation. WithRecordBoundaryPreservation = 1, } +/// Fault handler codes according to the CFDP standard. #[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 { + /// Notice of cancellation fault handler code. NoticeOfCancellation = 0b0001, + /// Notice of suspension fault handler code. NoticeOfSuspension = 0b0010, + /// Ignore error fault handler code. IgnoreError = 0b0011, + /// Abandon transaction fault handler code. AbandonTransaction = 0b0100, } +/// CFDP condition codes. #[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -113,15 +135,25 @@ pub enum FaultHandlerCode { pub enum ConditionCode { /// This is not an error condition for which a faulty handler override can be specified NoError = 0b0000, + /// Positive acknowledgement limit reached. PositiveAckLimitReached = 0b0001, + /// Keep-alive limit reached. KeepAliveLimitReached = 0b0010, + /// Invalid transmission mode. InvalidTransmissionMode = 0b0011, + /// Filestore rejection. FilestoreRejection = 0b0100, + /// File checksum error. FileChecksumFailure = 0b0101, + /// File size error. FileSizeError = 0b0110, + /// NAK limit reached. NakLimitReached = 0b0111, + /// Inactivity detected. InactivityDetected = 0b1000, + /// Check limit reached. CheckLimitReached = 0b1010, + /// Unsupported checksum type. UnsupportedChecksumType = 0b1011, /// Not an actual fault condition for which fault handler overrides can be specified SuspendRequestReceived = 0b1110, @@ -129,6 +161,7 @@ pub enum ConditionCode { CancelRequestReceived = 0b1111, } +/// Large file flag. #[derive(Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -151,6 +184,7 @@ pub enum TransactionStatus { /// Transaction is not currently active and the CFDP implementation does not retain a /// transaction history. Undefined = 0b00, + /// Transaction is currently active. Active = 0b01, /// Transaction was active in the past and was terminated. Terminated = 0b10, @@ -168,10 +202,13 @@ pub enum TransactionStatus { pub enum ChecksumType { /// Modular legacy checksum Modular = 0, + /// CRC32 Proximity-1. Crc32Proximity1 = 1, + /// CRC32C. Crc32C = 2, - /// Polynomial: 0x4C11DB7. Preferred checksum for now. + /// CRC32. Polynomial: 0x4C11DB7. Preferred checksum for now. Crc32 = 3, + /// Null checksum (no checksum). NullChecksum = 15, } @@ -181,8 +218,10 @@ impl Default for ChecksumType { } } +/// Raw null checksum. pub const NULL_CHECKSUM_U32: [u8; 4] = [0; 4]; +/// TLV or LV data larger than allowed [u8::MAX]. #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -199,16 +238,21 @@ pub struct InvalidTlvTypeFieldError { expected: Option, } +/// Generic TLV/LV error. #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum TlvLvError { + /// Data too large error. #[error("{0}")] DataTooLarge(#[from] TlvLvDataTooLargeError), + /// Byte conversion error. #[error("byte conversion error: {0}")] ByteConversion(#[from] ByteConversionError), + /// Invalid TLV type field error. #[error("{0}")] InvalidTlvTypeField(#[from] InvalidTlvTypeFieldError), + /// Invalid value length. #[error("invalid value length {0}")] InvalidValueLength(usize), /// Only applies to filestore requests and responses. Second name was missing where one is diff --git a/src/cfdp/pdu/finished.rs b/src/cfdp/pdu/finished.rs index af82141..a860655 100644 --- a/src/cfdp/pdu/finished.rs +++ b/src/cfdp/pdu/finished.rs @@ -626,7 +626,7 @@ mod tests { assert_eq!(finished_pdu_vec.len(), 12); assert_eq!(finished_pdu_vec[9], TlvType::EntityId.into()); assert_eq!(finished_pdu_vec[10], 1); - assert_eq!(finished_pdu_vec[11], TEST_DEST_ID.value_typed()); + assert_eq!(finished_pdu_vec[11], TEST_DEST_ID.value()); assert_eq!( finished_pdu.fault_location().unwrap().entity_id(), &TEST_DEST_ID.into() diff --git a/src/cfdp/tlv/mod.rs b/src/cfdp/tlv/mod.rs index a580031..dce0a15 100644 --- a/src/cfdp/tlv/mod.rs +++ b/src/cfdp/tlv/mod.rs @@ -19,9 +19,11 @@ use super::{InvalidTlvTypeFieldError, TlvLvDataTooLargeError}; pub mod msg_to_user; +/// Minimum length of a type-length-value structure, including type and length fields. pub const MIN_TLV_LEN: usize = 2; pub trait GenericTlv { + /// TLV type field. fn tlv_type_field(&self) -> TlvTypeField; /// Checks whether the type field contains one of the standard types specified in the CFDP @@ -45,7 +47,9 @@ pub trait GenericTlv { } } +/// Readable TLV structure trait. pub trait ReadableTlv { + /// Value field of the TLV. fn value(&self) -> &[u8]; /// Checks whether the value field is empty. @@ -68,9 +72,15 @@ pub trait ReadableTlv { } } +/// Writable TLV structure trait. pub trait WritableTlv { + /// Write the TLV to bytes. fn write_to_bytes(&self, buf: &mut [u8]) -> Result; + + /// Length of the written TLV. fn len_written(&self) -> usize; + + /// Convenience method to write the TLV to an owned [alloc::vec::Vec]. #[cfg(feature = "alloc")] fn to_vec(&self) -> Vec { let mut buf = vec![0; self.len_written()]; @@ -79,16 +89,23 @@ pub trait WritableTlv { } } +/// TLV type. #[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum TlvType { + /// Filestore request. FilestoreRequest = 0x00, + /// Filestore response. FilestoreResponse = 0x01, + /// Message to user. MsgToUser = 0x02, + /// Fault handler. FaultHandler = 0x04, + /// Flow label. FlowLabel = 0x05, + /// Entity ID. EntityId = 0x06, } diff --git a/src/ecss/event.rs b/src/ecss/event.rs index 23c1cc6..f87deb7 100644 --- a/src/ecss/event.rs +++ b/src/ecss/event.rs @@ -7,13 +7,21 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[repr(u8)] pub enum Subservice { + /// Telemetry - Info report. TmInfoReport = 1, + /// Telemetry - Low severity report. TmLowSeverityReport = 2, + /// Telemetry - Medium severity report. TmMediumSeverityReport = 3, + /// Telemetry - High severity report. TmHighSeverityReport = 4, + /// Telecommand - Enable event generation. TcEnableEventGeneration = 5, + /// Telecommand - Disable event generation. TcDisableEventGeneration = 6, + /// Telecommand - Report disabled list. TcReportDisabledList = 7, + /// Telemetry - Disabled events report. TmDisabledEventsReport = 8, } diff --git a/src/ecss/hk.rs b/src/ecss/hk.rs index 7a788f3..ddc13d6 100644 --- a/src/ecss/hk.rs +++ b/src/ecss/hk.rs @@ -9,13 +9,21 @@ use serde::{Deserialize, Serialize}; #[repr(u8)] pub enum Subservice { // Regular HK + /// Telecommand - Create Housekeeping Report Structure. TcCreateHkReportStructure = 1, + /// Telecommand - Delete HK report structures. TcDeleteHkReportStructures = 3, + /// Telecommand - Enable HK generation. TcEnableHkGeneration = 5, + /// Telecommand - Disable HK generation. TcDisableHkGeneration = 6, + /// Telecommand - Report HK report structures. TcReportHkReportStructures = 9, + /// Telemetry - HK report. TmHkPacket = 25, + /// Telecommand - Generate one-shot report. TcGenerateOneShotHk = 27, + /// Telecommand - Modify collection interval. TcModifyHkCollectionInterval = 31, // Diagnostics HK diff --git a/src/ecss/mod.rs b/src/ecss/mod.rs index aec0433..95dd2c9 100644 --- a/src/ecss/mod.rs +++ b/src/ecss/mod.rs @@ -25,53 +25,55 @@ pub mod tm; pub mod tm_pus_a; pub mod verification; +/// Type alias for the CRC16 type. pub type CrcType = u16; +/// Standard PUS service IDs. #[derive(Debug, Copy, Clone, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] #[non_exhaustive] pub enum PusServiceId { - /// Service 1 + /// Service 1 Verification Verification = 1, - /// Service 2 + /// Service 2 Device Access DeviceAccess = 2, - /// Service 3 + /// Service 3 Housekeeping Housekeeping = 3, - /// Service 4 + /// Service 4 Parameter Statistics ParameterStatistics = 4, - /// Service 5 + /// Service 5 Event Event = 5, - /// Service 6 + /// Service 6 Memory Management MemoryManagement = 6, - /// Service 8 + /// Service 8 Action Action = 8, - /// Service 9 + /// Service 9 Time Management TimeManagement = 9, - /// Service 11 + /// Service 11 Scheduling Scheduling = 11, - /// Service 12 + /// Service 12 On-Board Monitoring OnBoardMonitoring = 12, - /// Service 13 + /// Service 13 Large Packet Transfer LargePacketTransfer = 13, - /// Service 14 + /// Service 14 Real-Time Forwarding Control RealTimeForwardingControl = 14, - /// Service 15 + /// Service 15 Storage And Retrival StorageAndRetrival = 15, - /// Service 17 + /// Service 17 Test Test = 17, - /// Service 18 + /// Service 18 Operations And Procedures OpsAndProcedures = 18, - /// Service 19 + /// Service 19 Event Action EventAction = 19, - /// Service 20 + /// Service 20 Parameter Parameter = 20, - /// Service 21 + /// Service 21 Request Sequencing RequestSequencing = 21, - /// Service 22 + /// Service 22 Position Based Scheduling PositionBasedScheduling = 22, - /// Service 23 + /// Service 23 File Management FileManagement = 23, } @@ -83,8 +85,11 @@ pub enum PusServiceId { #[repr(u8)] #[non_exhaustive] pub enum PusVersion { + /// ESA PUS EsaPus = 0, + /// PUS A PusA = 1, + /// PUS C PusC = 2, } @@ -107,20 +112,33 @@ impl TryFrom for PusVersion { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum PacketTypeCodes { + /// Boolean. Boolean = 1, + /// Enumerated. Enumerated = 2, + /// Unsigned Integer. UnsignedInt = 3, + /// Signed Integer. SignedInt = 4, + /// Real (floating point). Real = 5, + /// Bit string. BitString = 6, + /// Octet (byte) string. OctetString = 7, + /// Character string. CharString = 8, + /// Absolute time. AbsoluteTime = 9, + /// Relative time. RelativeTime = 10, + /// Deduced. Deduced = 11, + /// Packet. Packet = 12, } +/// Type alias for the ECSS Packet Type Codes (PTC)s. pub type Ptc = PacketTypeCodes; /// ECSS Packet Field Codes (PFC)s for the unsigned [Ptc]. @@ -129,15 +147,25 @@ pub type Ptc = PacketTypeCodes; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[repr(u8)] pub enum PfcUnsigned { + /// 1 byte. OneByte = 4, + /// 12 bits. TwelveBits = 8, + /// 2 bytes. TwoBytes = 12, + /// 3 bytes. ThreeBytes = 13, + /// 4 bytes. FourBytes = 14, + /// 6 bytes. SixBytes = 15, + /// 8 bytes. EightBytes = 16, + /// 1 bit. OneBit = 17, + /// 2 bits. TwoBits = 18, + /// 3 bits. ThreeBits = 19, } @@ -157,12 +185,15 @@ pub enum PfcReal { DoubleMilStd = 4, } +/// Generic PUS error. #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum PusError { + /// PUS version is not supported. #[error("PUS version {0:?} not supported")] VersionNotSupported(u4), + /// Checksum failure. #[error("checksum verification for crc16 {0:#06x} failed")] ChecksumFailure(u16), /// CRC16 needs to be calculated first @@ -175,12 +206,21 @@ 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 { + /// PUS version. fn pus_version(&self) -> Result; + + /// Service ID. fn service(&self) -> u8; + + /// Subservice ID. fn subservice(&self) -> u8; + + /// User data field. fn user_data(&self) -> &[u8]; + /// CRC-16-CCITT checksum. fn checksum(&self) -> Option; + /// The presence of the CRC-16-CCITT checksum is optional. fn has_checksum(&self) -> bool { self.checksum().is_some() @@ -226,6 +266,7 @@ pub(crate) fn user_data_from_raw( } } +/// Verify the CRC16 of a raw packet and return a [PusError] on failure. pub fn verify_crc16_ccitt_false_from_raw_to_pus_error( raw_data: &[u8], crc16: u16, @@ -235,6 +276,8 @@ pub fn verify_crc16_ccitt_false_from_raw_to_pus_error( .ok_or(PusError::ChecksumFailure(crc16)) } +/// Verify the CRC16 of a raw packet using a table-less implementation and return a [PusError] on +/// failure. pub fn verify_crc16_ccitt_false_from_raw_to_pus_error_no_table( raw_data: &[u8], crc16: u16, @@ -267,10 +310,15 @@ pub fn verify_crc16_ccitt_false_from_raw_no_table(raw_data: &[u8]) -> bool { macro_rules! sp_header_impls { () => { delegate!(to self.sp_header { + /// Set the CCSDS APID. #[inline] pub fn set_apid(&mut self, apid: u11); + + /// Set the CCSDS sequence count. #[inline] pub fn set_seq_count(&mut self, seq_count: u14); + + /// Set the CCSDS sequence flags. #[inline] pub fn set_seq_flags(&mut self, seq_flag: SequenceFlags); }); @@ -289,27 +337,28 @@ pub trait EcssEnumeration: UnsignedEnum { fn pfc(&self) -> u8; } +/// Extension trait for [EcssEnumeration] which adds common trait bounds. pub trait EcssEnumerationExt: EcssEnumeration + Debug + Copy + Clone + PartialEq + Eq {} +/// ECSS enumerated type wrapper. #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct GenericEcssEnumWrapper> { - field: GenericUnsignedByteField, -} +pub struct GenericEcssEnumWrapper>(GenericUnsignedByteField); impl> GenericEcssEnumWrapper { + /// Returns [PacketTypeCodes::Enumerated]. pub const fn ptc() -> PacketTypeCodes { PacketTypeCodes::Enumerated } - pub const fn value_typed(&self) -> TYPE { - self.field.value_typed() + /// Value. + pub const fn value(&self) -> TYPE { + self.0.value() } - pub fn new(val: TYPE) -> Self { - Self { - field: GenericUnsignedByteField::new(val), - } + /// Generic constructor. + pub const fn new(val: TYPE) -> Self { + Self(GenericUnsignedByteField::new(val)) } } @@ -319,11 +368,11 @@ impl> UnsignedEnum for GenericEcssEnumWrapper } fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { - self.field.write_to_be_bytes(buf) + self.0.write_to_be_bytes(buf) } - fn value(&self) -> u64 { - self.field.value() + fn value_raw(&self) -> u64 { + self.0.value().into() } } @@ -347,11 +396,12 @@ impl> From for GenericEcssEnumWrapper { macro_rules! generic_ecss_enum_typedefs_and_from_impls { ($($ty:ty => $Enum:ident),*) => { $( + /// Type alias for ECSS enumeration wrapper around `$ty` pub type $Enum = GenericEcssEnumWrapper<$ty>; impl From<$Enum> for $ty { fn from(value: $Enum) -> Self { - value.value_typed() + value.value() } } )* @@ -412,6 +462,7 @@ pub trait WritablePusPacket { Ok(curr_idx) } + /// Converts the packet into an owned [alloc::vec::Vec]. #[cfg(feature = "alloc")] fn to_vec(&self) -> Result, PusError> { // This is the correct way to do this. See @@ -423,6 +474,7 @@ pub trait WritablePusPacket { } } +/// PUS packet creator configuration. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -465,7 +517,7 @@ mod tests { .expect("To byte conversion of u8 failed"); assert_eq!(buf[1], 1); assert_eq!(my_enum.value(), 1); - assert_eq!(my_enum.value_typed(), 1); + assert_eq!(my_enum.value(), 1); let enum_as_u8: u8 = my_enum.into(); assert_eq!(enum_as_u8, 1); let vec = my_enum.to_vec(); @@ -484,7 +536,7 @@ mod tests { assert_eq!(buf[1], 0x1f); assert_eq!(buf[2], 0x2f); assert_eq!(my_enum.value(), 0x1f2f); - assert_eq!(my_enum.value_typed(), 0x1f2f); + assert_eq!(my_enum.value(), 0x1f2f); let enum_as_raw: u16 = my_enum.into(); assert_eq!(enum_as_raw, 0x1f2f); let vec = my_enum.to_vec(); @@ -521,7 +573,7 @@ mod tests { assert_eq!(buf[3], 0x3f); assert_eq!(buf[4], 0x4f); assert_eq!(my_enum.value(), 0x1f2f3f4f); - assert_eq!(my_enum.value_typed(), 0x1f2f3f4f); + assert_eq!(my_enum.value(), 0x1f2f3f4f); let enum_as_raw: u32 = my_enum.into(); assert_eq!(enum_as_raw, 0x1f2f3f4f); let vec = my_enum.to_vec(); @@ -559,7 +611,7 @@ mod tests { assert_eq!(buf[6], 0x4f); assert_eq!(buf[7], 0x5f); assert_eq!(my_enum.value(), 0x1f2f3f4f5f); - assert_eq!(my_enum.value_typed(), 0x1f2f3f4f5f); + assert_eq!(my_enum.value(), 0x1f2f3f4f5f); let enum_as_raw: u64 = my_enum.into(); assert_eq!(enum_as_raw, 0x1f2f3f4f5f); assert_eq!(u64::from_be_bytes(buf), 0x1f2f3f4f5f); diff --git a/src/lib.rs b/src/lib.rs index 5cc6407..43f917f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,8 @@ //! ``` #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] +// TODO: Add docs everywhere. +//#![warn(missing_docs)] #[cfg(feature = "alloc")] extern crate alloc; #[cfg(any(feature = "std", test))] @@ -102,6 +104,7 @@ pub const MAX_SEQ_COUNT: u14 = u14::MAX; #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] pub enum ChecksumType { + /// Default CRC16-CCITT checksum. Crc16CcittFalse, } @@ -112,12 +115,23 @@ pub enum ChecksumType { pub enum ByteConversionError { /// The passed slice is too small. Returns the passed slice length and expected minimum size #[error("target slice with size {found} is too small, expected size of at least {expected}")] - ToSliceTooSmall { found: usize, expected: usize }, + ToSliceTooSmall { + /// Found slice size. + found: usize, + /// Expected slice size. + expected: usize, + }, /// 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 }, + FromSliceTooSmall { + /// Found slice size. + found: usize, + /// Expected slice size. + expected: usize, + }, } +/// [zerocopy] serialization and deserialization errors. #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -137,12 +151,15 @@ pub enum ZeroCopyError { #[error("invalid payload length: {0}")] pub struct InvalidPayloadLengthError(usize); +/// Errors during CCSDS packet creation. #[derive(thiserror::Error, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum CcsdsPacketCreationError { + /// Byte conversion error. #[error("byte conversion: {0}")] ByteConversion(#[from] ByteConversionError), + /// Invalid payload length which exceeded [u16::MAX]. #[error("invalid payload length: {0}")] InvalidPayloadLength(#[from] InvalidPayloadLengthError), } @@ -154,22 +171,30 @@ pub enum CcsdsPacketCreationError { #[bitbybit::bitenum(u1, exhaustive = true)] #[repr(u8)] pub enum PacketType { + /// Telemetry packet. Tm = 0, + /// Telecommand packet. Tc = 1, } +/// CCSDS packet sequence flags. #[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 { + /// Continuation segment of a segmented packet. ContinuationSegment = 0b00, + /// First segment of a sequence. FirstSegment = 0b01, + /// Last segment of a sequence. LastSegment = 0b10, + /// Unsegmented packet. Unsegmented = 0b11, } +/// Retrieve the [PacketType] from a raw packet ID. #[inline] pub fn packet_type_in_raw_packet_id(packet_id: u16) -> PacketType { PacketType::try_from((packet_id >> 12) as u8 & 0b1).unwrap() @@ -200,6 +225,9 @@ pub const fn ccsds_packet_len_for_user_data_len( Some(len) } +/// Calculate the full CCSDS packet length for a given user data length. +/// +/// Returns [None] if the packet length exceeds the maximum allowed size [u16::MAX]. #[inline] pub fn ccsds_packet_len_for_user_data_len_with_checksum(data_len: usize) -> Option { ccsds_packet_len_for_user_data_len(data_len, Some(ChecksumType::Crc16CcittFalse)) @@ -211,8 +239,11 @@ pub fn ccsds_packet_len_for_user_data_len_with_checksum(data_len: usize) -> Opti #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PacketId { + /// Packet type (telemetry or telecommand). pub packet_type: PacketType, + /// Secondary header flag. pub sec_header_flag: bool, + /// Application Process ID (APID). pub apid: u11, } @@ -256,16 +287,19 @@ impl Default for PacketId { } impl PacketId { + /// Generic constructor for telecommands. #[inline] pub const fn new_for_tc(sec_header: bool, apid: u11) -> Self { Self::new(PacketType::Tc, sec_header, apid) } + /// Generic constructor for telemetry. #[inline] pub const fn new_for_tm(sec_header: bool, apid: u11) -> Self { Self::new(PacketType::Tm, sec_header, apid) } + /// Generic constructor. #[inline] pub const fn new(packet_type: PacketType, sec_header_flag: bool, apid: u11) -> Self { PacketId { @@ -289,6 +323,7 @@ impl PacketId { self.apid } + /// Raw numeric value. #[inline] pub const fn raw(&self) -> u16 { ((self.packet_type as u16) << 12) @@ -307,6 +342,7 @@ impl From for PacketId { } } +/// Deprecated type alias. #[deprecated(since = "0.16.0", note = "use PacketSequenceControl instead")] pub type PacketSequenceCtrl = PacketSequenceControl; @@ -316,11 +352,14 @@ pub type PacketSequenceCtrl = PacketSequenceControl; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PacketSequenceControl { + /// CCSDS sequence flags. pub seq_flags: SequenceFlags, + /// CCSDS sequence count. pub seq_count: u14, } impl PacketSequenceControl { + /// Generic constructor. #[inline] pub const fn new(seq_flags: SequenceFlags, seq_count: u14) -> PacketSequenceControl { PacketSequenceControl { @@ -329,6 +368,7 @@ impl PacketSequenceControl { } } + /// Raw value. #[inline] pub const fn raw(&self) -> u16 { ((self.seq_flags as u16) << 14) | self.seq_count.value() @@ -348,7 +388,7 @@ macro_rules! sph_from_other { ($Self: path, $other: path) => { impl From<$other> for $Self { fn from(other: $other) -> Self { - Self::from_composite_fields( + Self::new_from_composite_fields( other.packet_id(), other.psc(), other.data_len(), @@ -364,19 +404,33 @@ 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 { + /// CCSDS version field. fn ccsds_version(&self) -> u3; + + /// CCSDS packet ID. + /// + /// First two bytes of the CCSDS primary header without the first three bits. fn packet_id(&self) -> PacketId; + + /// CCSDS packet sequence control. + /// + /// Third and fourth byte of the CCSDS primary header. fn psc(&self) -> PacketSequenceControl; - /// Retrieve data length field + /// Data length field. + /// + /// Please note that this is NOT the full packet length. + /// The full length can be calculated by adding the header length [CCSDS_HEADER_LEN] + 1 or + /// using [Self::packet_len]. fn data_len(&self) -> u16; - /// Retrieve the total packet size based on the data length field + /// Total packet size based on the data length field #[inline] fn packet_len(&self) -> usize { usize::from(self.data_len()) + CCSDS_HEADER_LEN + 1 } + /// Deprecated alias for [Self::packet_len]. #[deprecated(since = "0.16.0", note = "use packet_len instead")] #[inline] fn total_len(&self) -> usize { @@ -395,40 +449,45 @@ pub trait CcsdsPacket { self.psc().raw() } + /// CCSDS packet type. #[inline] fn packet_type(&self) -> PacketType { // This call should never fail because only 0 and 1 can be passed to the try_from call self.packet_id().packet_type } + /// Is this a telemetry packet? #[inline] fn is_tm(&self) -> bool { self.packet_type() == PacketType::Tm } + /// Is this a telecommand packet? #[inline] fn is_tc(&self) -> bool { self.packet_type() == PacketType::Tc } - /// Retrieve the secondary header flag. Returns true if a secondary header is present + /// CCSDS secondary header flag. Returns true if a secondary header is present /// and false if it is not. #[inline] fn sec_header_flag(&self) -> bool { self.packet_id().sec_header_flag } - /// Retrieve Application Process ID. + /// CCSDS Application Process ID (APID). #[inline] fn apid(&self) -> u11 { self.packet_id().apid } + /// CCSDS sequence count. #[inline] fn seq_count(&self) -> u14 { self.psc().seq_count } + /// CCSDS sequence flags. #[inline] fn sequence_flags(&self) -> SequenceFlags { // This call should never fail because the mask ensures that only valid values are passed @@ -437,8 +496,10 @@ pub trait CcsdsPacket { } } +/// Helper trait to generate the primary header from the composite fields. pub trait CcsdsPrimaryHeader { - fn from_composite_fields( + /// Constructor. + fn new_from_composite_fields( packet_id: PacketId, psc: PacketSequenceControl, data_len: u16, @@ -447,25 +508,23 @@ pub trait CcsdsPrimaryHeader { } /// Space Packet Primary Header according to CCSDS 133.0-B-2. -/// -/// # Arguments -/// -/// * `version` - CCSDS version field, occupies the first 3 bits of the raw header. Will generally -/// be set to 0b000 in all constructors provided by this crate. -/// * `packet_id` - Packet Identifier, which can also be used as a start marker. Occupies the last -/// 13 bits of the first two bytes of the raw header -/// * `psc` - Packet Sequence Control, occupies the third and fourth byte of the raw header -/// * `data_len` - Data length field occupies the fifth and the sixth byte of the raw header #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct SpacePacketHeader { + /// CCSDS version field, occupies the first 3 bits of the raw header. Will generally + /// be set to 0b000 in all constructors provided by this crate. pub version: u3, + /// CCSDS Packet Identifier, which can also be used as a start marker. Occupies the last + /// 13 bits of the first two bytes of the raw header pub packet_id: PacketId, + /// CCSDS Packet Sequence Control, occupies the third and fourth byte of the raw header pub psc: PacketSequenceControl, + /// Data length field occupies the fifth and the sixth byte of the raw header pub data_len: u16, } +/// Alias for [SpacePacketHeader]. pub type SpHeader = SpacePacketHeader; impl Default for SpacePacketHeader { @@ -486,8 +545,10 @@ impl Default for SpacePacketHeader { } impl SpacePacketHeader { + /// Length of the CCSDS primary header. pub const LENGTH: usize = CCSDS_HEADER_LEN; + /// Generic constructor. #[inline] pub const fn new(packet_id: PacketId, psc: PacketSequenceControl, data_len: u16) -> Self { Self { @@ -513,6 +574,7 @@ impl SpacePacketHeader { } } + /// Constructor from individual fields. #[inline] pub const fn new_from_fields( ptype: PacketType, @@ -530,6 +592,7 @@ impl SpacePacketHeader { } } + /// Constructor for telemetry packets. #[inline] pub const fn new_for_tm( apid: u11, @@ -540,6 +603,7 @@ impl SpacePacketHeader { Self::new_from_fields(PacketType::Tm, false, apid, seq_flags, seq_count, data_len) } + /// Constructor for telecommand packets. #[inline] pub const fn new_for_tc( apid: u11, @@ -564,6 +628,7 @@ impl SpacePacketHeader { delegate! { to self.packet_id { + /// Set the application process ID (APID). #[inline] pub fn set_apid(&mut self, apid: u11); } @@ -575,26 +640,31 @@ impl SpacePacketHeader { usize::from(self.data_len()) + Self::LENGTH + 1 } + /// Set the CCSDS sequence count. #[inline] pub fn set_seq_count(&mut self, seq_count: u14) { self.psc.seq_count = seq_count; } + /// Set the CCSDS sequence flags. #[inline] pub fn set_seq_flags(&mut self, seq_flags: SequenceFlags) { self.psc.seq_flags = seq_flags; } + /// Set the CCSDS secondary header flag. #[inline] pub fn set_sec_header_flag(&mut self) { self.packet_id.sec_header_flag = true; } + /// Clear the CCSDS secondary header flag. #[inline] pub fn clear_sec_header_flag(&mut self) { self.packet_id.sec_header_flag = false; } + /// Set the CCSDS packet type. #[inline] pub fn set_packet_type(&mut self, packet_type: PacketType) { self.packet_id.packet_type = packet_type; @@ -677,7 +747,7 @@ impl CcsdsPacket for SpacePacketHeader { impl CcsdsPrimaryHeader for SpacePacketHeader { #[inline] - fn from_composite_fields( + fn new_from_composite_fields( packet_id: PacketId, psc: PacketSequenceControl, data_len: u16, @@ -698,6 +768,7 @@ impl CcsdsPrimaryHeader for SpacePacketHeader { sph_from_other!(SpHeader, crate::zc::SpHeader); +/// [zerocopy] based CCSDS Space Packet Primary Header implementation. pub mod zc { use crate::{CcsdsPacket, CcsdsPrimaryHeader, PacketId, PacketSequenceControl, VERSION_MASK}; use arbitrary_int::traits::Integer; @@ -705,6 +776,7 @@ pub mod zc { use zerocopy::byteorder::NetworkEndian; use zerocopy::{FromBytes, Immutable, IntoBytes, Unaligned, U16}; + /// [zerocopy] space packet header. #[derive(FromBytes, IntoBytes, Immutable, Unaligned, Debug)] #[repr(C)] pub struct SpHeader { @@ -714,6 +786,7 @@ pub mod zc { } impl SpHeader { + /// Generic constructor. pub fn new( packet_id: PacketId, psc: PacketSequenceControl, @@ -769,7 +842,7 @@ pub mod zc { } impl CcsdsPrimaryHeader for SpHeader { - fn from_composite_fields( + fn new_from_composite_fields( packet_id: PacketId, psc: PacketSequenceControl, data_len: u16, @@ -799,8 +872,11 @@ pub struct CcsdsPacketCreatorWithReservedData<'buf> { } impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { + /// CCSDS header length. pub const HEADER_LEN: usize = CCSDS_HEADER_LEN; + /// Calculate the full CCSDS packet length for a given user data length and with a CRC16 + /// checksum. #[inline] pub fn packet_len_for_user_data_with_checksum(user_data_len: usize) -> Option { ccsds_packet_len_for_user_data_len(user_data_len, Some(ChecksumType::Crc16CcittFalse)) @@ -896,11 +972,13 @@ impl<'buf> CcsdsPacketCreatorWithReservedData<'buf> { } impl CcsdsPacketCreatorWithReservedData<'_> { + /// Raw full buffer this packet is constructed in. #[inline] pub fn raw_buffer(&self) -> &[u8] { self.buf } + /// Full packet length. #[inline] pub fn packet_len(&self) -> usize { ::packet_len(self) @@ -986,7 +1064,9 @@ impl CcsdsPacket for CcsdsPacketCreatorWithReservedData<'_> { #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CcsdsPacketId { + /// CCSDS Packet ID. pub packet_id: PacketId, + /// CCSDS Packet Sequence Control. pub psc: PacketSequenceControl, } @@ -998,6 +1078,7 @@ impl Hash for CcsdsPacketId { } impl CcsdsPacketId { + /// Generic constructor. #[inline] pub const fn new(packet_id: PacketId, psc: PacketSequenceControl) -> Self { Self { packet_id, psc } @@ -1012,6 +1093,7 @@ impl CcsdsPacketId { } } + /// Raw numeric value. #[inline] pub const fn raw(&self) -> u32 { ((self.packet_id.raw() as u32) << 16) | self.psc.raw() as u32 @@ -1133,6 +1215,7 @@ pub struct CcsdsPacketCreator<'app_data> { } impl<'app_data> CcsdsPacketCreator<'app_data> { + /// CCSDS header length. pub const HEADER_LEN: usize = CCSDS_HEADER_LEN; /// Helper function which can be used to determine the full packet length from the user @@ -1211,6 +1294,7 @@ impl CcsdsPacketCreator<'_> { .write_to_bytes(buf, self.len_written(), self.packet_data) } + /// CCSDS space packet header. #[inline] pub fn sp_header(&self) -> &SpHeader { &self.common.sp_header @@ -1256,7 +1340,9 @@ pub struct CcsdsPacketCreatorOwned { packet_data: alloc::vec::Vec, } +#[cfg(feature = "alloc")] impl CcsdsPacketCreatorOwned { + /// CCSDS header length. pub const HEADER_LEN: usize = CCSDS_HEADER_LEN; /// Helper function which can be used to determine the full packet length from the user @@ -1332,6 +1418,7 @@ impl CcsdsPacketCreatorOwned { .write_to_bytes(buf, self.len_written(), &self.packet_data) } + /// CCSDS space packet header. #[inline] pub fn sp_header(&self) -> &SpHeader { &self.common.sp_header @@ -1344,6 +1431,7 @@ impl CcsdsPacketCreatorOwned { } } +#[cfg(feature = "alloc")] impl CcsdsPacket for CcsdsPacketCreatorOwned { /// CCSDS version field. #[inline] @@ -1370,12 +1458,15 @@ impl CcsdsPacket for CcsdsPacketCreatorOwned { } } +/// CCSDS packet read error. #[derive(thiserror::Error, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum CcsdsPacketReadError { + /// Byte conversion error. #[error("byte conversion: {0}")] ByteConversion(#[from] ByteConversionError), + /// CRC error. #[error("CRC error")] CrcError, } @@ -1390,14 +1481,17 @@ pub struct CcsdsPacketReader<'buf> { } impl<'buf> CcsdsPacketReader<'buf> { + /// CCSDS header length. pub const HEADER_LEN: usize = CCSDS_HEADER_LEN; + /// Constructor which expects a CRC16 checksum. pub fn new_with_checksum( buf: &'buf [u8], ) -> Result, CcsdsPacketReadError> { Self::new(buf, Some(ChecksumType::Crc16CcittFalse)) } + /// Generic constructor. pub fn new( buf: &'buf [u8], checksum: Option, @@ -1672,7 +1766,7 @@ pub(crate) mod tests { assert_eq!(sp_header.data_len(), 36); assert_eq!(sp_header.ccsds_version().value(), 0b000); - let from_comp_fields = SpHeader::from_composite_fields( + let from_comp_fields = SpHeader::new_from_composite_fields( PacketId::new(PacketType::Tc, true, u11::new(0x42)), PacketSequenceControl::new(SequenceFlags::Unsegmented, u14::new(0x7)), 0, diff --git a/src/seq_count.rs b/src/seq_count.rs index 4d392cc..1640dca 100644 --- a/src/seq_count.rs +++ b/src/seq_count.rs @@ -14,28 +14,37 @@ use paste::paste; /// static structs when using the interior mutability pattern. This can be achieved by using /// [Cell], [core::cell::RefCell] or atomic types. pub trait SequenceCounter { + /// Raw type of the counter. type Raw: Into; + + /// Bit width of the counter. const MAX_BIT_WIDTH: usize; + /// Get the current sequence count value. fn get(&self) -> Self::Raw; + /// Increment the sequence count by one. fn increment(&self); + /// Increment the sequence count by one, mutable API. fn increment_mut(&mut self) { self.increment(); } + /// Get the current sequence count value and increment the counter by one. fn get_and_increment(&self) -> Self::Raw { let val = self.get(); self.increment(); val } + /// Get the current sequence count value and increment the counter by one, mutable API. fn get_and_increment_mut(&mut self) -> Self::Raw { self.get_and_increment() } } +/// Simple sequence counter which wraps at [T::MAX]. #[derive(Clone)] pub struct SequenceCounterSimple { seq_count: Cell, @@ -48,12 +57,15 @@ macro_rules! impl_for_primitives { $( paste! { impl SequenceCounterSimple<$ty> { + /// Constructor with a custom maximum value. pub fn [](max_val: $ty) -> Self { Self { seq_count: Cell::new(0), max_val, } } + + /// Generic constructor. pub fn []() -> Self { Self { seq_count: Cell::new(0), @@ -275,6 +287,7 @@ macro_rules! sync_clonable_seq_counter_impl { } impl [] { + /// Generic constructor. pub fn new(max_val: $ty) -> Self { Self { seq_count: core::sync::atomic::[]::new(0), diff --git a/src/time/ascii.rs b/src/time/ascii.rs index c672a61..2c28d9a 100644 --- a/src/time/ascii.rs +++ b/src/time/ascii.rs @@ -31,6 +31,7 @@ pub const FMT_STR_CODE_B_WITH_SIZE: (&str, usize) = ("%Y-%jT%T%.3f", 21); /// Three digits are used for the decimal fraction and a terminator is added at the end. pub const FMT_STR_CODE_B_TERMINATED_WITH_SIZE: (&str, usize) = ("%Y-%jT%T%.3fZ", 22); +/// Functions requiring both [chrono] and [alloc] support. #[cfg(all(feature = "alloc", feature = "chrono"))] pub mod alloc_mod_chrono { use super::*; diff --git a/src/time/cds.rs b/src/time/cds.rs index 049221d..09e246e 100644 --- a/src/time/cds.rs +++ b/src/time/cds.rs @@ -37,12 +37,15 @@ use super::{ /// Base value for the preamble field for a time field parser to determine the time field type. pub const P_FIELD_BASE: u8 = (CcsdsTimeCode::Cds as u8) << 4; +/// Minimum allowed length for a CDS timestamp. pub const MIN_CDS_FIELD_LEN: usize = 7; +/// Maximum allowed days value for 24 bit days field. pub const MAX_DAYS_24_BITS: u32 = 2_u32.pow(24) - 1; /// Generic trait implemented by token structs to specify the length of day field at type /// level. This trait is only meant to be implemented in this crate and therefore sealed. pub trait ProvidesDaysLength: Sealed + Clone { + /// Raw field type. type FieldType: Debug + Copy + Clone @@ -73,24 +76,33 @@ impl ProvidesDaysLength for DaysLen24Bits { type FieldType = u32; } +/// Length of day segment. #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum LengthOfDaySegment { + /// Shorter 16 bits length of days field. Short16Bits = 0, + /// Larger 24 bits length of days field. Long24Bits = 1, } +/// Sub-millisecond precision indicator. #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum SubmillisPrecision { + /// No sub-millisecond precision present. Absent = 0b00, + /// Microsecond precision present. Microseconds = 0b01, + /// Picoseconds precision present. Picoseconds = 0b10, + /// Reserved. Reserved = 0b11, } +/// CDS timestamp error. #[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -102,10 +114,12 @@ pub enum CdsError { /// field. This error will be returned if there is a missmatch. #[error("wrong constructor for length of day {0:?} detected in preamble")] InvalidCtorForDaysOfLenInPreamble(LengthOfDaySegment), + /// Date is before the CCSDS epoch (1958-01-01T00:00:00+00:00) #[error("date before CCSDS epoch: {0}")] DateBeforeCcsdsEpoch(#[from] DateBeforeCcsdsEpochError), } +/// Retrieve the [LengthOfDaySegment] from the p-field byte. pub fn length_of_day_segment_from_pfield(pfield: u8) -> LengthOfDaySegment { if (pfield >> 2) & 0b1 == 1 { return LengthOfDaySegment::Long24Bits; @@ -113,6 +127,7 @@ pub fn length_of_day_segment_from_pfield(pfield: u8) -> LengthOfDaySegment { LengthOfDaySegment::Short16Bits } +/// Retrieve the [SubmillisPrecision] from the p-field byte. #[inline] pub fn precision_from_pfield(pfield: u8) -> SubmillisPrecision { match pfield & 0b11 { @@ -180,19 +195,29 @@ pub struct CdsTime { /// /// Also exists to encapsulate properties used by private converters. pub trait CdsBase { + /// Sub-millisecond precision indicator. fn submillis_precision(&self) -> SubmillisPrecision; + + /// Sub-milliseconds. fn submillis(&self) -> u32; + + /// Milliseconds of day. fn ms_of_day(&self) -> u32; + + /// CCSDS days since the epoch as [u32]. fn ccsds_days_as_u32(&self) -> u32; } /// Generic properties for all CDS time providers. pub trait CdsTimestamp: CdsBase { + /// Length of day segment. fn len_of_day_seg(&self) -> LengthOfDaySegment; } +/// Generic implementation of [CcsdsTimeProvider] for CDS time providers. #[cfg(feature = "alloc")] pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimestamp + TimeWriter + Any {} + #[cfg(feature = "alloc")] impl DynCdsTimeProvider for CdsTime {} #[cfg(feature = "alloc")] @@ -294,11 +319,13 @@ impl CdsTime { true } + /// Clear the submillisecond field. pub fn clear_submillis(&mut self) { self.pfield &= !(0b11); self.submillis = 0; } + /// CCSDS days since the CCSDS epoch. pub fn ccsds_days(&self) -> ProvidesDaysLen::FieldType { self.ccsds_days } @@ -522,6 +549,7 @@ impl CdsTime { pfield } + /// Update the time from the current time. #[cfg(feature = "std")] pub fn update_from_now(&mut self) -> Result<(), StdTimestampError> { let conversion_from_now = self.generic_conversion_from_now()?; @@ -612,6 +640,7 @@ impl CdsTime { Self::now_generic_with_us_prec(LengthOfDaySegment::Long24Bits) } + /// Constructor from the CDS timestamp as a raw byte array. pub fn from_bytes_with_u24_days(buf: &[u8]) -> Result { let submillis_precision = Self::generic_raw_read_checks(buf, LengthOfDaySegment::Long24Bits)?; @@ -704,6 +733,7 @@ impl CdsTime { Self::from_now_generic_ps_prec(LengthOfDaySegment::Short16Bits) } + /// Write the CDS timestamp to a raw byte array. pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { self.length_check(buf, self.len_as_bytes())?; buf[0] = self.pfield; @@ -721,6 +751,7 @@ impl CdsTime { Ok(self.len_as_bytes()) } + /// Constructor from the CDS timestamp as a raw byte array. pub fn from_bytes_with_u16_days(buf: &[u8]) -> Result { let submillis_precision = Self::generic_raw_read_checks(buf, LengthOfDaySegment::Short16Bits)?; @@ -892,6 +923,7 @@ impl TimeWriter for CdsTime { } impl CdsTime { + /// Write the CDS timestamp to a raw byte array. pub fn write_to_bytes(&self, buf: &mut [u8]) -> Result { self.length_check(buf, self.len_as_bytes())?; buf[0] = self.pfield; diff --git a/src/time/cuc.rs b/src/time/cuc.rs index 503f2ef..876a360 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -32,6 +32,7 @@ pub const P_FIELD_BASE: u8 = (CcsdsTimeCode::CucCcsdsEpoch as u8) << 4; /// Maximum length if the preamble field is not extended. pub const MAX_CUC_LEN_SMALL_PREAMBLE: usize = 8; +/// Fractional resolution for the fractional part of the CUC time code. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -70,13 +71,14 @@ pub fn convert_fractional_part_to_ns(fractional_part: FractionalPart) -> u64 { 10_u64.pow(9) * fractional_part.counter as u64 / div as u64 } +/// Convert the fractional resolution to the divisor used to calculate the fractional part. #[inline(always)] pub const fn fractional_res_to_div(res: FractionalResolution) -> u32 { // We do not use the full possible range for a given resolution. This is because if we did // that, the largest value would be equal to the counter being incremented by one. Thus, the // smallest allowed fractions value is 0 while the largest allowed fractions value is the // closest fractions value to the next counter increment. - 2_u32.pow(8 * res as u32) - 1 + (1u32 << (8 * res as u32)) - 1 } /// Calculate the fractional part for a given resolution and subsecond nanoseconds. @@ -101,22 +103,34 @@ pub fn fractional_part_from_subsec_ns(res: FractionalResolution, ns: u64) -> Fra } } +/// CUC error. #[derive(Copy, Clone, PartialEq, Eq, Debug, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CucError { + /// Invalid CUC counter width. #[error("invalid cuc counter byte width {0}")] InvalidCounterWidth(u8), /// Invalid counter supplied. #[error("invalid cuc counter {counter} for width {width}")] - InvalidCounter { width: u8, counter: u64 }, + InvalidCounter { + /// Width. + width: u8, + /// Counter. + counter: u64, + }, + /// Invalid fractions. #[error("invalid cuc fractional part {value} for resolution {resolution:?}")] InvalidFractions { + /// Resolution. resolution: FractionalResolution, + /// Value. value: u64, }, + /// Error while correcting for leap seconds. #[error("error while correcting for leap seconds")] LeapSecondCorrectionError, + /// Data is before the CCSDS epoch. #[error("date before ccsds epoch: {0}")] DateBeforeCcsdsEpoch(#[from] DateBeforeCcsdsEpochError), } @@ -127,14 +141,20 @@ pub enum CucError { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct WidthCounterPair(pub u8, pub u32); +/// Fractional part of the CUC time code. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct FractionalPart { + /// Resolution. pub resolution: FractionalResolution, + /// Counter. pub counter: u32, } impl FractionalPart { + /// Generic constructor. + /// + /// This function will panic if the counter is smaller than the calculated divisor. #[inline] pub const fn new(resolution: FractionalResolution, counter: u32) -> Self { let div = fractional_res_to_div(resolution); @@ -157,6 +177,7 @@ impl FractionalPart { Self::new_with_seconds_resolution() } + /// Check constructor which verifies that the counter is larger than the divisor. #[inline] pub fn new_checked(resolution: FractionalResolution, counter: u32) -> Option { let div = fractional_res_to_div(resolution); @@ -169,16 +190,19 @@ impl FractionalPart { }) } + /// Fractional resolution. #[inline] pub fn resolution(&self) -> FractionalResolution { self.resolution } + /// Counter value. #[inline] pub fn counter(&self) -> u32 { self.counter } + /// Check whether the timestamp does not have a fractional part. #[inline] pub fn no_fractional_part(&self) -> bool { self.resolution == FractionalResolution::Seconds @@ -245,17 +269,21 @@ pub struct CucTime { #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct CucTimeWithLeapSecs { + /// CUC time. pub time: CucTime, + /// Leap seconds. pub leap_seconds: u32, } impl CucTimeWithLeapSecs { + /// Generic constructor. #[inline] pub fn new(time: CucTime, leap_seconds: u32) -> Self { Self { time, leap_seconds } } } +/// p-field length. #[inline] pub fn pfield_len(pfield: u8) -> usize { if ((pfield >> 7) & 0b1) == 1 { @@ -381,6 +409,7 @@ impl CucTime { Ok(()) } + /// Creates a CUC timestamp from a Chrono DateTime object. #[cfg(feature = "chrono")] pub fn from_chrono_date_time( dt: &chrono::DateTime, @@ -448,21 +477,25 @@ impl CucTime { }) } + /// CCSDS time code. #[inline] pub fn ccsds_time_code(&self) -> CcsdsTimeCode { CcsdsTimeCode::CucCcsdsEpoch } + /// Width and counter pair. #[inline] pub fn width_counter_pair(&self) -> WidthCounterPair { self.counter } + /// Counter width. #[inline] pub fn counter_width(&self) -> u8 { self.counter.0 } + /// Counter value. #[inline] pub fn counter(&self) -> u32 { self.counter.1 @@ -474,11 +507,13 @@ impl CucTime { self.fractions } + /// Convert to the leap seconds helper. #[inline] pub fn to_leap_sec_helper(&self, leap_seconds: u32) -> CucTimeWithLeapSecs { CucTimeWithLeapSecs::new(*self, leap_seconds) } + /// Set the fractional part. #[inline] pub fn set_fractions(&mut self, fractions: FractionalPart) -> Result<(), CucError> { Self::verify_fractions_value(fractions)?; @@ -525,16 +560,19 @@ impl CucTime { self.pfield |= self.fractions.resolution() as u8; } + /// Length of the counter from the p-field. #[inline] pub fn len_cntr_from_pfield(pfield: u8) -> u8 { ((pfield >> 2) & 0b11) + 1 } + /// Length of the fractional part from the p-field. #[inline] pub fn len_fractions_from_pfield(pfield: u8) -> u8 { pfield & 0b11 } + /// UNIX seconds. #[inline] pub fn unix_secs(&self, leap_seconds: u32) -> i64 { ccsds_epoch_to_unix_epoch(self.counter.1 as i64) @@ -542,6 +580,7 @@ impl CucTime { .unwrap() } + /// Subsecond milliseconds part of the CUC time. #[inline] pub fn subsec_millis(&self) -> u16 { (self.subsec_nanos() / 1_000_000) as u16 @@ -564,6 +603,7 @@ impl CucTime { ) } + /// Packed length from the raw p-field. #[inline] pub fn len_packed_from_pfield(pfield: u8) -> usize { let mut base_len: usize = 1; diff --git a/src/time/mod.rs b/src/time/mod.rs index 8ad6eca..fb3d373 100644 --- a/src/time/mod.rs +++ b/src/time/mod.rs @@ -22,19 +22,29 @@ pub mod ascii; pub mod cds; pub mod cuc; +/// Conversion constant for converting CCSDS days to UNIX days. pub const DAYS_CCSDS_TO_UNIX: i32 = -4383; +/// Seconds per day. pub const SECONDS_PER_DAY: u32 = 86400; +/// Milliseconds per day. pub const MS_PER_DAY: u32 = SECONDS_PER_DAY * 1000; +/// Nanoseconds per second. pub const NANOS_PER_SECOND: u32 = 1_000_000_000; +/// CCSDS time code identifiers. #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CcsdsTimeCode { + /// CUC with a CCSDS epoch (1958-01-01T00:00:00+00:00). CucCcsdsEpoch = 0b001, + /// CUC with a custom agency epoch. CucAgencyEpoch = 0b010, + /// CDS time code. Cds = 0b100, + /// CCS time code. Ccs = 0b101, + /// Agency defined time code. AgencyDefined = 0b110, } @@ -60,44 +70,61 @@ pub fn ccsds_time_code_from_p_field(pfield: u8) -> Result { CcsdsTimeCode::try_from(raw_bits).map_err(|_| raw_bits) } +/// Date is before the CCSDS epoch. #[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[error("date before ccsds epoch: {0:?}")] pub struct DateBeforeCcsdsEpochError(UnixTime); +/// Generic timestamp error. #[derive(Debug, PartialEq, Eq, Copy, Clone, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum TimestampError { + /// Invalid time code. #[error("invalid time code, expected {expected:?}, found {found}")] - InvalidTimeCode { expected: CcsdsTimeCode, found: u8 }, + InvalidTimeCode { + /// Expected time code. + expected: CcsdsTimeCode, + /// Found raw time code. + found: u8, + }, + /// Byte conversion error. #[error("time stamp: byte conversion error: {0}")] ByteConversion(#[from] ByteConversionError), + /// CDS timestamp error. #[error("CDS error: {0}")] Cds(#[from] cds::CdsError), + /// CUC timestamp error. #[error("CUC error: {0}")] Cuc(#[from] cuc::CucError), + /// Custom epoch is not supported. #[error("custom epoch not supported")] CustomEpochNotSupported, } +/// [std] module. #[cfg(feature = "std")] pub mod std_mod { use crate::time::TimestampError; use std::time::SystemTimeError; use thiserror::Error; + /// [std] timestamp error. #[derive(Debug, Clone, Error)] pub enum StdTimestampError { + /// System time error. #[error("system time error: {0:?}")] SystemTime(#[from] SystemTimeError), + /// Generic timestamp error. #[error("timestamp error: {0}")] Timestamp(#[from] TimestampError), } } +/// Seconds since epoch for the current system time. #[cfg(feature = "std")] pub fn seconds_since_epoch() -> f64 { SystemTime::now() @@ -131,16 +158,19 @@ pub const fn unix_epoch_to_ccsds_epoch(unix_epoch: i64) -> i64 { unix_epoch - (DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64) } +/// Convert CCSDS epoch to UNIX epoch. #[inline] pub const fn ccsds_epoch_to_unix_epoch(ccsds_epoch: i64) -> i64 { ccsds_epoch + (DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64) } +/// Milliseconds of day for the current system time. #[cfg(feature = "std")] pub fn ms_of_day_using_sysclock() -> u32 { ms_of_day(seconds_since_epoch()) } +/// Milliseconds for the given seconds since epoch. pub fn ms_of_day(seconds_since_epoch: f64) -> u32 { let fraction_ms = seconds_since_epoch - seconds_since_epoch.floor(); let ms_of_day: u32 = (((seconds_since_epoch.floor() as u32 % SECONDS_PER_DAY) * 1000) as f64 @@ -149,13 +179,16 @@ pub fn ms_of_day(seconds_since_epoch: f64) -> u32 { ms_of_day } +/// Generic writable timestamp trait. pub trait TimeWriter { + /// Written length. fn len_written(&self) -> usize; /// Generic function to convert write a timestamp into a raw buffer. /// Returns the number of written bytes on success. fn write_to_bytes(&self, bytes: &mut [u8]) -> Result; + /// Convert to a owned [alloc::vec::Vec]. #[cfg(feature = "alloc")] fn to_vec(&self) -> Result, TimestampError> { let mut vec = alloc::vec![0; self.len_written()]; @@ -164,7 +197,9 @@ pub trait TimeWriter { } } +/// Genmeric readable timestamp trait. pub trait TimeReader: Sized { + /// Create a timestamp from a raw byte buffer. fn from_bytes(buf: &[u8]) -> Result; } @@ -174,6 +209,7 @@ pub trait TimeReader: Sized { /// practical because they are a very common and simple exchange format for time information. /// Therefore, it was decided to keep them in this trait as well. pub trait CcsdsTimeProvider { + /// Length when written to bytes. fn len_as_bytes(&self) -> usize; /// Returns the pfield of the time provider. The pfield can have one or two bytes depending @@ -181,29 +217,37 @@ pub trait CcsdsTimeProvider { /// entry denotes the length of the pfield and the second entry is the value of the pfield /// in big endian format. fn p_field(&self) -> (usize, [u8; 2]); + + /// CCSDS time code field. fn ccdsd_time_code(&self) -> CcsdsTimeCode; + /// UNIX time as seconds. fn unix_secs(&self) -> i64 { self.unix_time().secs } + /// Subsecond nanoseconds. fn subsec_nanos(&self) -> u32 { self.unix_time().subsec_nanos } + /// Subsecond milliseconds. fn subsec_millis(&self) -> u16 { (self.subsec_nanos() / 1_000_000) as u16 } + /// UNIX time. fn unix_time(&self) -> UnixTime { UnixTime::new(self.unix_secs(), self.subsec_nanos()) } + /// [chrono] date time. #[cfg(feature = "chrono")] fn chrono_date_time(&self) -> chrono::LocalResult> { chrono::Utc.timestamp_opt(self.unix_secs(), self.subsec_nanos()) } + /// [time] library date] library date time. #[cfg(feature = "timelib")] fn timelib_date_time(&self) -> Result { Ok(time::OffsetDateTime::from_unix_timestamp(self.unix_secs())? @@ -285,6 +329,7 @@ impl UnixTime { } } + /// New UNIX time with only seconds, subseconds set to zero. pub fn new_only_secs(unix_seconds: i64) -> Self { Self { secs: unix_seconds, @@ -292,15 +337,18 @@ impl UnixTime { } } + /// Sub-second milliseconds. #[inline] pub fn subsec_millis(&self) -> u16 { (self.subsec_nanos / 1_000_000) as u16 } + /// Sub-second nanoseconds. pub fn subsec_nanos(&self) -> u32 { self.subsec_nanos } + /// Create a UNIX timestamp from the current system time. #[cfg(feature = "std")] pub fn now() -> Result { let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; @@ -308,27 +356,31 @@ impl UnixTime { Ok(Self::new(epoch as i64, now.subsec_nanos())) } + /// UNIX timestamp as a floating point number in seconds. #[inline] pub fn unix_secs_f64(&self) -> f64 { self.secs as f64 + (self.subsec_nanos as f64 / 1_000_000_000.0) } + /// UNIX timestamp as seconds, discards the sub-second part. pub fn as_secs(&self) -> i64 { self.secs } + /// UNIX timestamp as [chrono] date time. #[cfg(feature = "chrono")] pub fn chrono_date_time(&self) -> chrono::LocalResult> { Utc.timestamp_opt(self.secs, self.subsec_nanos) } + /// UNIX timestamp as [time] library date time. #[cfg(feature = "timelib")] pub fn timelib_date_time(&self) -> Result { Ok(time::OffsetDateTime::from_unix_timestamp(self.as_secs())? + time::Duration::nanoseconds(self.subsec_nanos().into())) } - // Calculate the difference in milliseconds between two UnixTimestamps + /// Calculate the difference in milliseconds between two UnixTimestamps pub fn diff_in_millis(&self, other: &UnixTime) -> Option { let seconds_difference = self.secs.checked_sub(other.secs)?; // Convert seconds difference to milliseconds @@ -398,7 +450,9 @@ impl Ord for UnixTime { /// so the sign information is supplied separately. #[derive(Clone, Copy, PartialEq, Eq)] pub struct StampDiff { + /// Positive duration flag. pub positive_duration: bool, + /// Absolute duration. pub duration_absolute: Duration, } diff --git a/src/util.rs b/src/util.rs index 5680808..0a5f7a3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,12 +1,16 @@ +//! # Utility module. use crate::ByteConversionError; use core::fmt::Debug; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; +/// Helper traits for types which can be converted to a byte array. pub trait ToBeBytes { + /// Concrete byte array type. type ByteArray: AsRef<[u8]>; /// Length when written to big endian bytes. fn written_len(&self) -> usize; + /// Convert to big endian byte array. fn to_be_bytes(&self) -> Self::ByteArray; } @@ -80,14 +84,17 @@ impl ToBeBytes for u64 { } } +/// Helper trait for unsigned enumerations. pub trait UnsignedEnum { /// Size of the unsigned enumeration in bytes. fn size(&self) -> usize; /// Write the unsigned enumeration to a raw buffer. Returns the written size on success. fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result; - fn value(&self) -> u64; + /// Type-erased raw value. + fn value_raw(&self) -> u64; + /// Convert to a [alloc::vec::Vec]. #[cfg(feature = "alloc")] fn to_vec(&self) -> alloc::vec::Vec { let mut buf = alloc::vec![0; self.size()]; @@ -96,22 +103,32 @@ pub trait UnsignedEnum { } } +/// Extension trait for unsigned enumerations. pub trait UnsignedEnumExt: UnsignedEnum + Debug + Copy + Clone + PartialEq + Eq {} +/// Unsigned byte field errors. #[derive(Debug, Copy, Clone, PartialEq, Eq, thiserror::Error)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum UnsignedByteFieldError { /// Value is too large for specified width of byte field. #[error("value {value} too large for width {width}")] - ValueTooLargeForWidth { width: usize, value: u64 }, + ValueTooLargeForWidth { + /// Width in bytes. + width: usize, + /// Value. + value: u64, + }, /// Only 1, 2, 4 and 8 are allow width values. Optionally contains the expected width if /// applicable, for example for conversions. #[error("invalid width {found}, expected {expected:?}")] InvalidWidth { + /// Found width. found: usize, + /// Expected width. expected: Option, }, + /// Error during byte conversion. #[error("byte conversion error: {0}")] ByteConversionError(#[from] ByteConversionError), } @@ -126,16 +143,19 @@ pub struct UnsignedByteField { } impl UnsignedByteField { + /// Generic constructor. #[inline] pub const fn new(width: usize, value: u64) -> Self { Self { width, value } } + /// Type-erased raw value. #[inline] - pub const fn value_const(&self) -> u64 { + pub const fn value(&self) -> u64 { self.value } + /// Construct from raw bytes, assuming big-endian byte order. #[inline] pub fn new_from_be_bytes(width: usize, buf: &[u8]) -> Result { if width > buf.len() { @@ -175,8 +195,8 @@ impl UnsignedEnum for UnsignedByteField { } #[inline] - fn value(&self) -> u64 { - self.value_const() + fn value_raw(&self) -> u64 { + self.value() } fn write_to_be_bytes(&self, buf: &mut [u8]) -> Result { @@ -212,6 +232,7 @@ impl UnsignedEnum for UnsignedByteField { } } +/// Generic type erased unsigned byte field. #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -220,11 +241,13 @@ pub struct GenericUnsignedByteField> { } impl> GenericUnsignedByteField { + /// Generic constructor. pub const fn new(val: TYPE) -> Self { Self { value: val } } - pub const fn value_typed(&self) -> TYPE { + /// Raw value. + pub const fn value(&self) -> TYPE { self.value } } @@ -247,20 +270,29 @@ impl> UnsignedEnum for GenericUnsignedByteFie } #[inline] - fn value(&self) -> u64 { - self.value_typed().into() + fn value_raw(&self) -> u64 { + self.value().into() } } +/// Alias for [GenericUnsignedByteField] with [()] generic. pub type UnsignedByteFieldEmpty = GenericUnsignedByteField<()>; +/// Alias for [GenericUnsignedByteField] with [u8] generic. pub type UnsignedByteFieldU8 = GenericUnsignedByteField; +/// Alias for [GenericUnsignedByteField] with [u16] generic. pub type UnsignedByteFieldU16 = GenericUnsignedByteField; +/// Alias for [GenericUnsignedByteField] with [u32] generic. pub type UnsignedByteFieldU32 = GenericUnsignedByteField; +/// Alias for [GenericUnsignedByteField] with [u64] generic. pub type UnsignedByteFieldU64 = GenericUnsignedByteField; +/// Alias for [UnsignedByteFieldU8] pub type UbfU8 = UnsignedByteFieldU8; +/// Alias for [UnsignedByteFieldU16] pub type UbfU16 = UnsignedByteFieldU16; +/// Alias for [UnsignedByteFieldU32] pub type UbfU32 = UnsignedByteFieldU32; +/// Alias for [UnsignedByteFieldU64] pub type UbfU64 = UnsignedByteFieldU64; impl From for UnsignedByteField { @@ -372,7 +404,7 @@ pub mod tests { for val in buf.iter().skip(1) { assert_eq!(*val, 0); } - assert_eq!(u8.value_typed(), 5); + assert_eq!(u8.value_raw(), 5); assert_eq!(u8.value(), 5); } @@ -390,7 +422,7 @@ pub mod tests { for val in buf.iter().skip(2) { assert_eq!(*val, 0); } - assert_eq!(u16.value_typed(), 3823); + assert_eq!(u16.value_raw(), 3823); assert_eq!(u16.value(), 3823); } @@ -408,7 +440,7 @@ pub mod tests { (4..8).for_each(|i| { assert_eq!(buf[i], 0); }); - assert_eq!(u32.value_typed(), 80932); + assert_eq!(u32.value_raw(), 80932); assert_eq!(u32.value(), 80932); } @@ -423,7 +455,7 @@ pub mod tests { assert_eq!(len, 8); let raw_val = u64::from_be_bytes(buf[0..8].try_into().unwrap()); assert_eq!(raw_val, 5999999); - assert_eq!(u64.value_typed(), 5999999); + assert_eq!(u64.value_raw(), 5999999); assert_eq!(u64.value(), 5999999); }