move some modules
This commit is contained in:
658
src/time/cds.rs
658
src/time/cds.rs
@@ -193,248 +193,6 @@ 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;
|
||||
}
|
||||
|
||||
struct ConversionFromUnix {
|
||||
ccsds_days: u32,
|
||||
ms_of_day: u32,
|
||||
submilis_prec: SubmillisPrecision,
|
||||
submillis: u32,
|
||||
/// This is a side-product of the calculation of the CCSDS days. It is useful for
|
||||
/// re-calculating the datetime at a later point and therefore supplied as well.
|
||||
unix_days_seconds: i64,
|
||||
}
|
||||
|
||||
impl ConversionFromUnix {
|
||||
fn new(
|
||||
unix_seconds: i64,
|
||||
subsec_nanos: u32,
|
||||
precision: SubmillisPrecision,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
let (unix_days, secs_of_day) = calc_unix_days_and_secs_of_day(unix_seconds);
|
||||
let ccsds_days = unix_to_ccsds_days(unix_days);
|
||||
if ccsds_days == 0 && (secs_of_day > 0 || subsec_nanos > 0) || ccsds_days < 0 {
|
||||
return Err(DateBeforeCcsdsEpochError(
|
||||
UnixTime::new_checked(unix_seconds, subsec_nanos)
|
||||
.expect("unix timestamp creation failed"),
|
||||
));
|
||||
}
|
||||
let ms_of_day = secs_of_day * 1000 + subsec_nanos / 10_u32.pow(6);
|
||||
|
||||
let submillis = match precision {
|
||||
SubmillisPrecision::Microseconds => (subsec_nanos / 1_000) % 1000,
|
||||
SubmillisPrecision::Picoseconds => (subsec_nanos % 10_u32.pow(6)) * 1000,
|
||||
_ => 0,
|
||||
};
|
||||
Ok(Self {
|
||||
ccsds_days: unix_to_ccsds_days(unix_days) as u32,
|
||||
ms_of_day,
|
||||
unix_days_seconds: unix_days * SECONDS_PER_DAY as i64,
|
||||
submilis_prec: precision,
|
||||
submillis,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CdsCommon for ConversionFromUnix {
|
||||
#[inline]
|
||||
fn submillis_precision(&self) -> SubmillisPrecision {
|
||||
self.submilis_prec
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ms_of_day(&self) -> u32 {
|
||||
self.ms_of_day
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ccsds_days_as_u32(&self) -> u32 {
|
||||
self.ccsds_days
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn submillis(&self) -> u32 {
|
||||
self.submillis
|
||||
}
|
||||
}
|
||||
|
||||
impl CdsConverter for ConversionFromUnix {
|
||||
#[inline]
|
||||
fn unix_days_seconds(&self) -> i64 {
|
||||
self.unix_days_seconds
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper struct which generates fields for the CDS time provider from a datetime.
|
||||
#[cfg(feature = "chrono")]
|
||||
struct ConversionFromChronoDatetime {
|
||||
unix_conversion: ConversionFromUnix,
|
||||
submillis_prec: SubmillisPrecision,
|
||||
submillis: u32,
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl CdsCommon for ConversionFromChronoDatetime {
|
||||
#[inline]
|
||||
fn submillis_precision(&self) -> SubmillisPrecision {
|
||||
self.submillis_prec
|
||||
}
|
||||
|
||||
delegate::delegate! {
|
||||
to self.unix_conversion {
|
||||
#[inline]
|
||||
fn ms_of_day(&self) -> u32;
|
||||
#[inline]
|
||||
fn ccsds_days_as_u32(&self) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn submillis(&self) -> u32 {
|
||||
self.submillis
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl CdsConverter for ConversionFromChronoDatetime {
|
||||
delegate::delegate! {to self.unix_conversion {
|
||||
#[inline]
|
||||
fn unix_days_seconds(&self) -> i64;
|
||||
}}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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 unix_days = (unix_seconds - secs_of_day) / SECONDS_PER_DAY as i64;
|
||||
// Imagine the CCSDS epoch time minus 5 seconds: We now have the last day in the year
|
||||
// 1969 (-1 unix days) shortly before midnight (SECONDS_PER_DAY - 5).
|
||||
if secs_of_day < 0 {
|
||||
unix_days -= 1;
|
||||
secs_of_day += SECONDS_PER_DAY as i64
|
||||
}
|
||||
(unix_days, secs_of_day as u32)
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl ConversionFromChronoDatetime {
|
||||
fn new(dt: &chrono::DateTime<chrono::Utc>) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
Self::new_generic(dt, SubmillisPrecision::Absent)
|
||||
}
|
||||
|
||||
fn new_with_submillis_us_prec(
|
||||
dt: &chrono::DateTime<chrono::Utc>,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
Self::new_generic(dt, SubmillisPrecision::Microseconds)
|
||||
}
|
||||
|
||||
fn new_with_submillis_ps_prec(
|
||||
dt: &chrono::DateTime<chrono::Utc>,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
Self::new_generic(dt, SubmillisPrecision::Picoseconds)
|
||||
}
|
||||
|
||||
fn new_generic(
|
||||
dt: &chrono::DateTime<chrono::Utc>,
|
||||
prec: SubmillisPrecision,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
// The CDS timestamp does not support timestamps before the CCSDS epoch.
|
||||
if dt.year() < 1958 {
|
||||
return Err(DateBeforeCcsdsEpochError(UnixTime::from(*dt)));
|
||||
}
|
||||
// The contained values in the conversion should be all positive now
|
||||
let unix_conversion =
|
||||
ConversionFromUnix::new(dt.timestamp(), dt.timestamp_subsec_nanos(), prec)?;
|
||||
let mut submillis = 0;
|
||||
match prec {
|
||||
SubmillisPrecision::Microseconds => {
|
||||
submillis = dt.timestamp_subsec_micros() % 1000;
|
||||
}
|
||||
SubmillisPrecision::Picoseconds => {
|
||||
submillis = (dt.timestamp_subsec_nanos() % 10_u32.pow(6)) * 1000;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(Self {
|
||||
unix_conversion,
|
||||
submillis_prec: prec,
|
||||
submillis,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
struct ConversionFromNow {
|
||||
unix_conversion: ConversionFromUnix,
|
||||
submillis_prec: SubmillisPrecision,
|
||||
submillis: u32,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ConversionFromNow {
|
||||
fn new() -> Result<Self, SystemTimeError> {
|
||||
Self::new_generic(SubmillisPrecision::Absent)
|
||||
}
|
||||
|
||||
fn new_with_submillis_us_prec() -> Result<Self, SystemTimeError> {
|
||||
Self::new_generic(SubmillisPrecision::Microseconds)
|
||||
}
|
||||
|
||||
fn new_with_submillis_ps_prec() -> Result<Self, SystemTimeError> {
|
||||
Self::new_generic(SubmillisPrecision::Picoseconds)
|
||||
}
|
||||
|
||||
fn new_generic(prec: SubmillisPrecision) -> Result<Self, SystemTimeError> {
|
||||
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
||||
let epoch = now.as_secs();
|
||||
// This should always return a value with valid (non-negative) CCSDS days,
|
||||
// so it is okay to unwrap
|
||||
let unix_conversion =
|
||||
ConversionFromUnix::new(epoch as i64, now.subsec_nanos(), prec).unwrap();
|
||||
let mut submillis = 0;
|
||||
|
||||
match prec {
|
||||
SubmillisPrecision::Microseconds => {
|
||||
submillis = now.subsec_micros() % 1000;
|
||||
}
|
||||
SubmillisPrecision::Picoseconds => {
|
||||
submillis = (now.subsec_nanos() % 10_u32.pow(6)) * 1000;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(Self {
|
||||
unix_conversion,
|
||||
submillis_prec: prec,
|
||||
submillis,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl CdsCommon for ConversionFromNow {
|
||||
fn submillis_precision(&self) -> SubmillisPrecision {
|
||||
self.submillis_prec
|
||||
}
|
||||
delegate::delegate! {
|
||||
to self.unix_conversion {
|
||||
fn ms_of_day(&self) -> u32;
|
||||
fn ccsds_days_as_u32(&self) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
fn submillis(&self) -> u32 {
|
||||
self.submillis
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl CdsConverter for ConversionFromNow {
|
||||
delegate::delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
pub trait DynCdsTimeProvider: CcsdsTimeProvider + CdsTimestamp + TimeWriter + Any {}
|
||||
#[cfg(feature = "alloc")]
|
||||
@@ -999,93 +757,6 @@ impl CdsTime<DaysLen16Bits> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_for_max_ccsds_days_val<T: ProvidesDaysLength>(
|
||||
time_provider: &CdsTime<T>,
|
||||
max_days_val: u32,
|
||||
duration: Duration,
|
||||
) -> (u32, u32, u32) {
|
||||
let mut next_ccsds_days = time_provider.ccsds_days_as_u32();
|
||||
let mut next_ms_of_day = time_provider.ms_of_day;
|
||||
// Increment CCSDS days by a certain amount while also accounting for overflow.
|
||||
let increment_days = |ccsds_days: &mut u32, days_inc: u32| {
|
||||
let days_addition: u64 = *ccsds_days as u64 + days_inc as u64;
|
||||
if days_addition > max_days_val as u64 {
|
||||
*ccsds_days = (days_addition - max_days_val as u64) as u32;
|
||||
} else {
|
||||
*ccsds_days += days_inc;
|
||||
}
|
||||
};
|
||||
// Increment MS of day by a certain amount while also accounting for overflow, where
|
||||
// the new value exceeds the MS of a day.
|
||||
let increment_ms_of_day = |ms_of_day: &mut u32, ms_inc: u32, ccsds_days: &mut u32| {
|
||||
*ms_of_day += ms_inc;
|
||||
if *ms_of_day >= MS_PER_DAY {
|
||||
*ms_of_day -= MS_PER_DAY;
|
||||
// Re-use existing closure to always amount for overflow.
|
||||
increment_days(ccsds_days, 1);
|
||||
}
|
||||
};
|
||||
let mut submillis = time_provider.submillis();
|
||||
match time_provider.submillis_precision() {
|
||||
SubmillisPrecision::Microseconds => {
|
||||
let subsec_micros = duration.subsec_micros();
|
||||
let subsec_millis = subsec_micros / 1000;
|
||||
let submilli_micros = subsec_micros % 1000;
|
||||
submillis += submilli_micros;
|
||||
if submillis >= 1000 {
|
||||
let carryover_us = submillis - 1000;
|
||||
increment_ms_of_day(&mut next_ms_of_day, 1, &mut next_ccsds_days);
|
||||
submillis = carryover_us;
|
||||
}
|
||||
increment_ms_of_day(&mut next_ms_of_day, subsec_millis, &mut next_ccsds_days);
|
||||
}
|
||||
SubmillisPrecision::Picoseconds => {
|
||||
let subsec_nanos = duration.subsec_nanos();
|
||||
let subsec_millis = subsec_nanos / 10_u32.pow(6);
|
||||
// 1 ms as ns is 1e6.
|
||||
let submilli_nanos = subsec_nanos % 10_u32.pow(6);
|
||||
// No overflow risk: The maximum value of an u32 is ~4.294e9, and one ms as ps
|
||||
// is 1e9. The amount ps can now have is always less than 2e9.
|
||||
submillis += submilli_nanos * 1000;
|
||||
if submillis >= 10_u32.pow(9) {
|
||||
let carry_over_ps = submillis - 10_u32.pow(9);
|
||||
increment_ms_of_day(&mut next_ms_of_day, 1, &mut next_ccsds_days);
|
||||
submillis = carry_over_ps;
|
||||
}
|
||||
increment_ms_of_day(&mut next_ms_of_day, subsec_millis, &mut next_ccsds_days);
|
||||
}
|
||||
_ => {
|
||||
increment_ms_of_day(
|
||||
&mut next_ms_of_day,
|
||||
duration.subsec_millis(),
|
||||
&mut next_ccsds_days,
|
||||
);
|
||||
}
|
||||
}
|
||||
// The subsecond millisecond were already handled.
|
||||
let full_seconds = duration.as_secs();
|
||||
let secs_of_day = (full_seconds % SECONDS_PER_DAY as u64) as u32;
|
||||
let ms_of_day = secs_of_day * 1000;
|
||||
increment_ms_of_day(&mut next_ms_of_day, ms_of_day, &mut next_ccsds_days);
|
||||
increment_days(
|
||||
&mut next_ccsds_days,
|
||||
(full_seconds as u32 - secs_of_day) / SECONDS_PER_DAY,
|
||||
);
|
||||
(next_ccsds_days, next_ms_of_day, submillis)
|
||||
}
|
||||
|
||||
impl CdsTimestamp for CdsTime<DaysLen16Bits> {
|
||||
fn len_of_day_seg(&self) -> LengthOfDaySegment {
|
||||
LengthOfDaySegment::Short16Bits
|
||||
}
|
||||
}
|
||||
|
||||
impl CdsTimestamp for CdsTime<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
|
||||
/// 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.
|
||||
@@ -1334,6 +1005,335 @@ impl TryFrom<CdsTime<DaysLen24Bits>> for CdsTime<DaysLen16Bits> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Private trait which serves as an abstraction for different converters.
|
||||
trait CdsConverter: CdsCommon {
|
||||
fn unix_days_seconds(&self) -> i64;
|
||||
}
|
||||
|
||||
struct ConversionFromUnix {
|
||||
ccsds_days: u32,
|
||||
ms_of_day: u32,
|
||||
submilis_prec: SubmillisPrecision,
|
||||
submillis: u32,
|
||||
/// This is a side-product of the calculation of the CCSDS days. It is useful for
|
||||
/// re-calculating the datetime at a later point and therefore supplied as well.
|
||||
unix_days_seconds: i64,
|
||||
}
|
||||
|
||||
impl ConversionFromUnix {
|
||||
fn new(
|
||||
unix_seconds: i64,
|
||||
subsec_nanos: u32,
|
||||
precision: SubmillisPrecision,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
let (unix_days, secs_of_day) = calc_unix_days_and_secs_of_day(unix_seconds);
|
||||
let ccsds_days = unix_to_ccsds_days(unix_days);
|
||||
if ccsds_days == 0 && (secs_of_day > 0 || subsec_nanos > 0) || ccsds_days < 0 {
|
||||
return Err(DateBeforeCcsdsEpochError(
|
||||
UnixTime::new_checked(unix_seconds, subsec_nanos)
|
||||
.expect("unix timestamp creation failed"),
|
||||
));
|
||||
}
|
||||
let ms_of_day = secs_of_day * 1000 + subsec_nanos / 10_u32.pow(6);
|
||||
|
||||
let submillis = match precision {
|
||||
SubmillisPrecision::Microseconds => (subsec_nanos / 1_000) % 1000,
|
||||
SubmillisPrecision::Picoseconds => (subsec_nanos % 10_u32.pow(6)) * 1000,
|
||||
_ => 0,
|
||||
};
|
||||
Ok(Self {
|
||||
ccsds_days: unix_to_ccsds_days(unix_days) as u32,
|
||||
ms_of_day,
|
||||
unix_days_seconds: unix_days * SECONDS_PER_DAY as i64,
|
||||
submilis_prec: precision,
|
||||
submillis,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl CdsCommon for ConversionFromUnix {
|
||||
#[inline]
|
||||
fn submillis_precision(&self) -> SubmillisPrecision {
|
||||
self.submilis_prec
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ms_of_day(&self) -> u32 {
|
||||
self.ms_of_day
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ccsds_days_as_u32(&self) -> u32 {
|
||||
self.ccsds_days
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn submillis(&self) -> u32 {
|
||||
self.submillis
|
||||
}
|
||||
}
|
||||
|
||||
impl CdsConverter for ConversionFromUnix {
|
||||
#[inline]
|
||||
fn unix_days_seconds(&self) -> i64 {
|
||||
self.unix_days_seconds
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper struct which generates fields for the CDS time provider from a datetime.
|
||||
#[cfg(feature = "chrono")]
|
||||
struct ConversionFromChronoDatetime {
|
||||
unix_conversion: ConversionFromUnix,
|
||||
submillis_prec: SubmillisPrecision,
|
||||
submillis: u32,
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl CdsCommon for ConversionFromChronoDatetime {
|
||||
#[inline]
|
||||
fn submillis_precision(&self) -> SubmillisPrecision {
|
||||
self.submillis_prec
|
||||
}
|
||||
|
||||
delegate::delegate! {
|
||||
to self.unix_conversion {
|
||||
#[inline]
|
||||
fn ms_of_day(&self) -> u32;
|
||||
#[inline]
|
||||
fn ccsds_days_as_u32(&self) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn submillis(&self) -> u32 {
|
||||
self.submillis
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl CdsConverter for ConversionFromChronoDatetime {
|
||||
delegate::delegate! {to self.unix_conversion {
|
||||
#[inline]
|
||||
fn unix_days_seconds(&self) -> i64;
|
||||
}}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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 unix_days = (unix_seconds - secs_of_day) / SECONDS_PER_DAY as i64;
|
||||
// Imagine the CCSDS epoch time minus 5 seconds: We now have the last day in the year
|
||||
// 1969 (-1 unix days) shortly before midnight (SECONDS_PER_DAY - 5).
|
||||
if secs_of_day < 0 {
|
||||
unix_days -= 1;
|
||||
secs_of_day += SECONDS_PER_DAY as i64
|
||||
}
|
||||
(unix_days, secs_of_day as u32)
|
||||
}
|
||||
|
||||
#[cfg(feature = "chrono")]
|
||||
impl ConversionFromChronoDatetime {
|
||||
fn new(dt: &chrono::DateTime<chrono::Utc>) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
Self::new_generic(dt, SubmillisPrecision::Absent)
|
||||
}
|
||||
|
||||
fn new_with_submillis_us_prec(
|
||||
dt: &chrono::DateTime<chrono::Utc>,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
Self::new_generic(dt, SubmillisPrecision::Microseconds)
|
||||
}
|
||||
|
||||
fn new_with_submillis_ps_prec(
|
||||
dt: &chrono::DateTime<chrono::Utc>,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
Self::new_generic(dt, SubmillisPrecision::Picoseconds)
|
||||
}
|
||||
|
||||
fn new_generic(
|
||||
dt: &chrono::DateTime<chrono::Utc>,
|
||||
prec: SubmillisPrecision,
|
||||
) -> Result<Self, DateBeforeCcsdsEpochError> {
|
||||
// The CDS timestamp does not support timestamps before the CCSDS epoch.
|
||||
if dt.year() < 1958 {
|
||||
return Err(DateBeforeCcsdsEpochError(UnixTime::from(*dt)));
|
||||
}
|
||||
// The contained values in the conversion should be all positive now
|
||||
let unix_conversion =
|
||||
ConversionFromUnix::new(dt.timestamp(), dt.timestamp_subsec_nanos(), prec)?;
|
||||
let mut submillis = 0;
|
||||
match prec {
|
||||
SubmillisPrecision::Microseconds => {
|
||||
submillis = dt.timestamp_subsec_micros() % 1000;
|
||||
}
|
||||
SubmillisPrecision::Picoseconds => {
|
||||
submillis = (dt.timestamp_subsec_nanos() % 10_u32.pow(6)) * 1000;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(Self {
|
||||
unix_conversion,
|
||||
submillis_prec: prec,
|
||||
submillis,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
struct ConversionFromNow {
|
||||
unix_conversion: ConversionFromUnix,
|
||||
submillis_prec: SubmillisPrecision,
|
||||
submillis: u32,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl ConversionFromNow {
|
||||
fn new() -> Result<Self, SystemTimeError> {
|
||||
Self::new_generic(SubmillisPrecision::Absent)
|
||||
}
|
||||
|
||||
fn new_with_submillis_us_prec() -> Result<Self, SystemTimeError> {
|
||||
Self::new_generic(SubmillisPrecision::Microseconds)
|
||||
}
|
||||
|
||||
fn new_with_submillis_ps_prec() -> Result<Self, SystemTimeError> {
|
||||
Self::new_generic(SubmillisPrecision::Picoseconds)
|
||||
}
|
||||
|
||||
fn new_generic(prec: SubmillisPrecision) -> Result<Self, SystemTimeError> {
|
||||
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
||||
let epoch = now.as_secs();
|
||||
// This should always return a value with valid (non-negative) CCSDS days,
|
||||
// so it is okay to unwrap
|
||||
let unix_conversion =
|
||||
ConversionFromUnix::new(epoch as i64, now.subsec_nanos(), prec).unwrap();
|
||||
let mut submillis = 0;
|
||||
|
||||
match prec {
|
||||
SubmillisPrecision::Microseconds => {
|
||||
submillis = now.subsec_micros() % 1000;
|
||||
}
|
||||
SubmillisPrecision::Picoseconds => {
|
||||
submillis = (now.subsec_nanos() % 10_u32.pow(6)) * 1000;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(Self {
|
||||
unix_conversion,
|
||||
submillis_prec: prec,
|
||||
submillis,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl CdsCommon for ConversionFromNow {
|
||||
fn submillis_precision(&self) -> SubmillisPrecision {
|
||||
self.submillis_prec
|
||||
}
|
||||
delegate::delegate! {
|
||||
to self.unix_conversion {
|
||||
fn ms_of_day(&self) -> u32;
|
||||
fn ccsds_days_as_u32(&self) -> u32;
|
||||
}
|
||||
}
|
||||
|
||||
fn submillis(&self) -> u32 {
|
||||
self.submillis
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl CdsConverter for ConversionFromNow {
|
||||
delegate::delegate! {to self.unix_conversion { fn unix_days_seconds(&self) -> i64; }}
|
||||
}
|
||||
|
||||
fn add_for_max_ccsds_days_val<T: ProvidesDaysLength>(
|
||||
time_provider: &CdsTime<T>,
|
||||
max_days_val: u32,
|
||||
duration: Duration,
|
||||
) -> (u32, u32, u32) {
|
||||
let mut next_ccsds_days = time_provider.ccsds_days_as_u32();
|
||||
let mut next_ms_of_day = time_provider.ms_of_day;
|
||||
// Increment CCSDS days by a certain amount while also accounting for overflow.
|
||||
let increment_days = |ccsds_days: &mut u32, days_inc: u32| {
|
||||
let days_addition: u64 = *ccsds_days as u64 + days_inc as u64;
|
||||
if days_addition > max_days_val as u64 {
|
||||
*ccsds_days = (days_addition - max_days_val as u64) as u32;
|
||||
} else {
|
||||
*ccsds_days += days_inc;
|
||||
}
|
||||
};
|
||||
// Increment MS of day by a certain amount while also accounting for overflow, where
|
||||
// the new value exceeds the MS of a day.
|
||||
let increment_ms_of_day = |ms_of_day: &mut u32, ms_inc: u32, ccsds_days: &mut u32| {
|
||||
*ms_of_day += ms_inc;
|
||||
if *ms_of_day >= MS_PER_DAY {
|
||||
*ms_of_day -= MS_PER_DAY;
|
||||
// Re-use existing closure to always amount for overflow.
|
||||
increment_days(ccsds_days, 1);
|
||||
}
|
||||
};
|
||||
let mut submillis = time_provider.submillis();
|
||||
match time_provider.submillis_precision() {
|
||||
SubmillisPrecision::Microseconds => {
|
||||
let subsec_micros = duration.subsec_micros();
|
||||
let subsec_millis = subsec_micros / 1000;
|
||||
let submilli_micros = subsec_micros % 1000;
|
||||
submillis += submilli_micros;
|
||||
if submillis >= 1000 {
|
||||
let carryover_us = submillis - 1000;
|
||||
increment_ms_of_day(&mut next_ms_of_day, 1, &mut next_ccsds_days);
|
||||
submillis = carryover_us;
|
||||
}
|
||||
increment_ms_of_day(&mut next_ms_of_day, subsec_millis, &mut next_ccsds_days);
|
||||
}
|
||||
SubmillisPrecision::Picoseconds => {
|
||||
let subsec_nanos = duration.subsec_nanos();
|
||||
let subsec_millis = subsec_nanos / 10_u32.pow(6);
|
||||
// 1 ms as ns is 1e6.
|
||||
let submilli_nanos = subsec_nanos % 10_u32.pow(6);
|
||||
// No overflow risk: The maximum value of an u32 is ~4.294e9, and one ms as ps
|
||||
// is 1e9. The amount ps can now have is always less than 2e9.
|
||||
submillis += submilli_nanos * 1000;
|
||||
if submillis >= 10_u32.pow(9) {
|
||||
let carry_over_ps = submillis - 10_u32.pow(9);
|
||||
increment_ms_of_day(&mut next_ms_of_day, 1, &mut next_ccsds_days);
|
||||
submillis = carry_over_ps;
|
||||
}
|
||||
increment_ms_of_day(&mut next_ms_of_day, subsec_millis, &mut next_ccsds_days);
|
||||
}
|
||||
_ => {
|
||||
increment_ms_of_day(
|
||||
&mut next_ms_of_day,
|
||||
duration.subsec_millis(),
|
||||
&mut next_ccsds_days,
|
||||
);
|
||||
}
|
||||
}
|
||||
// The subsecond millisecond were already handled.
|
||||
let full_seconds = duration.as_secs();
|
||||
let secs_of_day = (full_seconds % SECONDS_PER_DAY as u64) as u32;
|
||||
let ms_of_day = secs_of_day * 1000;
|
||||
increment_ms_of_day(&mut next_ms_of_day, ms_of_day, &mut next_ccsds_days);
|
||||
increment_days(
|
||||
&mut next_ccsds_days,
|
||||
(full_seconds as u32 - secs_of_day) / SECONDS_PER_DAY,
|
||||
);
|
||||
(next_ccsds_days, next_ms_of_day, submillis)
|
||||
}
|
||||
|
||||
impl CdsTimestamp for CdsTime<DaysLen16Bits> {
|
||||
fn len_of_day_seg(&self) -> LengthOfDaySegment {
|
||||
LengthOfDaySegment::Short16Bits
|
||||
}
|
||||
}
|
||||
|
||||
impl CdsTimestamp for CdsTime<DaysLen24Bits> {
|
||||
fn len_of_day_seg(&self) -> LengthOfDaySegment {
|
||||
LengthOfDaySegment::Long24Bits
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user