diff --git a/src/time/cuc.rs b/src/time/cuc.rs index 8df6a07..b18a8be 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -156,8 +156,10 @@ pub struct FractionalPart(FractionalResolution, u32); /// It has the capability to generate and read timestamps as specified in the CCSDS 301.0-B-4 /// section 3.2 . The preamble field only has one byte, which allows a time code representation /// through the year 2094. The time is represented as a simple binary counter starting from the -/// fixed CCSDS epoch (1958-01-01T00:00:00+00:00). It is possible to provide subsecond accuracy -/// using the fractional field with various available [resolutions][FractionalResolution]. +/// fixed CCSDS epoch 1958-01-01T00:00:00+00:00 using the TAI reference time scale. This time +/// code provides the advantage of being truly monotonic. +/// It is possible to provide subsecond accuracy using the fractional field with various available +/// [resolutions][FractionalResolution]. /// /// Having a preamble field of one byte limits the width of the counter /// type (generally seconds) to 4 bytes and the width of the fractions type to 3 bytes. This limits @@ -167,6 +169,9 @@ pub struct FractionalPart(FractionalResolution, u32); /// 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. /// +/// This time code is not UTC based. Conversion to UTC based times, for example a UNIX timestamp, +/// can be performed by subtracting the current number of leap seconds. +/// /// # Example /// /// ``` @@ -361,13 +366,18 @@ impl CucTime { res: FractionalResolution, leap_seconds: u32, ) -> Result { - let mut counter = unix_epoch_to_ccsds_epoch(unix_stamp.secs); + let counter = unix_epoch_to_ccsds_epoch(unix_stamp.secs); // Negative CCSDS epoch is invalid. if counter < 0 { return Err(TimestampError::DateBeforeCcsdsEpoch(*unix_stamp)); } + // We already excluded negative values, so the conversion to u64 should always work. + let mut counter = u32::try_from(counter).map_err(|_| CucError::InvalidCounter { + width: 4, + counter: counter as u64, + })?; counter = counter - .checked_add(i64::from(leap_seconds)) + .checked_add(leap_seconds) .ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?; let fractions = fractional_part_from_subsec_ns(res, unix_stamp.subsec_millis() as u64 * 10_u64.pow(6)); @@ -435,7 +445,7 @@ impl CucTime { if counter.1 > (2u64.pow(counter.0 as u32 * 8) - 1) as u32 { return Err(CucError::InvalidCounter { width: counter.0, - counter: counter.1 as u64, + counter: counter.1.into(), }); } if let Some(fractions) = fractions { @@ -704,9 +714,7 @@ impl CcsdsTimeProvider for CucTimeWithLeapSecs { } fn unix_secs(&self) -> i64 { - ccsds_epoch_to_unix_epoch(self.time.counter.1 as i64) - .checked_sub(self.leap_seconds as i64) - .unwrap() + self.time.unix_secs(self.leap_seconds) } fn subsec_nanos(&self) -> u32 {