From 88af15549068f24a34daeae301409635e9949e8b Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 28 Jul 2022 02:09:07 +0200 Subject: [PATCH] tests for time stamp provider --- Cargo.toml | 1 + src/tc.rs | 1 + src/time.rs | 128 ++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 117 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1bf3231..d9c919a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ serde = "1.0.137" zerocopy = "0.6.1" crc = "3.0.0" delegate = "0.7.0" +chrono = "0.4.19" [dependencies.heapless] version = "0.7.14" diff --git a/src/tc.rs b/src/tc.rs index 325f327..cb48f2c 100644 --- a/src/tc.rs +++ b/src/tc.rs @@ -474,6 +474,7 @@ impl PusTcSecondaryHeader for PusTc<'_> { fn ack_flags(&self) -> u8; }); } + #[cfg(test)] mod tests { use crate::ecss::{PusError, PusPacket}; diff --git a/src/time.rs b/src/time.rs index 1ede74d..9da0830 100644 --- a/src/time.rs +++ b/src/time.rs @@ -1,4 +1,6 @@ use crate::PacketError; +use chrono::{DateTime, TimeZone, Utc}; + #[cfg(feature = "std")] use std::time::SystemTime; @@ -34,8 +36,8 @@ pub const fn unix_to_ccsds_days(unix_days: i32) -> i32 { /// /// - CCSDS epoch: 1958 January 1 /// - UNIX Epoch: 1970 January 1 -pub const fn ccsds_to_unix_days(unix_days: i32) -> i32 { - unix_days + DAYS_CCSDS_TO_UNIX +pub const fn ccsds_to_unix_days(ccsds_days: i32) -> i32 { + ccsds_days + DAYS_CCSDS_TO_UNIX } /// Trait for generic CCSDS time providers @@ -48,26 +50,55 @@ trait CcsdsTimeProvider { /// in big endian format. fn p_field(&self) -> (usize, [u8; 2]); fn ccdsd_time_code(&self) -> CcsdsTimeCodes; - fn as_unix_seconds(&self) -> u64; + fn unix_seconds(&self) -> i64; + fn date_time(&self) -> DateTime; } +#[derive(Debug, Copy, Clone)] pub struct CdsShortTimeProvider { pfield: u8, ccsds_days: u16, ms_of_day: u32, - unix_seconds: u64, + unix_seconds: i64, + date_time: Option>, } impl CdsShortTimeProvider { pub fn new(ccsds_days: u16, ms_of_day: u32) -> Self { - let mut provider = Self { + let provider = Self { pfield: (CcsdsTimeCodes::Cds as u8) << 4, ccsds_days, ms_of_day, unix_seconds: 0, + date_time: None, }; - provider.calc_unix_seconds(); - provider + let unix_days_seconds = ccsds_to_unix_days(ccsds_days as i32) as i64 * (24 * 60 * 60); + provider.setup(unix_days_seconds as i64, ms_of_day.into()) + } + + #[cfg(feature = "std")] + pub fn from_now() -> Self { + let now = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("Error retrieving UNIX epoch"); + let epoch = now.as_secs(); + let secs_of_day = epoch % SECONDS_PER_DAY as u64; + let unix_days_seconds = epoch - secs_of_day; + let ms_of_day = secs_of_day * 1000 + now.subsec_millis() as u64; + let provider = Self { + pfield: (CcsdsTimeCodes::Cds as u8) << 4, + ccsds_days: unix_to_ccsds_days((unix_days_seconds / SECONDS_PER_DAY as u64) as i32) as u16, + ms_of_day: ms_of_day as u32, + unix_seconds: 0, + date_time: None, + }; + provider.setup(unix_days_seconds as i64, ms_of_day.into()) + } + + fn setup(mut self, unix_days_seconds: i64, ms_of_day: u64) -> Self { + self.calc_unix_seconds(unix_days_seconds, ms_of_day); + self.calc_date_time(unix_days_seconds, (ms_of_day % 1000) as u32); + self } #[cfg(feature = "std")] @@ -83,13 +114,23 @@ impl CdsShortTimeProvider { ms_of_day } - fn calc_unix_seconds(&mut self) { - let unix_days = ccsds_to_unix_days(self.ccsds_days as i32); - self.unix_seconds = unix_days as u64 * (24 * 60 * 60); - let seconds_of_day = (self.ms_of_day as f32 / 1000.0).floor() as u64; - self.unix_seconds += seconds_of_day; + fn calc_unix_seconds(&mut self, unix_days_seconds: i64, ms_of_day: u64) { + self.unix_seconds = unix_days_seconds; + let seconds_of_day = (ms_of_day / 1000) as i64; + if self.unix_seconds < 0 { + self.unix_seconds -= seconds_of_day; + } else { + self.unix_seconds += seconds_of_day; + } + } + + fn calc_date_time(&mut self, unix_days_seconds: i64, ms_since_last_second: u32) { + assert!(ms_since_last_second < 1000, "Invalid MS since last second"); + let ns_since_last_sec = ms_since_last_second * 1e6 as u32; + self.date_time = Some(Utc.timestamp(unix_days_seconds, ns_since_last_sec)); } } + impl CcsdsTimeProvider for CdsShortTimeProvider { fn len(&self) -> usize { CDS_SHORT_LEN @@ -114,7 +155,68 @@ impl CcsdsTimeProvider for CdsShortTimeProvider { CcsdsTimeCodes::Cds } - fn as_unix_seconds(&self) -> u64 { + fn unix_seconds(&self) -> i64 { self.unix_seconds } + + fn date_time(&self) -> DateTime { + self.date_time.expect("Invalid date time") + } +} + +#[cfg(test)] +mod tests { + use super::*; + use chrono::{Datelike, Timelike}; + #[cfg(feature = "std")] + use std::println; + + #[test] + fn test_creation() { + assert_eq!(unix_to_ccsds_days(DAYS_CCSDS_TO_UNIX), 0); + assert_eq!(ccsds_to_unix_days(0), DAYS_CCSDS_TO_UNIX); + } + + #[cfg(feature = "std")] + #[test] + fn test_get_current_time() { + let sec_floats = seconds_since_epoch(); + assert!(sec_floats > 0.0); + } + + #[test] + fn test_time_stamp_zero_args() { + let time_stamper = CdsShortTimeProvider::new(0, 0); + assert_eq!( + time_stamper.unix_seconds(), + (DAYS_CCSDS_TO_UNIX * 24 * 60 * 60) as i64 + ); + let date_time = time_stamper.date_time(); + assert_eq!(date_time.year(), 1958); + assert_eq!(date_time.month(), 1); + assert_eq!(date_time.day(), 1); + assert_eq!(date_time.hour(), 0); + assert_eq!(date_time.minute(), 0); + assert_eq!(date_time.second(), 0); + } + + #[test] + fn test_time_stamp_unix_epoch() { + let time_stamper = CdsShortTimeProvider::new((-DAYS_CCSDS_TO_UNIX) as u16, 0); + assert_eq!(time_stamper.unix_seconds(), 0); + let date_time = time_stamper.date_time(); + assert_eq!(date_time.year(), 1970); + assert_eq!(date_time.month(), 1); + assert_eq!(date_time.day(), 1); + assert_eq!(date_time.hour(), 0); + assert_eq!(date_time.minute(), 0); + assert_eq!(date_time.second(), 0); + } + + #[cfg(feature = "std")] + #[test] + fn test_time_now() { + let timestamp_now = CdsShortTimeProvider::from_now(); + println!("{}", timestamp_now.date_time()); + } }