diff --git a/CHANGELOG.md b/CHANGELOG.md index 9032268..4300d4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,8 +14,9 @@ to check all the API changes in the **Changed** chapter. ## Fixed - CUC timestamp was fixed to include leap second corrections because it is based on the TAI - time reference. Changed the `TimeReader` trait to allow specifying leap seconds which might - be necessary for some timestamps to enable other API. + time reference. The default CUC time object do not implement `CcsdsTimeProvider` anymore + because the trait methods require cached leap second information. This task is now performed + by the `cuc::CucTimeWithLeapSecs` which implements the trait. ## Added @@ -26,7 +27,10 @@ to check all the API changes in the **Changed** chapter. ## Changed -- Renamed `CcsdsTimeProvider::date_time` to `CcsdsTimeProvider::chrono_date_time`. +- Renamed `CcsdsTimeProvider::date_time` to `CcsdsTimeProvider::chrono_date_time` +- Renamed `CcsdsTimeCodes` to `CcsdsTimeCode` +- Renamed `cds::TimeProvider` to `cds::CdsTime` +- Renamed `cuc::TimeProviderCcsdsEpoch` to `cuc::CucTime` - `UnixTimestamp` renamed to `UnixTime` - `UnixTime` seconds are now private and can be retrieved using the `secs` member method. - `UnixTime::new` renamed to `UnixTime::new_checked`. @@ -38,6 +42,7 @@ to check all the API changes in the **Changed** chapter. implementation for the `subsec_millis` method. - `CcsdsTimeProvider::date_time` renamed to `CcsdsTimeProvider::chrono_date_time`. - Added `UnixTime::MIN`, `UnixTime::MAX` and `UnixTime::EPOCH`. +- Added `UnixTime::timelib_date_time`. # [v0.11.0-rc.0] 2024-03-04 diff --git a/src/ecss/tm.rs b/src/ecss/tm.rs index fedfb0e..837a6dc 100644 --- a/src/ecss/tm.rs +++ b/src/ecss/tm.rs @@ -1097,7 +1097,7 @@ mod tests { use super::*; use crate::ecss::PusVersion::PusC; - use crate::time::cds::TimeProvider; + use crate::time::cds::CdsTime; #[cfg(feature = "serde")] use crate::time::CcsdsTimeProvider; use crate::SpHeader; @@ -1136,7 +1136,7 @@ mod tests { #[test] fn test_basic_simple_api() { let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); - let time_provider = TimeProvider::new_with_u16_days(0, 0); + let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = PusTmCreator::new_simple(&mut sph, 17, 2, &time_provider, &mut stamp_buf, None, true) @@ -1534,7 +1534,7 @@ mod tests { #[cfg(feature = "serde")] fn test_serialization_creator_serde() { let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); - let time_provider = TimeProvider::new_with_u16_days(0, 0); + let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = PusTmCreator::new_simple(&mut sph, 17, 2, &time_provider, &mut stamp_buf, None, true) @@ -1549,7 +1549,7 @@ mod tests { #[cfg(feature = "serde")] fn test_serialization_reader_serde() { let mut sph = SpHeader::tm_unseg(0x123, 0x234, 0).unwrap(); - let time_provider = TimeProvider::new_with_u16_days(0, 0); + let time_provider = CdsTime::new_with_u16_days(0, 0); let mut stamp_buf: [u8; 8] = [0; 8]; let pus_tm = PusTmCreator::new_simple(&mut sph, 17, 2, &time_provider, &mut stamp_buf, None, true) diff --git a/src/time/ascii.rs b/src/time/ascii.rs index ad0a210..c749c49 100644 --- a/src/time/ascii.rs +++ b/src/time/ascii.rs @@ -2,11 +2,8 @@ //! [CCSDS 301.0-B-4](https://public.ccsds.org/Pubs/301x0b4e1.pdf) section 3.5 . //! See [chrono::DateTime::format] for a usage example of the generated //! [chrono::format::DelayedFormat] structs. -#[cfg(feature = "alloc")] -use chrono::{ - format::{DelayedFormat, StrftimeItems}, - DateTime, Utc, -}; +#[cfg(all(feature = "alloc", feature = "chrono"))] +pub use alloc_mod_chrono::*; /// Tuple of format string and formatted size for time code A. /// @@ -34,36 +31,41 @@ 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); -/// Generates a time code formatter using the [FMT_STR_CODE_A_WITH_SIZE] format. -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -pub fn generate_time_code_a(date: &DateTime) -> DelayedFormat> { - date.format(FMT_STR_CODE_A_WITH_SIZE.0) -} +#[cfg(all(feature = "alloc", feature = "chrono"))] +pub mod alloc_mod_chrono { + use super::*; + use chrono::{ + format::{DelayedFormat, StrftimeItems}, + DateTime, Utc, + }; -/// Generates a time code formatter using the [FMT_STR_CODE_A_TERMINATED_WITH_SIZE] format. -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -pub fn generate_time_code_a_terminated( - date: &DateTime, -) -> DelayedFormat> { - date.format(FMT_STR_CODE_A_TERMINATED_WITH_SIZE.0) -} + /// Generates a time code formatter using the [FMT_STR_CODE_A_WITH_SIZE] format. + #[cfg_attr(doc_cfg, doc(cfg(all(feature = "alloc", feature = "chrono"))))] + pub fn generate_time_code_a(date: &DateTime) -> DelayedFormat> { + date.format(FMT_STR_CODE_A_WITH_SIZE.0) + } -/// Generates a time code formatter using the [FMT_STR_CODE_B_WITH_SIZE] format. -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -pub fn generate_time_code_b(date: &DateTime) -> DelayedFormat> { - date.format(FMT_STR_CODE_B_WITH_SIZE.0) -} + /// Generates a time code formatter using the [FMT_STR_CODE_A_TERMINATED_WITH_SIZE] format. + #[cfg_attr(doc_cfg, doc(cfg(all(feature = "alloc", feature = "chrono"))))] + pub fn generate_time_code_a_terminated( + date: &DateTime, + ) -> DelayedFormat> { + date.format(FMT_STR_CODE_A_TERMINATED_WITH_SIZE.0) + } -/// Generates a time code formatter using the [FMT_STR_CODE_B_TERMINATED_WITH_SIZE] format. -#[cfg(feature = "alloc")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -pub fn generate_time_code_b_terminated( - date: &DateTime, -) -> DelayedFormat> { - date.format(FMT_STR_CODE_B_TERMINATED_WITH_SIZE.0) + /// Generates a time code formatter using the [FMT_STR_CODE_B_WITH_SIZE] format. + #[cfg_attr(doc_cfg, doc(cfg(all(feature = "alloc", feature = "chrono"))))] + pub fn generate_time_code_b(date: &DateTime) -> DelayedFormat> { + date.format(FMT_STR_CODE_B_WITH_SIZE.0) + } + + /// Generates a time code formatter using the [FMT_STR_CODE_B_TERMINATED_WITH_SIZE] format. + #[cfg_attr(doc_cfg, doc(cfg(all(feature = "alloc", feature = "chrono"))))] + pub fn generate_time_code_b_terminated( + date: &DateTime, + ) -> DelayedFormat> { + date.format(FMT_STR_CODE_B_TERMINATED_WITH_SIZE.0) + } } #[cfg(test)] @@ -77,7 +79,7 @@ mod tests { let date = Utc::now(); let stamp_formatter = generate_time_code_a(&date); let stamp = format!("{}", stamp_formatter); - let t_sep = stamp.find("T"); + let t_sep = stamp.find('T'); assert!(t_sep.is_some()); assert_eq!(t_sep.unwrap(), 10); assert_eq!(stamp.len(), FMT_STR_CODE_A_WITH_SIZE.1); @@ -88,10 +90,10 @@ mod tests { let date = Utc::now(); let stamp_formatter = generate_time_code_a_terminated(&date); let stamp = format!("{}", stamp_formatter); - let t_sep = stamp.find("T"); + let t_sep = stamp.find('T'); assert!(t_sep.is_some()); assert_eq!(t_sep.unwrap(), 10); - let z_terminator = stamp.find("Z"); + let z_terminator = stamp.find('Z'); assert!(z_terminator.is_some()); assert_eq!( z_terminator.unwrap(), @@ -105,7 +107,7 @@ mod tests { let date = Utc::now(); let stamp_formatter = generate_time_code_b(&date); let stamp = format!("{}", stamp_formatter); - let t_sep = stamp.find("T"); + let t_sep = stamp.find('T'); assert!(t_sep.is_some()); assert_eq!(t_sep.unwrap(), 8); assert_eq!(stamp.len(), FMT_STR_CODE_B_WITH_SIZE.1); @@ -116,10 +118,10 @@ mod tests { let date = Utc::now(); let stamp_formatter = generate_time_code_b_terminated(&date); let stamp = format!("{}", stamp_formatter); - let t_sep = stamp.find("T"); + let t_sep = stamp.find('T'); assert!(t_sep.is_some()); assert_eq!(t_sep.unwrap(), 8); - let z_terminator = stamp.find("Z"); + let z_terminator = stamp.find('Z'); assert!(z_terminator.is_some()); assert_eq!( z_terminator.unwrap(), diff --git a/src/time/cds.rs b/src/time/cds.rs index fc553ee..227eab8 100644 --- a/src/time/cds.rs +++ b/src/time/cds.rs @@ -31,15 +31,15 @@ use alloc::boxed::Box; use core::any::Any; #[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use super::{ - ccsds_to_unix_days, unix_to_ccsds_days, CcsdsTimeCodes, CcsdsTimeProvider, TimeReader, + ccsds_to_unix_days, unix_to_ccsds_days, CcsdsTimeCode, CcsdsTimeProvider, TimeReader, TimeWriter, TimestampError, UnixTime, MS_PER_DAY, SECONDS_PER_DAY, }; /// Base value for the preamble field for a time field parser to determine the time field type. -pub const P_FIELD_BASE: u8 = (CcsdsTimeCodes::Cds as u8) << 4; +pub const P_FIELD_BASE: u8 = (CcsdsTimeCode::Cds as u8) << 4; pub const MIN_CDS_FIELD_LEN: usize = 7; pub const MAX_DAYS_24_BITS: u32 = 2_u32.pow(24) - 1; @@ -175,13 +175,13 @@ pub fn precision_from_pfield(pfield: u8) -> SubmillisPrecision { /// } /// // It is possible to add a Duration offset to a timestamp provider. Add 5 minutes offset here /// let offset = Duration::from_secs(60 * 5); -/// let former_unix_seconds = timestamp_now.unix_seconds(); +/// let former_unix_seconds = timestamp_now.unix_secs(); /// let timestamp_in_5_minutes = timestamp_now + offset; -/// assert_eq!(timestamp_in_5_minutes.unix_seconds(), former_unix_seconds + 5 * 60); +/// assert_eq!(timestamp_in_5_minutes.unix_secs(), former_unix_seconds + 5 * 60); /// ``` #[derive(Debug, Copy, Clone, Eq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct TimeProvider { +pub struct CdsTime { pfield: u8, ccsds_days: DaysLen::FieldType, ms_of_day: u32, @@ -341,9 +341,7 @@ impl ConversionFromChronoDatetime { ) -> Result { // The CDS timestamp does not support timestamps before the CCSDS epoch. if dt.year() < 1958 { - return Err(TimestampError::DateBeforeCcsdsEpoch(UnixTime::from( - *dt, - ))); + return Err(TimestampError::DateBeforeCcsdsEpoch(UnixTime::from(*dt))); } // The contained values in the conversion should be all positive now let unix_conversion = @@ -440,10 +438,10 @@ impl CdsConverter for ConversionFromNow { pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimestamp + TimeWriter + Any {} #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -impl DynCdsTimeProvider for TimeProvider {} +impl DynCdsTimeProvider for CdsTime {} #[cfg(feature = "alloc")] #[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] -impl DynCdsTimeProvider for TimeProvider {} +impl DynCdsTimeProvider for CdsTime {} /// This function returns the correct [TimeProvider] instance from a raw byte array /// by checking the length of days field. It also checks the CCSDS time code for correctness. @@ -479,25 +477,25 @@ pub fn get_dyn_time_provider_from_bytes( let time_code = ccsds_time_code_from_p_field(buf[0]); if let Err(e) = time_code { return Err(TimestampError::InvalidTimeCode { - expected: CcsdsTimeCodes::Cds, + expected: CcsdsTimeCode::Cds, found: e, }); } let time_code = time_code.unwrap(); - if time_code != CcsdsTimeCodes::Cds { + if time_code != CcsdsTimeCode::Cds { return Err(TimestampError::InvalidTimeCode { - expected: CcsdsTimeCodes::Cds, + expected: CcsdsTimeCode::Cds, found: time_code as u8, }); } if length_of_day_segment_from_pfield(buf[0]) == LengthOfDaySegment::Short16Bits { - Ok(Box::new(TimeProvider::from_bytes_with_u16_days(buf)?)) + Ok(Box::new(CdsTime::from_bytes_with_u16_days(buf)?)) } else { - Ok(Box::new(TimeProvider::from_bytes_with_u24_days(buf)?)) + Ok(Box::new(CdsTime::from_bytes_with_u24_days(buf)?)) } } -impl CdsCommon for TimeProvider { +impl CdsCommon for CdsTime { fn submillis_precision(&self) -> SubmillisPrecision { precision_from_pfield(self.pfield) } @@ -515,7 +513,7 @@ impl CdsCommon for TimeProvider TimeProvider { +impl CdsTime { /// Please note that a precision value of 0 will be converted to [None] (no precision). pub fn set_submillis(&mut self, prec: SubmillisPrecision, value: u32) -> bool { self.pfield &= !(0b11); @@ -574,19 +572,19 @@ impl TimeProvider { )); } let pfield = buf[0]; - match CcsdsTimeCodes::try_from(pfield >> 4 & 0b111) { + match CcsdsTimeCode::try_from(pfield >> 4 & 0b111) { Ok(cds_type) => match cds_type { - CcsdsTimeCodes::Cds => (), + CcsdsTimeCode::Cds => (), _ => { return Err(TimestampError::InvalidTimeCode { - expected: CcsdsTimeCodes::Cds, + expected: CcsdsTimeCode::Cds, found: cds_type as u8, }) } }, _ => { return Err(TimestampError::InvalidTimeCode { - expected: CcsdsTimeCodes::Cds, + expected: CcsdsTimeCode::Cds, found: pfield >> 4 & 0b111, }); } @@ -710,11 +708,8 @@ impl TimeProvider { days_len: LengthOfDaySegment, submillis_prec: SubmillisPrecision, ) -> Result { - let conv_from_dt = ConversionFromUnix::new( - unix_stamp.secs, - unix_stamp.subsec_nanos, - submillis_prec, - )?; + let conv_from_dt = + ConversionFromUnix::new(unix_stamp.secs, unix_stamp.subsec_nanos, submillis_prec)?; Self::generic_from_conversion(days_len, conv_from_dt) } @@ -806,7 +801,7 @@ impl TimeProvider { } } -impl TimeProvider { +impl CdsTime { /// Generate a new timestamp provider with the days field width set to 24 bits pub fn new_with_u24_days(ccsds_days: u32, ms_of_day: u32) -> Result { if ccsds_days > MAX_DAYS_24_BITS { @@ -907,7 +902,7 @@ impl TimeProvider { } } -impl TimeProvider { +impl CdsTime { /// Generate a new timestamp provider with the days field width set to 16 bits pub fn new_with_u16_days(ccsds_days: u16, ms_of_day: u32) -> Self { // This should never fail, type system ensures CCSDS can not be negative or too large @@ -1005,7 +1000,7 @@ impl TimeProvider { } fn add_for_max_ccsds_days_val( - time_provider: &TimeProvider, + time_provider: &CdsTime, max_days_val: u32, duration: Duration, ) -> (u32, u32, u32) { @@ -1079,13 +1074,13 @@ fn add_for_max_ccsds_days_val( (next_ccsds_days, next_ms_of_day, submillis) } -impl CdsTimestamp for TimeProvider { +impl CdsTimestamp for CdsTime { fn len_of_day_seg(&self) -> LengthOfDaySegment { LengthOfDaySegment::Short16Bits } } -impl CdsTimestamp for TimeProvider { +impl CdsTimestamp for CdsTime { fn len_of_day_seg(&self) -> LengthOfDaySegment { LengthOfDaySegment::Long24Bits } @@ -1094,7 +1089,7 @@ impl CdsTimestamp for TimeProvider { /// Allows adding an duration in form of an offset. Please note that the CCSDS days will rollover /// when they overflow, because addition needs to be infallible. The user needs to check for a /// days overflow when this is a possibility and might be a problem. -impl Add for TimeProvider { +impl Add for CdsTime { type Output = Self; fn add(self, duration: Duration) -> Self::Output { @@ -1106,8 +1101,8 @@ impl Add for TimeProvider { } } -impl Add for &TimeProvider { - type Output = TimeProvider; +impl Add for &CdsTime { + type Output = CdsTime; fn add(self, duration: Duration) -> Self::Output { let (next_ccsds_days, next_ms_of_day, precision) = @@ -1121,7 +1116,7 @@ impl Add for &TimeProvider { /// Allows adding an duration in form of an offset. Please note that the CCSDS days will rollover /// when they overflow, because addition needs to be infallible. The user needs to check for a /// days overflow when this is a possibility and might be a problem. -impl Add for TimeProvider { +impl Add for CdsTime { type Output = Self; fn add(self, duration: Duration) -> Self::Output { @@ -1133,8 +1128,8 @@ impl Add for TimeProvider { } } -impl Add for &TimeProvider { - type Output = TimeProvider; +impl Add for &CdsTime { + type Output = CdsTime; fn add(self, duration: Duration) -> Self::Output { let (next_ccsds_days, next_ms_of_day, precision) = add_for_max_ccsds_days_val(self, MAX_DAYS_24_BITS, duration); @@ -1148,7 +1143,7 @@ impl Add for &TimeProvider { /// Allows adding an duration in form of an offset. Please note that the CCSDS days will rollover /// when they overflow, because addition needs to be infallible. The user needs to check for a /// days overflow when this is a possibility and might be a problem. -impl AddAssign for TimeProvider { +impl AddAssign for CdsTime { fn add_assign(&mut self, duration: Duration) { let (next_ccsds_days, next_ms_of_day, submillis) = add_for_max_ccsds_days_val(self, u16::MAX as u32, duration); @@ -1161,7 +1156,7 @@ impl AddAssign for TimeProvider { /// Allows adding an duration in form of an offset. Please note that the CCSDS days will rollover /// when they overflow, because addition needs to be infallible. The user needs to check for a /// days overflow when this is a possibility and might be a problem. -impl AddAssign for TimeProvider { +impl AddAssign for CdsTime { fn add_assign(&mut self, duration: Duration) { let (next_ccsds_days, next_ms_of_day, submillis) = add_for_max_ccsds_days_val(self, MAX_DAYS_24_BITS, duration); @@ -1172,7 +1167,7 @@ impl AddAssign for TimeProvider { } #[cfg(feature = "chrono")] -impl TryFrom> for TimeProvider { +impl TryFrom> for CdsTime { type Error = TimestampError; fn try_from(dt: chrono::DateTime) -> Result { @@ -1182,7 +1177,7 @@ impl TryFrom> for TimeProvider { } #[cfg(feature = "chrono")] -impl TryFrom> for TimeProvider { +impl TryFrom> for CdsTime { type Error = TimestampError; fn try_from(dt: chrono::DateTime) -> Result { @@ -1191,7 +1186,7 @@ impl TryFrom> for TimeProvider { } } -impl CcsdsTimeProvider for TimeProvider { +impl CcsdsTimeProvider for CdsTime { fn len_as_bytes(&self) -> usize { Self::calc_stamp_len(self.pfield) } @@ -1200,8 +1195,8 @@ impl CcsdsTimeProvider for TimeProvider CcsdsTimeCodes { - CcsdsTimeCodes::Cds + fn ccdsd_time_code(&self) -> CcsdsTimeCode { + CcsdsTimeCode::Cds } #[inline] @@ -1219,19 +1214,19 @@ impl CcsdsTimeProvider for TimeProvider { - fn from_bytes_generic(buf: &[u8], _leap_seconds: Option) -> Result { +impl TimeReader for CdsTime { + fn from_bytes(buf: &[u8]) -> Result { Self::from_bytes_with_u16_days(buf) } } -impl TimeReader for TimeProvider { - fn from_bytes_generic(buf: &[u8], _leap_seconds: Option) -> Result { +impl TimeReader for CdsTime { + fn from_bytes(buf: &[u8]) -> Result { Self::from_bytes_with_u24_days(buf) } } -impl TimeWriter for TimeProvider { +impl TimeWriter for CdsTime { fn write_to_bytes(&self, buf: &mut [u8]) -> Result { self.length_check(buf, self.len_as_bytes())?; buf[0] = self.pfield; @@ -1254,7 +1249,7 @@ impl TimeWriter for TimeProvider { } } -impl TimeWriter for TimeProvider { +impl TimeWriter for CdsTime { fn write_to_bytes(&self, buf: &mut [u8]) -> Result { self.length_check(buf, self.len_as_bytes())?; buf[0] = self.pfield; @@ -1278,7 +1273,7 @@ impl TimeWriter for TimeProvider { } } -impl PartialEq for TimeProvider { +impl PartialEq for CdsTime { fn eq(&self, other: &Self) -> bool { if self.ccsds_days == other.ccsds_days && self.ms_of_day == other.ms_of_day @@ -1290,7 +1285,7 @@ impl PartialEq for TimeProvider PartialOrd for TimeProvider { +impl PartialOrd for CdsTime { fn partial_cmp(&self, other: &Self) -> Option { if self == other { return Some(Ordering::Equal); @@ -1318,14 +1313,14 @@ impl PartialOrd for TimeProvider Ord for TimeProvider { +impl Ord for CdsTime { fn cmp(&self, other: &Self) -> Ordering { PartialOrd::partial_cmp(self, other).unwrap() } } -impl From> for TimeProvider { - fn from(value: TimeProvider) -> Self { +impl From> for CdsTime { + fn from(value: CdsTime) -> Self { // This function only fails if the days value exceeds 24 bits, which is not possible here, // so it is okay to unwrap. Self::new_with_u24_days(value.ccsds_days_as_u32(), value.ms_of_day()).unwrap() @@ -1333,9 +1328,9 @@ impl From> for TimeProvider { } /// This conversion can fail if the days value exceeds 16 bits. -impl TryFrom> for TimeProvider { +impl TryFrom> for CdsTime { type Error = CdsError; - fn try_from(value: TimeProvider) -> Result { + fn try_from(value: CdsTime) -> Result { let ccsds_days = value.ccsds_days_as_u32(); if ccsds_days > u16::MAX as u32 { return Err(CdsError::InvalidCcsdsDays(ccsds_days as i64)); @@ -1361,7 +1356,7 @@ mod tests { #[test] fn test_time_stamp_zero_args() { - let time_stamper = TimeProvider::new_with_u16_days(0, 0); + let time_stamper = CdsTime::new_with_u16_days(0, 0); let unix_stamp = time_stamper.unix_stamp(); assert_eq!( unix_stamp.secs, @@ -1374,10 +1369,10 @@ mod tests { SubmillisPrecision::Absent ); assert_eq!(time_stamper.subsec_nanos(), 0); - assert_eq!(time_stamper.ccdsd_time_code(), CcsdsTimeCodes::Cds); + assert_eq!(time_stamper.ccdsd_time_code(), CcsdsTimeCode::Cds); assert_eq!( time_stamper.p_field(), - (1, [(CcsdsTimeCodes::Cds as u8) << 4, 0]) + (1, [(CcsdsTimeCode::Cds as u8) << 4, 0]) ); let date_time = time_stamper.chrono_date_time().unwrap(); assert_eq!(date_time.year(), 1958); @@ -1390,7 +1385,7 @@ mod tests { #[test] fn test_time_stamp_unix_epoch() { - let time_stamper = TimeProvider::new_with_u16_days((-DAYS_CCSDS_TO_UNIX) as u16, 0); + let time_stamper = CdsTime::new_with_u16_days((-DAYS_CCSDS_TO_UNIX) as u16, 0); assert_eq!(time_stamper.unix_stamp().secs, 0); assert_eq!( time_stamper.submillis_precision(), @@ -1403,17 +1398,17 @@ mod tests { assert_eq!(date_time.hour(), 0); assert_eq!(date_time.minute(), 0); assert_eq!(date_time.second(), 0); - let time_stamper = TimeProvider::new_with_u16_days((-DAYS_CCSDS_TO_UNIX) as u16, 40); + let time_stamper = CdsTime::new_with_u16_days((-DAYS_CCSDS_TO_UNIX) as u16, 40); assert_eq!(time_stamper.subsec_nanos(), 40 * 10_u32.pow(6)); assert_eq!(time_stamper.subsec_millis(), 40); - let time_stamper = TimeProvider::new_with_u16_days((-DAYS_CCSDS_TO_UNIX) as u16, 1040); + let time_stamper = CdsTime::new_with_u16_days((-DAYS_CCSDS_TO_UNIX) as u16, 1040); assert_eq!(time_stamper.subsec_nanos(), 40 * 10_u32.pow(6)); assert_eq!(time_stamper.subsec_millis(), 40); } #[test] fn test_large_days_field_write() { - let time_stamper = TimeProvider::new_with_u24_days(0x108020_u32, 0x10203040); + let time_stamper = CdsTime::new_with_u24_days(0x108020_u32, 0x10203040); assert!(time_stamper.is_ok()); let time_stamper = time_stamper.unwrap(); assert_eq!(time_stamper.len_as_bytes(), 8); @@ -1432,13 +1427,13 @@ mod tests { #[test] fn test_large_days_field_read() { - let time_stamper = TimeProvider::new_with_u24_days(0x108020_u32, 0); + let time_stamper = CdsTime::new_with_u24_days(0x108020_u32, 0); assert!(time_stamper.is_ok()); let time_stamper = time_stamper.unwrap(); let mut buf = [0; 16]; let written = time_stamper.write_to_bytes(&mut buf); assert!(written.is_ok()); - let provider = TimeProvider::::from_bytes(&buf); + let provider = CdsTime::::from_bytes(&buf); assert!(provider.is_ok()); let provider = provider.unwrap(); assert_eq!(provider.ccsds_days(), 0x108020); @@ -1447,13 +1442,13 @@ mod tests { #[test] fn test_large_days_field_read_invalid_ctor() { - let time_stamper = TimeProvider::new_with_u24_days(0x108020, 0); + let time_stamper = CdsTime::new_with_u24_days(0x108020, 0); assert!(time_stamper.is_ok()); let time_stamper = time_stamper.unwrap(); let mut buf = [0; 16]; let written = time_stamper.write_to_bytes(&mut buf); assert!(written.is_ok()); - let faulty_ctor = TimeProvider::::from_bytes(&buf); + let faulty_ctor = CdsTime::::from_bytes(&buf); assert!(faulty_ctor.is_err()); let error = faulty_ctor.unwrap_err(); if let TimestampError::Cds(CdsError::InvalidCtorForDaysOfLenInPreamble(len_of_day)) = error @@ -1467,7 +1462,7 @@ mod tests { #[test] fn test_write() { let mut buf = [0; 16]; - let time_stamper_0 = TimeProvider::new_with_u16_days(0, 0); + let time_stamper_0 = CdsTime::new_with_u16_days(0, 0); let unix_stamp = time_stamper_0.unix_stamp(); assert_eq!( unix_stamp.secs, @@ -1475,7 +1470,7 @@ mod tests { ); let mut res = time_stamper_0.write_to_bytes(&mut buf); assert!(res.is_ok()); - assert_eq!(buf[0], (CcsdsTimeCodes::Cds as u8) << 4); + assert_eq!(buf[0], (CcsdsTimeCode::Cds as u8) << 4); assert_eq!( u16::from_be_bytes(buf[1..3].try_into().expect("Byte conversion failed")), 0 @@ -1484,10 +1479,10 @@ mod tests { u32::from_be_bytes(buf[3..7].try_into().expect("Byte conversion failed")), 0 ); - let time_stamper_1 = TimeProvider::new_with_u16_days(u16::MAX - 1, u32::MAX - 1); + let time_stamper_1 = CdsTime::new_with_u16_days(u16::MAX - 1, u32::MAX - 1); res = time_stamper_1.write_to_bytes(&mut buf); assert!(res.is_ok()); - assert_eq!(buf[0], (CcsdsTimeCodes::Cds as u8) << 4); + assert_eq!(buf[0], (CcsdsTimeCode::Cds as u8) << 4); assert_eq!( u16::from_be_bytes(buf[1..3].try_into().expect("Byte conversion failed")), u16::MAX - 1 @@ -1501,7 +1496,7 @@ mod tests { #[test] fn test_faulty_write_buf_too_small() { let mut buf = [0; 7]; - let time_stamper = TimeProvider::new_with_u16_days(u16::MAX - 1, u32::MAX - 1); + let time_stamper = CdsTime::new_with_u16_days(u16::MAX - 1, u32::MAX - 1); for i in 0..6 { let res = time_stamper.write_to_bytes(&mut buf[0..i]); assert!(res.is_err()); @@ -1527,7 +1522,7 @@ mod tests { fn test_faulty_read_buf_too_small() { let buf = [0; 7]; for i in 0..6 { - let res = TimeProvider::::from_bytes(&buf[0..i]); + let res = CdsTime::::from_bytes(&buf[0..i]); assert!(res.is_err()); let err = res.unwrap_err(); match err { @@ -1548,15 +1543,15 @@ mod tests { #[test] fn test_faulty_invalid_pfield() { let mut buf = [0; 16]; - let time_stamper_0 = TimeProvider::new_with_u16_days(0, 0); + let time_stamper_0 = CdsTime::new_with_u16_days(0, 0); let res = time_stamper_0.write_to_bytes(&mut buf); assert!(res.is_ok()); buf[0] = 0; - let res = TimeProvider::::from_bytes(&buf); + let res = CdsTime::::from_bytes(&buf); assert!(res.is_err()); let err = res.unwrap_err(); if let InvalidTimeCode { expected, found } = err { - assert_eq!(expected, CcsdsTimeCodes::Cds); + assert_eq!(expected, CcsdsTimeCode::Cds); assert_eq!(found, 0); assert_eq!( err.to_string(), @@ -1568,10 +1563,10 @@ mod tests { #[test] fn test_reading() { let mut buf = [0; 16]; - let time_stamper = TimeProvider::new_with_u16_days(u16::MAX - 1, u32::MAX - 1); + let time_stamper = CdsTime::new_with_u16_days(u16::MAX - 1, u32::MAX - 1); let res = time_stamper.write_to_bytes(&mut buf); assert!(res.is_ok()); - assert_eq!(buf[0], (CcsdsTimeCodes::Cds as u8) << 4); + assert_eq!(buf[0], (CcsdsTimeCode::Cds as u8) << 4); assert_eq!( u16::from_be_bytes(buf[1..3].try_into().expect("Byte conversion failed")), u16::MAX - 1 @@ -1581,14 +1576,14 @@ mod tests { u32::MAX - 1 ); - let read_stamp: TimeProvider = - TimeProvider::from_bytes(&buf).expect("Reading timestamp failed"); + let read_stamp: CdsTime = + CdsTime::from_bytes(&buf).expect("Reading timestamp failed"); assert_eq!(read_stamp.ccsds_days(), u16::MAX - 1); assert_eq!(read_stamp.ms_of_day(), u32::MAX - 1); } fn generic_now_test( - timestamp_now: TimeProvider, + timestamp_now: CdsTime, compare_stamp: chrono::DateTime, ) { let dt = timestamp_now.chrono_date_time().unwrap(); @@ -1614,42 +1609,42 @@ mod tests { #[test] fn test_time_now() { - let timestamp_now = TimeProvider::from_now_with_u16_days().unwrap(); + let timestamp_now = CdsTime::from_now_with_u16_days().unwrap(); let compare_stamp = chrono::Utc::now(); generic_now_test(timestamp_now, compare_stamp); } #[test] fn test_time_now_us_prec() { - let timestamp_now = TimeProvider::from_now_with_u16_days_us_precision().unwrap(); + let timestamp_now = CdsTime::from_now_with_u16_days_us_precision().unwrap(); let compare_stamp = chrono::Utc::now(); generic_now_test(timestamp_now, compare_stamp); } #[test] fn test_time_now_ps_prec() { - let timestamp_now = TimeProvider::from_now_with_u16_days_ps_precision().unwrap(); + let timestamp_now = CdsTime::from_now_with_u16_days_ps_precision().unwrap(); let compare_stamp = chrono::Utc::now(); generic_now_test(timestamp_now, compare_stamp); } #[test] fn test_time_now_ps_prec_u16_days() { - let timestamp_now = TimeProvider::from_now_with_u16_days_ps_precision().unwrap(); + let timestamp_now = CdsTime::from_now_with_u16_days_ps_precision().unwrap(); let compare_stamp = chrono::Utc::now(); generic_now_test(timestamp_now, compare_stamp); } #[test] fn test_time_now_ps_prec_u24_days() { - let timestamp_now = TimeProvider::from_now_with_u24_days_ps_precision().unwrap(); + let timestamp_now = CdsTime::from_now_with_u24_days_ps_precision().unwrap(); let compare_stamp = chrono::Utc::now(); generic_now_test(timestamp_now, compare_stamp); } #[test] fn test_submillis_precision_micros() { - let mut time_stamper = TimeProvider::new_with_u16_days(0, 0); + let mut time_stamper = CdsTime::new_with_u16_days(0, 0); time_stamper.set_submillis(SubmillisPrecision::Microseconds, 500); assert_eq!( time_stamper.submillis_precision(), @@ -1667,7 +1662,7 @@ mod tests { #[test] fn test_submillis_precision_picos() { - let mut time_stamper = TimeProvider::new_with_u16_days(0, 0); + let mut time_stamper = CdsTime::new_with_u16_days(0, 0); time_stamper.set_submillis(SubmillisPrecision::Picoseconds, 5e8 as u32); assert_eq!( time_stamper.submillis_precision(), @@ -1685,14 +1680,14 @@ mod tests { #[test] fn read_stamp_with_ps_submillis_precision() { - let mut time_stamper = TimeProvider::new_with_u16_days(0, 0); + let mut time_stamper = CdsTime::new_with_u16_days(0, 0); time_stamper.set_submillis(SubmillisPrecision::Picoseconds, 5e8 as u32); let mut write_buf: [u8; 16] = [0; 16]; let written = time_stamper .write_to_bytes(&mut write_buf) .expect("Writing timestamp failed"); assert_eq!(written, 11); - let stamp_deserialized = TimeProvider::::from_bytes(&write_buf); + let stamp_deserialized = CdsTime::::from_bytes(&write_buf); assert!(stamp_deserialized.is_ok()); let stamp_deserialized = stamp_deserialized.unwrap(); assert_eq!(stamp_deserialized.len_as_bytes(), 11); @@ -1705,14 +1700,14 @@ mod tests { #[test] fn read_stamp_with_us_submillis_precision() { - let mut time_stamper = TimeProvider::new_with_u16_days(0, 0); + let mut time_stamper = CdsTime::new_with_u16_days(0, 0); time_stamper.set_submillis(SubmillisPrecision::Microseconds, 500); let mut write_buf: [u8; 16] = [0; 16]; let written = time_stamper .write_to_bytes(&mut write_buf) .expect("Writing timestamp failed"); assert_eq!(written, 9); - let stamp_deserialized = TimeProvider::::from_bytes(&write_buf); + let stamp_deserialized = CdsTime::::from_bytes(&write_buf); assert!(stamp_deserialized.is_ok()); let stamp_deserialized = stamp_deserialized.unwrap(); assert_eq!(stamp_deserialized.len_as_bytes(), 9); @@ -1725,7 +1720,7 @@ mod tests { #[test] fn read_u24_stamp_with_us_submillis_precision() { - let mut time_stamper = TimeProvider::new_with_u24_days(u16::MAX as u32 + 1, 0).unwrap(); + let mut time_stamper = CdsTime::new_with_u24_days(u16::MAX as u32 + 1, 0).unwrap(); time_stamper.set_submillis(SubmillisPrecision::Microseconds, 500); let mut write_buf: [u8; 16] = [0; 16]; let written = time_stamper @@ -1733,7 +1728,7 @@ mod tests { .expect("Writing timestamp failed"); // 1 byte pfield + 3 bytes days + 4 bytes ms of day + 2 bytes us precision assert_eq!(written, 10); - let stamp_deserialized = TimeProvider::from_bytes_with_u24_days(&write_buf); + let stamp_deserialized = CdsTime::from_bytes_with_u24_days(&write_buf); assert!(stamp_deserialized.is_ok()); let stamp_deserialized = stamp_deserialized.unwrap(); assert_eq!(stamp_deserialized.len_as_bytes(), 10); @@ -1747,7 +1742,7 @@ mod tests { #[test] fn read_u24_stamp_with_ps_submillis_precision() { - let mut time_stamper = TimeProvider::new_with_u24_days(u16::MAX as u32 + 1, 0).unwrap(); + let mut time_stamper = CdsTime::new_with_u24_days(u16::MAX as u32 + 1, 0).unwrap(); time_stamper.set_submillis(SubmillisPrecision::Picoseconds, 5e8 as u32); let mut write_buf: [u8; 16] = [0; 16]; let written = time_stamper @@ -1755,7 +1750,7 @@ mod tests { .expect("Writing timestamp failed"); // 1 byte pfield + 3 bytes days + 4 bytes ms of day + 4 bytes us precision assert_eq!(written, 12); - let stamp_deserialized = TimeProvider::from_bytes_with_u24_days(&write_buf); + let stamp_deserialized = CdsTime::from_bytes_with_u24_days(&write_buf); assert!(stamp_deserialized.is_ok()); let stamp_deserialized = stamp_deserialized.unwrap(); assert_eq!(stamp_deserialized.len_as_bytes(), 12); @@ -1777,7 +1772,7 @@ mod tests { } fn generic_check_dt_case_0( - time_provider: &TimeProvider, + time_provider: &CdsTime, subsec_millis: u32, datetime_utc: chrono::DateTime, ) { @@ -1795,9 +1790,9 @@ mod tests { fn test_creation_from_dt_u16_days() { let subsec_millis = 250; let datetime_utc = generic_dt_case_0_no_prec(subsec_millis); - let time_provider = TimeProvider::from_dt_with_u16_days(&datetime_utc).unwrap(); + let time_provider = CdsTime::from_dt_with_u16_days(&datetime_utc).unwrap(); generic_check_dt_case_0(&time_provider, subsec_millis, datetime_utc); - let time_provider_2: TimeProvider = + let time_provider_2: CdsTime = datetime_utc.try_into().expect("conversion failed"); // Test the TryInto trait impl assert_eq!(time_provider, time_provider_2); @@ -1806,9 +1801,9 @@ mod tests { fn test_creation_from_dt_u24_days() { let subsec_millis = 250; let datetime_utc = generic_dt_case_0_no_prec(subsec_millis); - let time_provider = TimeProvider::from_dt_with_u24_days(&datetime_utc).unwrap(); + let time_provider = CdsTime::from_dt_with_u24_days(&datetime_utc).unwrap(); generic_check_dt_case_0(&time_provider, subsec_millis, datetime_utc); - let time_provider_2: TimeProvider = + let time_provider_2: CdsTime = datetime_utc.try_into().expect("conversion failed"); // Test the TryInto trait impl assert_eq!(time_provider, time_provider_2); @@ -1826,7 +1821,7 @@ mod tests { } fn generic_check_dt_case_1_us_prec( - time_provider: &TimeProvider, + time_provider: &CdsTime, subsec_millis: u32, datetime_utc: chrono::DateTime, ) { @@ -1849,8 +1844,7 @@ mod tests { fn test_creation_from_dt_u16_days_us_prec() { let subsec_millis = 250; let datetime_utc = generic_dt_case_1_us_prec(subsec_millis); - let time_provider = - TimeProvider::from_dt_with_u16_days_us_precision(&datetime_utc).unwrap(); + let time_provider = CdsTime::from_dt_with_u16_days_us_precision(&datetime_utc).unwrap(); generic_check_dt_case_1_us_prec(&time_provider, subsec_millis, datetime_utc); } @@ -1858,8 +1852,7 @@ mod tests { fn test_creation_from_dt_u24_days_us_prec() { let subsec_millis = 250; let datetime_utc = generic_dt_case_1_us_prec(subsec_millis); - let time_provider = - TimeProvider::from_dt_with_u24_days_us_precision(&datetime_utc).unwrap(); + let time_provider = CdsTime::from_dt_with_u24_days_us_precision(&datetime_utc).unwrap(); generic_check_dt_case_1_us_prec(&time_provider, subsec_millis, datetime_utc); } @@ -1879,7 +1872,7 @@ mod tests { } fn generic_check_dt_case_2_ps_prec( - time_provider: &TimeProvider, + time_provider: &CdsTime, subsec_millis: u32, submilli_nanos: u32, datetime_utc: chrono::DateTime, @@ -1903,8 +1896,7 @@ mod tests { fn test_creation_from_dt_u16_days_ps_prec() { let subsec_millis = 250; let (datetime_utc, submilli_nanos) = generic_dt_case_2_ps_prec(subsec_millis); - let time_provider = - TimeProvider::from_dt_with_u16_days_ps_precision(&datetime_utc).unwrap(); + let time_provider = CdsTime::from_dt_with_u16_days_ps_precision(&datetime_utc).unwrap(); generic_check_dt_case_2_ps_prec( &time_provider, subsec_millis, @@ -1917,8 +1909,7 @@ mod tests { fn test_creation_from_dt_u24_days_ps_prec() { let subsec_millis = 250; let (datetime_utc, submilli_nanos) = generic_dt_case_2_ps_prec(subsec_millis); - let time_provider = - TimeProvider::from_dt_with_u24_days_ps_precision(&datetime_utc).unwrap(); + let time_provider = CdsTime::from_dt_with_u24_days_ps_precision(&datetime_utc).unwrap(); generic_check_dt_case_2_ps_prec( &time_provider, subsec_millis, @@ -1931,7 +1922,7 @@ mod tests { fn test_creation_from_unix_stamp_0_u16_days() { let unix_secs = 0; let subsec_millis = 0; - let time_provider = TimeProvider::from_unix_stamp_with_u16_days( + let time_provider = CdsTime::from_unix_stamp_with_u16_days( &UnixTime::new(unix_secs, subsec_millis), SubmillisPrecision::Absent, ) @@ -1943,7 +1934,7 @@ mod tests { fn test_creation_from_unix_stamp_0_u24_days() { let unix_secs = 0; let subsec_millis = 0; - let time_provider = TimeProvider::from_unix_stamp_with_u24_days( + let time_provider = CdsTime::from_unix_stamp_with_u24_days( &UnixTime::new(unix_secs, subsec_millis), SubmillisPrecision::Absent, ) @@ -1960,7 +1951,7 @@ mod tests { .unwrap() .and_local_timezone(chrono::Utc) .unwrap(); - let time_provider = TimeProvider::from_unix_stamp_with_u16_days( + let time_provider = CdsTime::from_unix_stamp_with_u16_days( &datetime_utc.into(), SubmillisPrecision::Absent, ) @@ -1980,7 +1971,7 @@ mod tests { fn test_creation_0_ccsds_days() { let unix_secs = DAYS_CCSDS_TO_UNIX as i64 * SECONDS_PER_DAY as i64; let subsec_millis = 0; - let time_provider = TimeProvider::from_unix_stamp_with_u16_days( + let time_provider = CdsTime::from_unix_stamp_with_u16_days( &UnixTime::new(unix_secs, subsec_millis), SubmillisPrecision::Absent, ) @@ -1992,7 +1983,7 @@ mod tests { fn test_invalid_creation_from_unix_stamp_days_too_large() { let invalid_unix_secs: i64 = (u16::MAX as i64 + 1) * SECONDS_PER_DAY as i64; let subsec_millis = 0; - match TimeProvider::from_unix_stamp_with_u16_days( + match CdsTime::from_unix_stamp_with_u16_days( &UnixTime::new(invalid_unix_secs, subsec_millis), SubmillisPrecision::Absent, ) { @@ -2019,7 +2010,7 @@ mod tests { // precisely 31-12-1957 23:59:55 let unix_secs = DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32 - 5; let subsec_millis = 0; - match TimeProvider::from_unix_stamp_with_u16_days( + match CdsTime::from_unix_stamp_with_u16_days( &UnixTime::new(unix_secs as i64, subsec_millis), SubmillisPrecision::Absent, ) { @@ -2048,7 +2039,7 @@ mod tests { #[test] fn test_addition_u16_days_day_increment() { - let mut provider = TimeProvider::new_with_u16_days(0, MS_PER_DAY - 5 * 1000); + let mut provider = CdsTime::new_with_u16_days(0, MS_PER_DAY - 5 * 1000); let seconds_offset = Duration::from_secs(10); assert_eq!(provider.ccsds_days, 0); assert_eq!(provider.ms_of_day, MS_PER_DAY - 5 * 1000); @@ -2059,7 +2050,7 @@ mod tests { #[test] fn test_addition_u16_days() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); let seconds_offset = Duration::from_secs(5); assert_eq!(provider.ccsds_days, 0); assert_eq!(provider.ms_of_day, 0); @@ -2073,7 +2064,7 @@ mod tests { #[test] fn test_addition_u24_days() { - let mut provider = TimeProvider::new_with_u24_days(u16::MAX as u32, 0).unwrap(); + let mut provider = CdsTime::new_with_u24_days(u16::MAX as u32, 0).unwrap(); let seconds_offset = Duration::from_secs(5); assert_eq!(provider.ccsds_days, u16::MAX as u32); assert_eq!(provider.ms_of_day, 0); @@ -2087,13 +2078,13 @@ mod tests { #[test] fn test_dyn_creation_u24_days() { - let stamp = TimeProvider::new_with_u24_days(u16::MAX as u32 + 1, 24).unwrap(); + let stamp = CdsTime::new_with_u24_days(u16::MAX as u32 + 1, 24).unwrap(); let mut buf: [u8; 32] = [0; 32]; stamp.write_to_bytes(&mut buf).unwrap(); let dyn_provider = get_dyn_time_provider_from_bytes(&buf); assert!(dyn_provider.is_ok()); let dyn_provider = dyn_provider.unwrap(); - assert_eq!(dyn_provider.ccdsd_time_code(), CcsdsTimeCodes::Cds); + assert_eq!(dyn_provider.ccdsd_time_code(), CcsdsTimeCode::Cds); assert_eq!(dyn_provider.ccsds_days_as_u32(), u16::MAX as u32 + 1); assert_eq!(dyn_provider.ms_of_day(), 24); assert_eq!( @@ -2108,7 +2099,7 @@ mod tests { #[test] fn test_addition_with_us_precision_u16_days() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); provider.set_submillis(SubmillisPrecision::Microseconds, 0); let duration = Duration::from_micros(500); provider += duration; @@ -2121,7 +2112,7 @@ mod tests { #[test] fn test_addition_with_us_precision_u16_days_with_subsec_millis() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); provider.set_submillis(SubmillisPrecision::Microseconds, 0); let duration = Duration::from_micros(1200); provider += duration; @@ -2135,7 +2126,7 @@ mod tests { #[test] fn test_addition_with_us_precision_u16_days_carry_over() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); provider.set_submillis(SubmillisPrecision::Microseconds, 800); let duration = Duration::from_micros(400); provider += duration; @@ -2150,7 +2141,7 @@ mod tests { #[test] fn test_addition_with_ps_precision_u16_days() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); provider.set_submillis(SubmillisPrecision::Picoseconds, 0); // 500 us as ns let duration = Duration::from_nanos(500 * 10u32.pow(3) as u64); @@ -2167,7 +2158,7 @@ mod tests { fn test_addition_on_ref() { // This test case also tests the case where there is no submillis precision but subsecond // milliseconds. - let provider_ref = &TimeProvider::new_with_u16_days(2, 500); + let provider_ref = &CdsTime::new_with_u16_days(2, 500); let new_stamp = provider_ref + Duration::from_millis(2 * 24 * 60 * 60 * 1000 + 500); assert_eq!(new_stamp.ccsds_days_as_u32(), 4); assert_eq!(new_stamp.ms_of_day, 1000); @@ -2183,7 +2174,7 @@ mod tests { } #[test] fn test_addition_with_ps_precision_u16_days_with_subsec_millis() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); provider.set_submillis(SubmillisPrecision::Picoseconds, 0); // 1200 us as ns let duration = Duration::from_nanos(1200 * 10u32.pow(3) as u64); @@ -2198,7 +2189,7 @@ mod tests { #[test] fn test_addition_with_ps_precision_u16_days_carryover() { - let mut provider = TimeProvider::new_with_u16_days(0, 0); + let mut provider = CdsTime::new_with_u16_days(0, 0); // 800 us as ps provider.set_submillis(SubmillisPrecision::Picoseconds, 800 * 10_u32.pow(6)); // 400 us as ns @@ -2214,14 +2205,14 @@ mod tests { #[test] fn test_dyn_creation_u16_days_with_precision() { - let mut stamp = TimeProvider::new_with_u16_days(24, 24); + let mut stamp = CdsTime::new_with_u16_days(24, 24); stamp.set_submillis(SubmillisPrecision::Microseconds, 666); let mut buf: [u8; 32] = [0; 32]; stamp.write_to_bytes(&mut buf).unwrap(); let dyn_provider = get_dyn_time_provider_from_bytes(&buf); assert!(dyn_provider.is_ok()); let dyn_provider = dyn_provider.unwrap(); - assert_eq!(dyn_provider.ccdsd_time_code(), CcsdsTimeCodes::Cds); + assert_eq!(dyn_provider.ccdsd_time_code(), CcsdsTimeCode::Cds); assert_eq!(dyn_provider.ccsds_days_as_u32(), 24); assert_eq!(dyn_provider.ms_of_day(), 24); assert_eq!( @@ -2237,7 +2228,7 @@ mod tests { #[test] fn test_new_u24_days_too_large() { - let time_provider = TimeProvider::new_with_u24_days(2_u32.pow(24), 0); + let time_provider = CdsTime::new_with_u24_days(2_u32.pow(24), 0); assert!(time_provider.is_err()); let e = time_provider.unwrap_err(); if let CdsError::InvalidCcsdsDays(days) = e { @@ -2256,7 +2247,7 @@ mod tests { .unwrap() .and_local_timezone(chrono::Utc) .unwrap(); - let time_provider = TimeProvider::from_dt_with_u24_days(&datetime_utc); + let time_provider = CdsTime::from_dt_with_u24_days(&datetime_utc); assert!(time_provider.is_err()); if let TimestampError::DateBeforeCcsdsEpoch(dt) = time_provider.unwrap_err() { assert_eq!(dt, datetime_utc.into()); @@ -2265,10 +2256,10 @@ mod tests { #[test] fn test_eq() { - let stamp0 = TimeProvider::new_with_u16_days(0, 0); + let stamp0 = CdsTime::new_with_u16_days(0, 0); let mut buf: [u8; 7] = [0; 7]; stamp0.write_to_bytes(&mut buf).unwrap(); - let stamp1 = TimeProvider::from_bytes_with_u16_days(&buf).unwrap(); + let stamp1 = CdsTime::from_bytes_with_u16_days(&buf).unwrap(); assert_eq!(stamp0, stamp1); assert!(stamp0 >= stamp1); assert!(stamp1 <= stamp0); @@ -2276,11 +2267,11 @@ mod tests { #[test] fn test_ord() { - let stamp0 = TimeProvider::new_with_u24_days(0, 0).unwrap(); - let stamp1 = TimeProvider::new_with_u24_days(0, 50000).unwrap(); - let mut stamp2 = TimeProvider::new_with_u24_days(0, 50000).unwrap(); + let stamp0 = CdsTime::new_with_u24_days(0, 0).unwrap(); + let stamp1 = CdsTime::new_with_u24_days(0, 50000).unwrap(); + let mut stamp2 = CdsTime::new_with_u24_days(0, 50000).unwrap(); stamp2.set_submillis(SubmillisPrecision::Microseconds, 500); - let stamp3 = TimeProvider::new_with_u24_days(1, 0).unwrap(); + let stamp3 = CdsTime::new_with_u24_days(1, 0).unwrap(); assert!(stamp1 > stamp0); assert!(stamp2 > stamp0); assert!(stamp2 > stamp1); @@ -2291,8 +2282,8 @@ mod tests { #[test] fn test_conversion() { - let mut stamp_small = TimeProvider::new_with_u16_days(u16::MAX, 500); - let stamp_larger: TimeProvider = stamp_small.into(); + let mut stamp_small = CdsTime::new_with_u16_days(u16::MAX, 500); + let stamp_larger: CdsTime = stamp_small.into(); assert_eq!(stamp_larger.ccsds_days_as_u32(), u16::MAX as u32); assert_eq!(stamp_larger.ms_of_day(), 500); stamp_small = stamp_larger.try_into().unwrap(); @@ -2302,7 +2293,7 @@ mod tests { #[test] fn test_update_from_now() { - let mut stamp = TimeProvider::new_with_u16_days(0, 0); + let mut stamp = CdsTime::new_with_u16_days(0, 0); let _ = stamp.update_from_now(); let dt = stamp.unix_stamp().chrono_date_time().unwrap(); assert!(dt.year() > 2020); @@ -2310,17 +2301,17 @@ mod tests { #[test] fn test_setting_submillis_precision() { - let mut provider = TimeProvider::new_with_u16_days(0, 15); + let mut provider = CdsTime::new_with_u16_days(0, 15); provider.set_submillis(SubmillisPrecision::Microseconds, 500); } #[test] #[cfg(feature = "serde")] fn test_serialization() { - let stamp_now = TimeProvider::from_now_with_u16_days().expect("Error retrieving time"); + let stamp_now = CdsTime::from_now_with_u16_days().expect("Error retrieving time"); let val = to_allocvec(&stamp_now).expect("Serializing timestamp failed"); assert!(val.len() > 0); - let stamp_deser: TimeProvider = from_bytes(&val).expect("Stamp deserialization failed"); + let stamp_deser: CdsTime = from_bytes(&val).expect("Stamp deserialization failed"); assert_eq!(stamp_deser, stamp_now); } @@ -2337,7 +2328,7 @@ mod tests { #[test] fn test_stamp_to_vec_u16() { - let stamp = TimeProvider::new_with_u16_days(1, 1); + let stamp = CdsTime::new_with_u16_days(1, 1); let stamp_vec = stamp.to_vec().unwrap(); let mut buf: [u8; 7] = [0; 7]; stamp.write_to_bytes(&mut buf).unwrap(); @@ -2346,10 +2337,23 @@ mod tests { #[test] fn test_stamp_to_vec_u24() { - let stamp = TimeProvider::new_with_u24_days(1, 1).unwrap(); + let stamp = CdsTime::new_with_u24_days(1, 1).unwrap(); let stamp_vec = stamp.to_vec().unwrap(); let mut buf: [u8; 10] = [0; 10]; stamp.write_to_bytes(&mut buf).unwrap(); assert_eq!(stamp_vec, buf[..stamp.len_written()]); } + + #[test] + #[cfg(feature = "timelib")] + fn test_timelib_stamp() { + let stamp = CdsTime::new_with_u16_days(0, 0); + let timelib_dt = stamp.timelib_date_time().unwrap(); + assert_eq!(timelib_dt.year(), 1958); + assert_eq!(timelib_dt.month(), time::Month::January); + assert_eq!(timelib_dt.day(), 1); + assert_eq!(timelib_dt.hour(), 0); + assert_eq!(timelib_dt.minute(), 0); + assert_eq!(timelib_dt.second(), 0); + } } diff --git a/src/time/cuc.rs b/src/time/cuc.rs index 499e598..66f4cf6 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -15,7 +15,7 @@ use crate::ByteConversionError; #[cfg(feature = "std")] use super::StdTimestampError; use super::{ - ccsds_epoch_to_unix_epoch, unix_epoch_to_ccsds_epoch, CcsdsTimeCodes, CcsdsTimeProvider, + ccsds_epoch_to_unix_epoch, unix_epoch_to_ccsds_epoch, CcsdsTimeCode, CcsdsTimeProvider, TimeReader, TimeWriter, TimestampError, UnixTime, }; #[cfg(feature = "std")] @@ -32,7 +32,7 @@ use super::ccsds_time_code_from_p_field; const MIN_CUC_LEN: usize = 2; /// Base value for the preamble field for a time field parser to determine the time field type. -pub const P_FIELD_BASE: u8 = (CcsdsTimeCodes::CucCcsdsEpoch as u8) << 4; +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; @@ -171,15 +171,19 @@ pub struct FractionalPart(FractionalResolution, u32); /// type (generally seconds) to 4 bytes and the width of the fractions type to 3 bytes. This limits /// the maximum time stamp size to [MAX_CUC_LEN_SMALL_PREAMBLE] (8 bytes). /// +/// Please note that this object does not implement the [CcsdsTimeProvider] trait by itself because +/// leap seconds corrections need to be applied to support the trait methods. Instead, it needs +/// to be converted to a [CucTimeWithLeapSecs] object using the [Self::to_leap_sec_helper] method. +/// /// # Example /// /// ``` -/// use spacepackets::time::cuc::{FractionalResolution, TimeProviderCcsdsEpoch}; +/// use spacepackets::time::cuc::{FractionalResolution, CucTime}; /// use spacepackets::time::{TimeWriter, CcsdsTimeCodes, TimeReader, CcsdsTimeProvider}; /// /// const LEAP_SECONDS: u32 = 37; /// // Highest fractional resolution -/// let timestamp_now = TimeProviderCcsdsEpoch::from_now(FractionalResolution::SixtyNs, LEAP_SECONDS) +/// let timestamp_now = CucTime::from_now(FractionalResolution::SixtyNs, LEAP_SECONDS) /// .expect("creating cuc stamp failed"); /// let mut raw_stamp = [0; 16]; /// { @@ -197,11 +201,25 @@ pub struct FractionalPart(FractionalResolution, u32); /// ``` #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct TimeProviderCcsdsEpoch { +pub struct CucTime { pfield: u8, counter: WidthCounterPair, fractions: Option, - leap_seconds: u32, +} + +/// This object is a wrapper object around the [CucTime] object which also tracks +/// the leap seconds. This is necessary to implement the [CcsdsTimeProvider] trait. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct CucTimeWithLeapSecs { + pub time: CucTime, + pub leap_seconds: u32, +} + +impl CucTimeWithLeapSecs { + pub fn new(time: CucTime, leap_seconds: u32) -> Self { + Self { time, leap_seconds } + } } #[inline] @@ -212,28 +230,20 @@ pub fn pfield_len(pfield: u8) -> usize { 1 } -impl TimeProviderCcsdsEpoch { +impl CucTime { /// Create a time provider with a four byte counter and no fractional part. - pub fn new(counter: u32, leap_seconds: u32) -> Self { + pub fn new(counter: u32) -> Self { // These values are definitely valid, so it is okay to unwrap here. - Self::new_generic(WidthCounterPair(4, counter), None, leap_seconds).unwrap() + Self::new_generic(WidthCounterPair(4, counter), None).unwrap() } /// Like [TimeProviderCcsdsEpoch::new] but allow to supply a fractional part as well. - pub fn new_with_fractions( - counter: u32, - fractions: FractionalPart, - leap_seconds: u32, - ) -> Result { - Self::new_generic(WidthCounterPair(4, counter), Some(fractions), leap_seconds) + pub fn new_with_fractions(counter: u32, fractions: FractionalPart) -> Result { + Self::new_generic(WidthCounterPair(4, counter), Some(fractions)) } /// Fractions with a resolution of ~ 4 ms - pub fn new_with_coarse_fractions( - counter: u32, - subsec_fractions: u8, - leap_seconds: u32, - ) -> Self { + pub fn new_with_coarse_fractions(counter: u32, subsec_fractions: u8) -> Self { // These values are definitely valid, so it is okay to unwrap here. Self::new_generic( WidthCounterPair(4, counter), @@ -241,17 +251,12 @@ impl TimeProviderCcsdsEpoch { FractionalResolution::FourMs, subsec_fractions as u32, )), - leap_seconds, ) .unwrap() } /// Fractions with a resolution of ~ 16 us - pub fn new_with_medium_fractions( - counter: u32, - subsec_fractions: u16, - leap_seconds: u32, - ) -> Self { + pub fn new_with_medium_fractions(counter: u32, subsec_fractions: u16) -> Self { // These values are definitely valid, so it is okay to unwrap here. Self::new_generic( WidthCounterPair(4, counter), @@ -259,7 +264,6 @@ impl TimeProviderCcsdsEpoch { FractionalResolution::FifteenUs, subsec_fractions as u32, )), - leap_seconds, ) .unwrap() } @@ -267,18 +271,13 @@ impl TimeProviderCcsdsEpoch { /// Fractions with a resolution of ~ 60 ns. The fractional part value is limited by the /// 24 bits of the fractional field, so this function will fail with /// [CucError::InvalidFractions] if the fractional value exceeds the value. - pub fn new_with_fine_fractions( - counter: u32, - subsec_fractions: u32, - leap_seconds: u32, - ) -> Result { + pub fn new_with_fine_fractions(counter: u32, subsec_fractions: u32) -> Result { Self::new_generic( WidthCounterPair(4, counter), Some(FractionalPart( FractionalResolution::SixtyNs, subsec_fractions, )), - leap_seconds, ) } @@ -301,11 +300,11 @@ impl TimeProviderCcsdsEpoch { .checked_add(i64::from(leap_seconds)) .ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?; if fraction_resolution == FractionalResolution::Seconds { - return Ok(Self::new(ccsds_epoch as u32, leap_seconds)); + return Ok(Self::new(ccsds_epoch as u32)); } let fractions = fractional_part_from_subsec_ns(fraction_resolution, now.subsec_nanos() as u64); - Self::new_with_fractions(ccsds_epoch as u32, fractions.unwrap(), leap_seconds) + Self::new_with_fractions(ccsds_epoch as u32, fractions.unwrap()) .map_err(|e| StdTimestampError::Timestamp(e.into())) } @@ -317,12 +316,12 @@ impl TimeProviderCcsdsEpoch { /// conversion to the CCSDS epoch. #[cfg(feature = "std")] #[cfg_attr(doc_cfg, doc(cfg(feature = "std")))] - pub fn update_from_now(&mut self) -> Result<(), StdTimestampError> { + pub fn update_from_now(&mut self, leap_seconds: u32) -> Result<(), StdTimestampError> { let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?; self.counter.1 = unix_epoch_to_ccsds_epoch(now.as_secs() as i64) as u32; self.counter .1 - .checked_add(self.leap_seconds) + .checked_add(leap_seconds) .ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?; if self.fractions.is_some() { self.fractions = fractional_part_from_subsec_ns( @@ -351,7 +350,6 @@ impl TimeProviderCcsdsEpoch { Self::new_generic( WidthCounterPair(4, counter as u32), fractional_part_from_subsec_ns(res, dt.timestamp_subsec_nanos() as u64), - leap_seconds, ) .map_err(|e| e.into()) } @@ -373,17 +371,16 @@ impl TimeProviderCcsdsEpoch { .ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?; let fractions = fractional_part_from_subsec_ns(res, unix_stamp.subsec_millis() as u64 * 10_u64.pow(6)); - Self::new_generic( - WidthCounterPair(4, ccsds_epoch as u32), - fractions, - leap_seconds, - ) - .map_err(|e| e.into()) + Self::new_generic(WidthCounterPair(4, ccsds_epoch as u32), fractions).map_err(|e| e.into()) } - pub fn new_u16_counter(counter: u16, leap_seconds: u32) -> Self { + pub fn new_u16_counter(counter: u16) -> Self { // These values are definitely valid, so it is okay to unwrap here. - Self::new_generic(WidthCounterPair(2, counter as u32), None, leap_seconds).unwrap() + Self::new_generic(WidthCounterPair(2, counter as u32), None).unwrap() + } + + pub fn ccsds_time_code(&self) -> CcsdsTimeCode { + CcsdsTimeCode::CucCcsdsEpoch } pub fn width_counter_pair(&self) -> WidthCounterPair { @@ -402,6 +399,10 @@ impl TimeProviderCcsdsEpoch { self.fractions } + pub fn to_leap_sec_helper(&self, leap_seconds: u32) -> CucTimeWithLeapSecs { + CucTimeWithLeapSecs::new(*self, leap_seconds) + } + pub fn set_fractions(&mut self, fractions: FractionalPart) -> Result<(), CucError> { Self::verify_fractions_value(fractions)?; self.fractions = Some(fractions); @@ -429,7 +430,6 @@ impl TimeProviderCcsdsEpoch { pub fn new_generic( counter: WidthCounterPair, fractions: Option, - leap_seconds: u32, ) -> Result { Self::verify_counter_width(counter.0)?; if counter.1 > (2u64.pow(counter.0 as u32 * 8) - 1) as u32 { @@ -445,7 +445,6 @@ impl TimeProviderCcsdsEpoch { pfield: Self::build_p_field(counter.0, fractions.map(|v| v.0)), counter, fractions, - leap_seconds, }) } @@ -489,12 +488,17 @@ impl TimeProviderCcsdsEpoch { } #[inline] - fn unix_seconds(&self) -> i64 { + pub fn unix_secs(&self, leap_seconds: u32) -> i64 { ccsds_epoch_to_unix_epoch(self.counter.1 as i64) - .checked_sub(self.leap_seconds as i64) + .checked_sub(leap_seconds as i64) .unwrap() } + #[inline] + pub fn subsec_millis(&self) -> u16 { + (self.subsec_nanos() / 1_000_000) as u16 + } + /// This returns the length of the individual components of the CUC timestamp in addition /// to the total size. /// @@ -536,10 +540,25 @@ impl TimeProviderCcsdsEpoch { } Ok(()) } + + fn len_as_bytes(&self) -> usize { + Self::len_packed_from_pfield(self.pfield) + } + + fn subsec_nanos(&self) -> u32 { + if let Some(fractions) = self.fractions { + if fractions.0 == FractionalResolution::Seconds { + return 0; + } + // Rounding down here is the correct approach. + return convert_fractional_part_to_ns(fractions) as u32; + } + 0 + } } -impl TimeReader for TimeProviderCcsdsEpoch { - fn from_bytes_generic(buf: &[u8], leap_seconds: Option) -> Result { +impl TimeReader for CucTime { + fn from_bytes(buf: &[u8]) -> Result { if buf.len() < MIN_CUC_LEN { return Err(TimestampError::ByteConversion( ByteConversionError::FromSliceTooSmall { @@ -548,21 +567,18 @@ impl TimeReader for TimeProviderCcsdsEpoch { }, )); } - if leap_seconds.is_none() { - return Err(TimestampError::Cuc(CucError::LeapSecondCorrectionError)); - } match ccsds_time_code_from_p_field(buf[0]) { Ok(code) => { - if code != CcsdsTimeCodes::CucCcsdsEpoch { + if code != CcsdsTimeCode::CucCcsdsEpoch { return Err(TimestampError::InvalidTimeCode { - expected: CcsdsTimeCodes::CucCcsdsEpoch, + expected: CcsdsTimeCode::CucCcsdsEpoch, found: code as u8, }); } } Err(raw) => { return Err(TimestampError::InvalidTimeCode { - expected: CcsdsTimeCodes::CucCcsdsEpoch, + expected: CcsdsTimeCode::CucCcsdsEpoch, found: raw, }); } @@ -617,16 +633,12 @@ impl TimeReader for TimeProviderCcsdsEpoch { _ => panic!("unreachable match arm"), } } - let provider = Self::new_generic( - WidthCounterPair(cntr_len, counter), - fractions, - leap_seconds.unwrap(), - )?; + let provider = Self::new_generic(WidthCounterPair(cntr_len, counter), fractions)?; Ok(provider) } } -impl TimeWriter for TimeProviderCcsdsEpoch { +impl TimeWriter for CucTime { fn write_to_bytes(&self, bytes: &mut [u8]) -> Result { // Cross check the sizes of the counters against byte widths in the ctor if bytes.len() < self.len_as_bytes() { @@ -678,37 +690,32 @@ impl TimeWriter for TimeProviderCcsdsEpoch { } } -impl CcsdsTimeProvider for TimeProviderCcsdsEpoch { +impl CcsdsTimeProvider for CucTimeWithLeapSecs { fn len_as_bytes(&self) -> usize { - Self::len_packed_from_pfield(self.pfield) + self.time.len_as_bytes() } fn p_field(&self) -> (usize, [u8; 2]) { - (1, [self.pfield, 0]) + (1, [self.time.pfield, 0]) } - fn ccdsd_time_code(&self) -> CcsdsTimeCodes { - CcsdsTimeCodes::CucCcsdsEpoch + fn ccdsd_time_code(&self) -> CcsdsTimeCode { + self.time.ccsds_time_code() } fn unix_secs(&self) -> i64 { - self.unix_seconds() + ccsds_epoch_to_unix_epoch(self.time.counter.1 as i64) + .checked_sub(self.leap_seconds as i64) + .unwrap() } fn subsec_nanos(&self) -> u32 { - if let Some(fractions) = self.fractions { - if fractions.0 == FractionalResolution::Seconds { - return 0; - } - // Rounding down here is the correct approach. - return convert_fractional_part_to_ns(fractions) as u32; - } - 0 + self.time.subsec_nanos() } } fn get_provider_values_after_duration_addition( - provider: &TimeProviderCcsdsEpoch, + provider: &CucTime, duration: Duration, ) -> (u32, Option) { let mut new_counter = provider.counter.1; @@ -757,7 +764,7 @@ fn get_provider_values_after_duration_addition( (new_counter, fractional_part) } -impl AddAssign for TimeProviderCcsdsEpoch { +impl AddAssign for CucTime { fn add_assign(&mut self, duration: Duration) { let (new_counter, new_fractional_part) = get_provider_values_after_duration_addition(self, duration); @@ -768,7 +775,7 @@ impl AddAssign for TimeProviderCcsdsEpoch { } } -impl Add for TimeProviderCcsdsEpoch { +impl Add for CucTime { type Output = Self; fn add(self, duration: Duration) -> Self::Output { @@ -776,29 +783,23 @@ impl Add for TimeProviderCcsdsEpoch { get_provider_values_after_duration_addition(&self, duration); if let Some(fractional_part) = new_fractional_part { // The generated fractional part should always be valid, so its okay to unwrap here. - return Self::new_with_fractions(new_counter, fractional_part, self.leap_seconds) - .unwrap(); + return Self::new_with_fractions(new_counter, fractional_part).unwrap(); } - Self::new(new_counter, self.leap_seconds) + Self::new(new_counter) } } -impl Add for &TimeProviderCcsdsEpoch { - type Output = TimeProviderCcsdsEpoch; +impl Add for &CucTime { + type Output = CucTime; fn add(self, duration: Duration) -> Self::Output { let (new_counter, new_fractional_part) = get_provider_values_after_duration_addition(self, duration); if let Some(fractional_part) = new_fractional_part { // The generated fractional part should always be valid, so its okay to unwrap here. - return Self::Output::new_with_fractions( - new_counter, - fractional_part, - self.leap_seconds, - ) - .unwrap(); + return Self::Output::new_with_fractions(new_counter, fractional_part).unwrap(); } - Self::Output::new(new_counter, self.leap_seconds) + Self::Output::new(new_counter) } } @@ -817,17 +818,18 @@ mod tests { #[test] fn test_basic_zero_epoch() { // Do not include leap second corrections, which do not apply to dates before 1972. - let zero_cuc = TimeProviderCcsdsEpoch::new(0, 0); + let zero_cuc = CucTime::new(0); assert_eq!(zero_cuc.len_as_bytes(), 5); assert_eq!(zero_cuc.width(), zero_cuc.width_counter_pair().0); assert_eq!(zero_cuc.counter(), zero_cuc.width_counter_pair().1); - assert_eq!(zero_cuc.ccdsd_time_code(), CcsdsTimeCodes::CucCcsdsEpoch); + let ccsds_cuc = zero_cuc.to_leap_sec_helper(0); + assert_eq!(ccsds_cuc.ccdsd_time_code(), CcsdsTimeCode::CucCcsdsEpoch); let counter = zero_cuc.width_counter_pair(); assert_eq!(counter.0, 4); assert_eq!(counter.1, 0); let fractions = zero_cuc.width_fractions_pair(); assert!(fractions.is_none()); - let dt = zero_cuc.chrono_date_time(); + let dt = ccsds_cuc.chrono_date_time(); if let chrono::LocalResult::Single(dt) = dt { assert_eq!(dt.year(), 1958); assert_eq!(dt.month(), 1); @@ -841,11 +843,7 @@ mod tests { #[test] fn test_write_no_fractions() { let mut buf: [u8; 16] = [0; 16]; - let zero_cuc = TimeProviderCcsdsEpoch::new_generic( - WidthCounterPair(4, 0x20102030), - None, - LEAP_SECONDS, - ); + let zero_cuc = CucTime::new_generic(WidthCounterPair(4, 0x20102030), None); assert!(zero_cuc.is_ok()); let zero_cuc = zero_cuc.unwrap(); let res = zero_cuc.write_to_bytes(&mut buf); @@ -858,7 +856,7 @@ mod tests { assert_eq!((buf[0] >> 7) & 0b1, 0); let time_code = ccsds_time_code_from_p_field(buf[0]); assert!(time_code.is_ok()); - assert_eq!(time_code.unwrap(), CcsdsTimeCodes::CucCcsdsEpoch); + assert_eq!(time_code.unwrap(), CcsdsTimeCode::CucCcsdsEpoch); assert_eq!((buf[0] >> 2) & 0b11, 0b11); assert_eq!(buf[0] & 0b11, 0); let raw_counter = u32::from_be_bytes(buf[1..5].try_into().unwrap()); @@ -869,10 +867,11 @@ mod tests { #[test] fn test_datetime_now() { let now = chrono::Utc::now(); - let cuc_now = TimeProviderCcsdsEpoch::from_now(FractionalResolution::SixtyNs, LEAP_SECONDS); + let cuc_now = CucTime::from_now(FractionalResolution::SixtyNs, LEAP_SECONDS); assert!(cuc_now.is_ok()); let cuc_now = cuc_now.unwrap(); - let dt_opt = cuc_now.chrono_date_time(); + let ccsds_cuc = cuc_now.to_leap_sec_helper(LEAP_SECONDS); + let dt_opt = ccsds_cuc.chrono_date_time(); if let chrono::LocalResult::Single(dt) = dt_opt { let diff = dt - now; assert!(diff.num_milliseconds() < 1000); @@ -886,16 +885,9 @@ mod tests { #[test] fn test_read_no_fractions() { let mut buf: [u8; 16] = [0; 16]; - let zero_cuc = TimeProviderCcsdsEpoch::new_generic( - WidthCounterPair(4, 0x20102030), - None, - LEAP_SECONDS, - ) - .unwrap(); + let zero_cuc = CucTime::new_generic(WidthCounterPair(4, 0x20102030), None).unwrap(); zero_cuc.write_to_bytes(&mut buf).unwrap(); - let cuc_read_back = - TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS) - .expect("reading cuc timestamp failed"); + let cuc_read_back = CucTime::from_bytes(&buf).expect("reading cuc timestamp failed"); assert_eq!(cuc_read_back, zero_cuc); assert_eq!(cuc_read_back.width_counter_pair().1, 0x20102030); assert_eq!(cuc_read_back.width_fractions_pair(), None); @@ -905,8 +897,7 @@ mod tests { fn invalid_read_len() { let mut buf: [u8; 16] = [0; 16]; for i in 0..2 { - let res = - TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf[0..i], LEAP_SECONDS); + let res = CucTime::from_bytes(&buf[0..i]); assert!(res.is_err()); let err = res.unwrap_err(); if let TimestampError::ByteConversion(ByteConversionError::FromSliceTooSmall { @@ -918,12 +909,10 @@ mod tests { assert_eq!(expected, 2); } } - let large_stamp = - TimeProviderCcsdsEpoch::new_with_fine_fractions(22, 300, LEAP_SECONDS).unwrap(); + let large_stamp = CucTime::new_with_fine_fractions(22, 300).unwrap(); large_stamp.write_to_bytes(&mut buf).unwrap(); for i in 2..large_stamp.len_as_bytes() - 1 { - let res = - TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf[0..i], LEAP_SECONDS); + let res = CucTime::from_bytes(&buf[0..i]); assert!(res.is_err()); let err = res.unwrap_err(); if let TimestampError::ByteConversion(ByteConversionError::FromSliceTooSmall { @@ -940,7 +929,7 @@ mod tests { #[test] fn write_and_read_tiny_stamp() { let mut buf = [0; 2]; - let cuc = TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(1, 200), None, LEAP_SECONDS); + let cuc = CucTime::new_generic(WidthCounterPair(1, 200), None); assert!(cuc.is_ok()); let cuc = cuc.unwrap(); assert_eq!(cuc.len_as_bytes(), 2); @@ -949,8 +938,7 @@ mod tests { let written = res.unwrap(); assert_eq!(written, 2); assert_eq!(buf[1], 200); - let cuc_read_back = - TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + let cuc_read_back = CucTime::from_bytes(&buf); assert!(cuc_read_back.is_ok()); let cuc_read_back = cuc_read_back.unwrap(); assert_eq!(cuc_read_back, cuc); @@ -959,8 +947,7 @@ mod tests { #[test] fn write_slightly_larger_stamp() { let mut buf = [0; 4]; - let cuc = - TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(2, 40000), None, LEAP_SECONDS); + let cuc = CucTime::new_generic(WidthCounterPair(2, 40000), None); assert!(cuc.is_ok()); let cuc = cuc.unwrap(); assert_eq!(cuc.len_as_bytes(), 3); @@ -969,8 +956,7 @@ mod tests { let written = res.unwrap(); assert_eq!(written, 3); assert_eq!(u16::from_be_bytes(buf[1..3].try_into().unwrap()), 40000); - let cuc_read_back = - TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + let cuc_read_back = CucTime::from_bytes(&buf); assert!(cuc_read_back.is_ok()); let cuc_read_back = cuc_read_back.unwrap(); assert_eq!(cuc_read_back, cuc); @@ -982,11 +968,7 @@ mod tests { #[test] fn write_read_three_byte_cntr_stamp() { let mut buf = [0; 4]; - let cuc = TimeProviderCcsdsEpoch::new_generic( - WidthCounterPair(3, 2_u32.pow(24) - 2), - None, - LEAP_SECONDS, - ); + let cuc = CucTime::new_generic(WidthCounterPair(3, 2_u32.pow(24) - 2), None); assert!(cuc.is_ok()); let cuc = cuc.unwrap(); assert_eq!(cuc.len_as_bytes(), 4); @@ -997,8 +979,7 @@ mod tests { let mut temp_buf = [0; 4]; temp_buf[1..4].copy_from_slice(&buf[1..4]); assert_eq!(u32::from_be_bytes(temp_buf), 2_u32.pow(24) - 2); - let cuc_read_back = - TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + let cuc_read_back = CucTime::from_bytes(&buf); assert!(cuc_read_back.is_ok()); let cuc_read_back = cuc_read_back.unwrap(); assert_eq!(cuc_read_back, cuc); @@ -1007,7 +988,7 @@ mod tests { #[test] fn test_write_invalid_buf() { let mut buf: [u8; 16] = [0; 16]; - let res = TimeProviderCcsdsEpoch::new_with_fine_fractions(0, 0, LEAP_SECONDS); + let res = CucTime::new_with_fine_fractions(0, 0); let cuc = res.unwrap(); for i in 0..cuc.len_as_bytes() - 1 { let err = cuc.write_to_bytes(&mut buf[0..i]); @@ -1028,13 +1009,13 @@ mod tests { #[test] fn invalid_ccsds_stamp_type() { let mut buf: [u8; 16] = [0; 16]; - buf[0] |= (CcsdsTimeCodes::CucAgencyEpoch as u8) << 4; - let res = TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + buf[0] |= (CcsdsTimeCode::CucAgencyEpoch as u8) << 4; + let res = CucTime::from_bytes(&buf); assert!(res.is_err()); let err = res.unwrap_err(); if let TimestampError::InvalidTimeCode { expected, found } = err { - assert_eq!(expected, CcsdsTimeCodes::CucCcsdsEpoch); - assert_eq!(found, CcsdsTimeCodes::CucAgencyEpoch as u8); + assert_eq!(expected, CcsdsTimeCode::CucCcsdsEpoch); + assert_eq!(found, CcsdsTimeCode::CucAgencyEpoch as u8); } else { panic!("unexpected error: {}", err); } @@ -1043,7 +1024,7 @@ mod tests { #[test] fn test_write_with_coarse_fractions() { let mut buf: [u8; 16] = [0; 16]; - let cuc = TimeProviderCcsdsEpoch::new_with_coarse_fractions(0x30201060, 120, LEAP_SECONDS); + let cuc = CucTime::new_with_coarse_fractions(0x30201060, 120); assert!(cuc.fractions.is_some()); assert_eq!(cuc.fractions.unwrap().1, 120); assert_eq!(cuc.fractions.unwrap().0, FractionalResolution::FourMs); @@ -1062,10 +1043,10 @@ mod tests { #[test] fn test_read_with_coarse_fractions() { let mut buf: [u8; 16] = [0; 16]; - let cuc = TimeProviderCcsdsEpoch::new_with_coarse_fractions(0x30201060, 120, LEAP_SECONDS); + let cuc = CucTime::new_with_coarse_fractions(0x30201060, 120); let res = cuc.write_to_bytes(&mut buf); assert!(res.is_ok()); - let res = TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + let res = CucTime::from_bytes(&buf); assert!(res.is_ok()); let read_back = res.unwrap(); assert_eq!(read_back, cuc); @@ -1074,8 +1055,7 @@ mod tests { #[test] fn test_write_with_medium_fractions() { let mut buf: [u8; 16] = [0; 16]; - let cuc = - TimeProviderCcsdsEpoch::new_with_medium_fractions(0x30303030, 30000, LEAP_SECONDS); + let cuc = CucTime::new_with_medium_fractions(0x30303030, 30000); let res = cuc.write_to_bytes(&mut buf); assert!(res.is_ok()); let written = res.unwrap(); @@ -1087,11 +1067,10 @@ mod tests { #[test] fn test_read_with_medium_fractions() { let mut buf: [u8; 16] = [0; 16]; - let cuc = - TimeProviderCcsdsEpoch::new_with_medium_fractions(0x30303030, 30000, LEAP_SECONDS); + let cuc = CucTime::new_with_medium_fractions(0x30303030, 30000); let res = cuc.write_to_bytes(&mut buf); assert!(res.is_ok()); - let res = TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + let res = CucTime::from_bytes(&buf); assert!(res.is_ok()); let cuc_read_back = res.unwrap(); assert_eq!(cuc_read_back, cuc); @@ -1100,11 +1079,7 @@ mod tests { #[test] fn test_write_with_fine_fractions() { let mut buf: [u8; 16] = [0; 16]; - let cuc = TimeProviderCcsdsEpoch::new_with_fine_fractions( - 0x30303030, - u16::MAX as u32 + 60000, - LEAP_SECONDS, - ); + let cuc = CucTime::new_with_fine_fractions(0x30303030, u16::MAX as u32 + 60000); assert!(cuc.is_ok()); let cuc = cuc.unwrap(); let res = cuc.write_to_bytes(&mut buf); @@ -1119,16 +1094,12 @@ mod tests { #[test] fn test_read_with_fine_fractions() { let mut buf: [u8; 16] = [0; 16]; - let cuc = TimeProviderCcsdsEpoch::new_with_fine_fractions( - 0x30303030, - u16::MAX as u32 + 60000, - LEAP_SECONDS, - ); + let cuc = CucTime::new_with_fine_fractions(0x30303030, u16::MAX as u32 + 60000); assert!(cuc.is_ok()); let cuc = cuc.unwrap(); let res = cuc.write_to_bytes(&mut buf); assert!(res.is_ok()); - let res = TimeProviderCcsdsEpoch::from_bytes_with_leap_seconds(&buf, LEAP_SECONDS); + let res = CucTime::from_bytes(&buf); assert!(res.is_ok()); let cuc_read_back = res.unwrap(); assert_eq!(cuc_read_back, cuc); @@ -1202,7 +1173,7 @@ mod tests { #[test] fn update_fractions() { - let mut stamp = TimeProviderCcsdsEpoch::new(2000, LEAP_SECONDS); + let mut stamp = CucTime::new(2000); let res = stamp.set_fractions(FractionalPart(FractionalResolution::SixtyNs, 5000)); assert!(res.is_ok()); assert!(stamp.fractions.is_some()); @@ -1213,13 +1184,13 @@ mod tests { #[test] fn set_fract_resolution() { - let mut stamp = TimeProviderCcsdsEpoch::new(2000, LEAP_SECONDS); + let mut stamp = CucTime::new(2000); stamp.set_fractional_resolution(FractionalResolution::SixtyNs); assert!(stamp.fractions.is_some()); let fractions = stamp.fractions.unwrap(); assert_eq!(fractions.0, FractionalResolution::SixtyNs); assert_eq!(fractions.1, 0); - let res = stamp.update_from_now(); + let res = stamp.update_from_now(LEAP_SECONDS); assert!(res.is_ok()); } @@ -1233,7 +1204,12 @@ mod tests { assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 2); } - fn check_stamp_after_addition(cuc_stamp: &TimeProviderCcsdsEpoch) { + fn check_stamp_after_addition(cuc_stamp: &CucTime) { + let cuc_with_leaps = cuc_stamp.to_leap_sec_helper(LEAP_SECONDS); + assert_eq!( + cuc_with_leaps.ccdsd_time_code(), + CcsdsTimeCode::CucCcsdsEpoch + ); assert_eq!(cuc_stamp.width_counter_pair().1, 202); let fractions = cuc_stamp.width_fractions_pair().unwrap().1; let expected_val = @@ -1248,7 +1224,7 @@ mod tests { #[test] fn add_duration_basic() { - let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200, LEAP_SECONDS); + let mut cuc_stamp = CucTime::new(200); cuc_stamp.set_fractional_resolution(FractionalResolution::FifteenUs); let duration = Duration::from_millis(2500); cuc_stamp += duration; @@ -1257,7 +1233,7 @@ mod tests { #[test] fn add_duration_basic_on_ref() { - let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200, LEAP_SECONDS); + let mut cuc_stamp = CucTime::new(200); cuc_stamp.set_fractional_resolution(FractionalResolution::FifteenUs); let duration = Duration::from_millis(2500); let new_stamp = cuc_stamp + duration; @@ -1266,7 +1242,7 @@ mod tests { #[test] fn add_duration_basic_no_fractions() { - let mut cuc_stamp = TimeProviderCcsdsEpoch::new(200, LEAP_SECONDS); + let mut cuc_stamp = CucTime::new(200); let duration = Duration::from_millis(2000); cuc_stamp += duration; assert_eq!(cuc_stamp.counter(), 202); @@ -1275,7 +1251,7 @@ mod tests { #[test] fn add_duration_basic_on_ref_no_fractions() { - let cuc_stamp = TimeProviderCcsdsEpoch::new(200, LEAP_SECONDS); + let cuc_stamp = CucTime::new(200); let duration = Duration::from_millis(2000); let new_stamp = cuc_stamp + duration; assert_eq!(new_stamp.counter(), 202); @@ -1283,9 +1259,7 @@ mod tests { } #[test] fn add_duration_overflow() { - let mut cuc_stamp = - TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(1, 255), None, LEAP_SECONDS) - .unwrap(); + let mut cuc_stamp = CucTime::new_generic(WidthCounterPair(1, 255), None).unwrap(); let duration = Duration::from_secs(10); cuc_stamp += duration; assert_eq!(cuc_stamp.counter.1, 10); @@ -1293,7 +1267,7 @@ mod tests { #[test] fn test_invalid_width_param() { - let error = TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(8, 0), None, LEAP_SECONDS); + let error = CucTime::new_generic(WidthCounterPair(8, 0), None); assert!(error.is_err()); let error = error.unwrap_err(); if let CucError::InvalidCounterWidth(width) = error { @@ -1307,18 +1281,14 @@ mod tests { #[test] fn test_from_dt() { let dt = chrono::Utc.with_ymd_and_hms(2021, 1, 1, 0, 0, 0).unwrap(); - let cuc = TimeProviderCcsdsEpoch::from_chrono_date_time( - &dt, - FractionalResolution::Seconds, - LEAP_SECONDS, - ) - .unwrap(); + let cuc = CucTime::from_chrono_date_time(&dt, FractionalResolution::Seconds, LEAP_SECONDS) + .unwrap(); assert_eq!(cuc.counter(), dt.timestamp() as u32 + LEAP_SECONDS); } #[test] fn test_new_u16_width() { - let cuc = TimeProviderCcsdsEpoch::new_u16_counter(0, LEAP_SECONDS); + let cuc = CucTime::new_u16_counter(0); assert_eq!(cuc.width(), 2); assert_eq!(cuc.counter(), 0); } @@ -1326,12 +1296,9 @@ mod tests { #[test] fn from_unix_stamp() { let unix_stamp = UnixTime::new(0, 0); - let cuc = TimeProviderCcsdsEpoch::from_unix_stamp( - &unix_stamp, - FractionalResolution::Seconds, - LEAP_SECONDS, - ) - .expect("failed to create cuc from unix stamp"); + let cuc = + CucTime::from_unix_stamp(&unix_stamp, FractionalResolution::Seconds, LEAP_SECONDS) + .expect("failed to create cuc from unix stamp"); assert_eq!( cuc.counter(), (-DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32) as u32 @@ -1340,8 +1307,7 @@ mod tests { #[test] fn test_invalid_counter() { - let cuc_error = - TimeProviderCcsdsEpoch::new_generic(WidthCounterPair(1, 256), None, LEAP_SECONDS); + let cuc_error = CucTime::new_generic(WidthCounterPair(1, 256), None); assert!(cuc_error.is_err()); let cuc_error = cuc_error.unwrap_err(); if let CucError::InvalidCounter { width, counter } = cuc_error { @@ -1355,7 +1321,7 @@ mod tests { #[test] fn test_stamp_to_vec() { - let stamp = TimeProviderCcsdsEpoch::new_u16_counter(100, LEAP_SECONDS); + let stamp = CucTime::new_u16_counter(100); let stamp_vec = stamp.to_vec().unwrap(); let mut buf: [u8; 16] = [0; 16]; stamp.write_to_bytes(&mut buf).unwrap(); diff --git a/src/time/mod.rs b/src/time/mod.rs index d73ada0..b9deea9 100644 --- a/src/time/mod.rs +++ b/src/time/mod.rs @@ -33,7 +33,7 @@ pub const NANOS_PER_SECOND: u32 = 1_000_000_000; #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum CcsdsTimeCodes { +pub enum CcsdsTimeCode { CucCcsdsEpoch = 0b001, CucAgencyEpoch = 0b010, Cds = 0b100, @@ -41,16 +41,16 @@ pub enum CcsdsTimeCodes { AgencyDefined = 0b110, } -impl TryFrom for CcsdsTimeCodes { +impl TryFrom for CcsdsTimeCode { type Error = (); fn try_from(value: u8) -> Result { match value { - x if x == CcsdsTimeCodes::CucCcsdsEpoch as u8 => Ok(CcsdsTimeCodes::CucCcsdsEpoch), - x if x == CcsdsTimeCodes::CucAgencyEpoch as u8 => Ok(CcsdsTimeCodes::CucAgencyEpoch), - x if x == CcsdsTimeCodes::Cds as u8 => Ok(CcsdsTimeCodes::Cds), - x if x == CcsdsTimeCodes::Ccs as u8 => Ok(CcsdsTimeCodes::Ccs), - x if x == CcsdsTimeCodes::AgencyDefined as u8 => Ok(CcsdsTimeCodes::AgencyDefined), + x if x == CcsdsTimeCode::CucCcsdsEpoch as u8 => Ok(CcsdsTimeCode::CucCcsdsEpoch), + x if x == CcsdsTimeCode::CucAgencyEpoch as u8 => Ok(CcsdsTimeCode::CucAgencyEpoch), + x if x == CcsdsTimeCode::Cds as u8 => Ok(CcsdsTimeCode::Cds), + x if x == CcsdsTimeCode::Ccs as u8 => Ok(CcsdsTimeCode::Ccs), + x if x == CcsdsTimeCode::AgencyDefined as u8 => Ok(CcsdsTimeCode::AgencyDefined), _ => Err(()), } } @@ -58,16 +58,16 @@ impl TryFrom for CcsdsTimeCodes { /// Retrieve the CCSDS time code from the p-field. If no valid time code identifier is found, the /// value of the raw time code identification field is returned. -pub fn ccsds_time_code_from_p_field(pfield: u8) -> Result { +pub fn ccsds_time_code_from_p_field(pfield: u8) -> Result { let raw_bits = (pfield >> 4) & 0b111; - CcsdsTimeCodes::try_from(raw_bits).map_err(|_| raw_bits) + CcsdsTimeCode::try_from(raw_bits).map_err(|_| raw_bits) } #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[non_exhaustive] pub enum TimestampError { - InvalidTimeCode { expected: CcsdsTimeCodes, found: u8 }, + InvalidTimeCode { expected: CcsdsTimeCode, found: u8 }, ByteConversion(ByteConversionError), Cds(cds::CdsError), Cuc(cuc::CucError), @@ -208,21 +208,14 @@ pub trait TimeWriter { } pub trait TimeReader: Sized { - fn from_bytes(buf: &[u8]) -> Result { - Self::from_bytes_generic(buf, None) - } - - fn from_bytes_with_leap_seconds(buf: &[u8], leap_seconds: u32) -> Result { - Self::from_bytes_generic(buf, Some(leap_seconds)) - } - - fn from_bytes_generic(buf: &[u8], leap_seconds: Option) -> Result; + fn from_bytes(buf: &[u8]) -> Result; } /// Trait for generic CCSDS time providers. /// -/// The UNIX helper methods and the [Self::date_time] method are not strictly necessary but extremely +/// The UNIX helper methods and the helper method are not strictly necessary but extremely /// 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 { fn len_as_bytes(&self) -> usize; @@ -231,7 +224,7 @@ 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]); - fn ccdsd_time_code(&self) -> CcsdsTimeCodes; + fn ccdsd_time_code(&self) -> CcsdsTimeCode; fn unix_secs(&self) -> i64; fn subsec_nanos(&self) -> u32; @@ -253,10 +246,8 @@ pub trait CcsdsTimeProvider { #[cfg(feature = "timelib")] #[cfg_attr(doc_cfg, doc(cfg(feature = "timelib")))] fn timelib_date_time(&self) -> Result { - Ok( - time::OffsetDateTime::from_unix_timestamp(self.unix_seconds())? - + time::Duration::nanoseconds(self.subsecond_nanos().into()), - ) + Ok(time::OffsetDateTime::from_unix_timestamp(self.unix_secs())? + + time::Duration::nanoseconds(self.subsec_nanos().into())) } } @@ -374,11 +365,9 @@ impl UnixTime { #[cfg(feature = "timelib")] #[cfg_attr(doc_cfg, doc(cfg(feature = "timelib")))] - fn timelib_date_time(&self) -> Result { - Ok( - time::OffsetDateTime::from_unix_timestamp(self.unix_seconds())? - + time::Duration::nanoseconds(self.subsecond_nanos().into()), - ) + pub fn timelib_date_time(&self) -> Result { + Ok(time::OffsetDateTime::from_unix_timestamp(self.secs())? + + time::Duration::nanoseconds(self.subsec_nanos().into())) } // Calculate the difference in milliseconds between two UnixTimestamps @@ -651,7 +640,7 @@ mod tests { fn test_addition() { let mut stamp0 = UnixTime::new_only_secs(1); stamp0 += Duration::from_secs(5); - assert_eq!(stamp0.secs, 6); + assert_eq!(stamp0.secs(), 6); assert_eq!(stamp0.subsec_millis(), 0); let stamp1 = stamp0 + Duration::from_millis(500); assert_eq!(stamp1.secs, 6); @@ -737,4 +726,17 @@ mod tests { let stamp_error = TimestampError::from(cuc_error); assert_eq!(stamp_error.to_string(), format!("cuc error: {cuc_error}")); } + + #[test] + #[cfg(feature = "timelib")] + fn test_unix_stamp_as_timelib_datetime() { + let stamp_epoch = UnixTime::EPOCH; + let timelib_dt = stamp_epoch.timelib_date_time().unwrap(); + assert_eq!(timelib_dt.year(), 1970); + assert_eq!(timelib_dt.month(), time::Month::January); + assert_eq!(timelib_dt.day(), 1); + assert_eq!(timelib_dt.hour(), 0); + assert_eq!(timelib_dt.minute(), 0); + assert_eq!(timelib_dt.second(), 0); + } }