dyn provider works great
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
Some checks failed
Rust/spacepackets/pipeline/head There was a failure building this commit
This commit is contained in:
parent
39bf0c6a61
commit
22f3b72faf
143
src/time/cds.rs
143
src/time/cds.rs
@ -7,6 +7,7 @@ use crate::private::Sealed;
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
|
use core::any::Any;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
@ -147,11 +148,22 @@ pub struct TimeProvider<DaysLen: ProvidesDaysLength = DaysLen16Bits> {
|
|||||||
unix_seconds: i64,
|
unix_seconds: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Private trait which serves as an abstraction for different converters.
|
/// Common properties for all CDS time providers.
|
||||||
trait CdsConverter {
|
///
|
||||||
|
/// Also exists to encapsulate properties used by private converters.
|
||||||
|
pub trait CdsCommon {
|
||||||
fn submillis_precision(&self) -> Option<SubmillisPrecision>;
|
fn submillis_precision(&self) -> Option<SubmillisPrecision>;
|
||||||
fn ms_of_day(&self) -> u32;
|
fn ms_of_day(&self) -> u32;
|
||||||
fn ccsds_days(&self) -> u32;
|
fn ccsds_days_as_u32(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic properties for all CDS time providers.
|
||||||
|
pub trait CdsTimeStamp: CdsCommon {
|
||||||
|
fn len_of_day_seg(&self) -> LengthOfDaySegment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Private trait which serves as an abstraction for different converters.
|
||||||
|
trait CdsConverter: CdsCommon {
|
||||||
fn unix_days_seconds(&self) -> i64;
|
fn unix_days_seconds(&self) -> i64;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +197,7 @@ impl ConversionFromUnix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CdsConverter for ConversionFromUnix {
|
impl CdsCommon for ConversionFromUnix {
|
||||||
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -194,22 +206,23 @@ impl CdsConverter for ConversionFromUnix {
|
|||||||
self.ms_of_day
|
self.ms_of_day
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ccsds_days(&self) -> u32 {
|
fn ccsds_days_as_u32(&self) -> u32 {
|
||||||
self.ccsds_days
|
self.ccsds_days
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CdsConverter for ConversionFromUnix {
|
||||||
fn unix_days_seconds(&self) -> i64 {
|
fn unix_days_seconds(&self) -> i64 {
|
||||||
self.unix_days_seconds
|
self.unix_days_seconds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper struct which generates fields for the CDS time provider from a datetime.
|
/// Helper struct which generates fields for the CDS time provider from a datetime.
|
||||||
struct ConversionFromDatetime {
|
struct ConversionFromDatetime {
|
||||||
unix_conversion: ConversionFromUnix,
|
unix_conversion: ConversionFromUnix,
|
||||||
submillis_prec: Option<SubmillisPrecision>,
|
submillis_prec: Option<SubmillisPrecision>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CdsConverter for ConversionFromDatetime {
|
impl CdsCommon for ConversionFromDatetime {
|
||||||
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
||||||
self.submillis_prec
|
self.submillis_prec
|
||||||
}
|
}
|
||||||
@ -217,12 +230,15 @@ impl CdsConverter for ConversionFromDatetime {
|
|||||||
delegate! {
|
delegate! {
|
||||||
to self.unix_conversion {
|
to self.unix_conversion {
|
||||||
fn ms_of_day(&self) -> u32;
|
fn ms_of_day(&self) -> u32;
|
||||||
fn ccsds_days(&self) -> u32;
|
fn ccsds_days_as_u32(&self) -> u32;
|
||||||
fn unix_days_seconds(&self) -> i64;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CdsConverter for ConversionFromDatetime {
|
||||||
|
delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn calc_unix_days_and_secs_of_day(unix_seconds: i64) -> (i64, u32) {
|
fn calc_unix_days_and_secs_of_day(unix_seconds: i64) -> (i64, u32) {
|
||||||
let mut secs_of_day = unix_seconds % SECONDS_PER_DAY as i64;
|
let mut secs_of_day = unix_seconds % SECONDS_PER_DAY as i64;
|
||||||
@ -332,22 +348,25 @@ impl ConversionFromNow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
impl CdsConverter for ConversionFromNow {
|
impl CdsCommon for ConversionFromNow {
|
||||||
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
||||||
self.submillis_prec
|
self.submillis_prec
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate! {
|
delegate! {
|
||||||
to self.unix_conversion {
|
to self.unix_conversion {
|
||||||
fn ms_of_day(&self) -> u32;
|
fn ms_of_day(&self) -> u32;
|
||||||
fn ccsds_days(&self) -> u32;
|
fn ccsds_days_as_u32(&self) -> u32;
|
||||||
fn unix_days_seconds(&self) -> i64;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl CdsConverter for ConversionFromNow {
|
||||||
|
delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub trait DynCdsTimeProvider: CcsdsTimeProvider + TimeWriter {}
|
pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimeStamp + TimeWriter + Any {}
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl DynCdsTimeProvider for TimeProvider<DaysLen16Bits> {}
|
impl DynCdsTimeProvider for TimeProvider<DaysLen16Bits> {}
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
@ -379,7 +398,31 @@ pub fn get_dyn_time_provider_from_bytes(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<ProvidesDaysLen: ProvidesDaysLength> CdsCommon for TimeProvider<ProvidesDaysLen> {
|
||||||
|
fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
||||||
|
self.submillis_precision
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ms_of_day(&self) -> u32 {
|
||||||
|
self.ms_of_day
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ccsds_days_as_u32(&self) -> u32 {
|
||||||
|
self.ccsds_days.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
|
impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
|
||||||
|
/// This function returns the correct [TimeProvider] instance from a raw byte array
|
||||||
|
/// by checking the days of length field. It also checks the CCSDS time code for correctness.
|
||||||
|
///
|
||||||
|
/// The time provider instance is returned as a [DynCdsTimeProvider] trait object.
|
||||||
|
/// This function also simply calls [`get_dyn_time_provider_from_bytes`].
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
pub fn from_bytes_dyn(buf: &[u8]) -> Result<Box<dyn DynCdsTimeProvider>, TimestampError> {
|
||||||
|
get_dyn_time_provider_from_bytes(buf)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_submillis_precision(&mut self, prec: SubmillisPrecision) {
|
pub fn set_submillis_precision(&mut self, prec: SubmillisPrecision) {
|
||||||
self.pfield &= !(0b11);
|
self.pfield &= !(0b11);
|
||||||
if let SubmillisPrecision::Absent = prec {
|
if let SubmillisPrecision::Absent = prec {
|
||||||
@ -407,18 +450,6 @@ impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
|
|||||||
self.ccsds_days
|
self.ccsds_days
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ccsds_days_as_u32(&self) -> u32 {
|
|
||||||
self.ccsds_days.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn submillis_precision(&self) -> Option<SubmillisPrecision> {
|
|
||||||
self.submillis_precision
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ms_of_day(&self) -> u32 {
|
|
||||||
self.ms_of_day
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generic_raw_read_checks(
|
fn generic_raw_read_checks(
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
days_len: LengthOfDaySegment,
|
days_len: LengthOfDaySegment,
|
||||||
@ -603,8 +634,10 @@ impl<ProvidesDaysLen: ProvidesDaysLength> TimeProvider<ProvidesDaysLen> {
|
|||||||
converter: C,
|
converter: C,
|
||||||
) -> Result<Self, TimestampError> {
|
) -> Result<Self, TimestampError> {
|
||||||
let ccsds_days: ProvidesDaysLen::FieldType =
|
let ccsds_days: ProvidesDaysLen::FieldType =
|
||||||
converter.ccsds_days().try_into().map_err(|_| {
|
converter.ccsds_days_as_u32().try_into().map_err(|_| {
|
||||||
TimestampError::CdsError(CdsError::InvalidCcsdsDays(converter.ccsds_days().into()))
|
TimestampError::CdsError(CdsError::InvalidCcsdsDays(
|
||||||
|
converter.ccsds_days_as_u32().into(),
|
||||||
|
))
|
||||||
})?;
|
})?;
|
||||||
let mut provider = Self {
|
let mut provider = Self {
|
||||||
pfield: Self::generate_p_field(days_len, converter.submillis_precision()),
|
pfield: Self::generate_p_field(days_len, converter.submillis_precision()),
|
||||||
@ -908,6 +941,18 @@ fn add_for_max_ccsds_days_val<T: ProvidesDaysLength>(
|
|||||||
(next_ccsds_days, next_ms_of_day, precision)
|
(next_ccsds_days, next_ms_of_day, precision)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CdsTimeStamp for TimeProvider<DaysLen16Bits> {
|
||||||
|
fn len_of_day_seg(&self) -> LengthOfDaySegment {
|
||||||
|
LengthOfDaySegment::Short16Bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CdsTimeStamp for TimeProvider<DaysLen24Bits> {
|
||||||
|
fn len_of_day_seg(&self) -> LengthOfDaySegment {
|
||||||
|
LengthOfDaySegment::Long24Bits
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Allows adding an duration in form of an offset. Please note that the CCSDS days will rollover
|
/// 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
|
/// 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.
|
/// days overflow when this is a possibility and might be a problem.
|
||||||
@ -1443,7 +1488,7 @@ mod tests {
|
|||||||
let time_provider = TimeProvider::from_dt_with_u16_days(&datetime_utc).unwrap();
|
let time_provider = TimeProvider::from_dt_with_u16_days(&datetime_utc).unwrap();
|
||||||
// https://www.timeanddate.com/date/durationresult.html?d1=01&m1=01&y1=1958&d2=14&m2=01&y2=2023
|
// https://www.timeanddate.com/date/durationresult.html?d1=01&m1=01&y1=1958&d2=14&m2=01&y2=2023
|
||||||
// Leap years need to be accounted for as well.
|
// Leap years need to be accounted for as well.
|
||||||
assert_eq!(time_provider.ccsds_days, 23754);
|
assert_eq!(time_provider.ccsds_days(), 23754);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
time_provider.ms_of_day,
|
time_provider.ms_of_day,
|
||||||
30 * 1000 + 49 * 60 * 1000 + 16 * 60 * 60 * 1000 + subsec_millis
|
30 * 1000 + 49 * 60 * 1000 + 16 * 60 * 60 * 1000 + subsec_millis
|
||||||
@ -1662,6 +1707,46 @@ mod tests {
|
|||||||
assert_eq!(provider2.ms_of_day, 5000);
|
assert_eq!(provider2.ms_of_day, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dyn_creation_u24_days() {
|
||||||
|
let stamp = TimeProvider::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.ccsds_days_as_u32(), u16::MAX as u32 + 1);
|
||||||
|
assert_eq!(dyn_provider.ms_of_day(), 24);
|
||||||
|
assert_eq!(dyn_provider.submillis_precision(), None);
|
||||||
|
assert_eq!(
|
||||||
|
dyn_provider.len_of_day_seg(),
|
||||||
|
LengthOfDaySegment::Long24Bits
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_dyn_creation_u16_days_with_precision() {
|
||||||
|
let mut stamp = TimeProvider::new_with_u16_days(24, 24);
|
||||||
|
stamp.set_submillis_precision(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.ccsds_days_as_u32(), 24);
|
||||||
|
assert_eq!(dyn_provider.ms_of_day(), 24);
|
||||||
|
assert_eq!(
|
||||||
|
dyn_provider.len_of_day_seg(),
|
||||||
|
LengthOfDaySegment::Short16Bits
|
||||||
|
);
|
||||||
|
assert!(dyn_provider.submillis_precision().is_some());
|
||||||
|
if let SubmillisPrecision::Microseconds(us) = dyn_provider.submillis_precision().unwrap() {
|
||||||
|
assert_eq!(us, 666);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
fn test_serialization() {
|
fn test_serialization() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user