all code review fixes
This commit is contained in:
parent
9cbdd30939
commit
3fc95f0927
@ -39,7 +39,7 @@ pub const MAX_CUC_LEN_SMALL_PREAMBLE: usize = 8;
|
|||||||
pub enum FractionalResolution {
|
pub enum FractionalResolution {
|
||||||
/// No fractional part, only second resolution
|
/// No fractional part, only second resolution
|
||||||
Seconds = 0,
|
Seconds = 0,
|
||||||
/// 256 fractional parts, resulting in 1/255 ~= 4 ms fractional resolution
|
/// 255 fractional parts, resulting in 1/255 ~= 4 ms fractional resolution
|
||||||
FourMs = 1,
|
FourMs = 1,
|
||||||
/// 65535 fractional parts, resulting in 1/65535 ~= 15 us fractional resolution
|
/// 65535 fractional parts, resulting in 1/65535 ~= 15 us fractional resolution
|
||||||
FifteenUs = 2,
|
FifteenUs = 2,
|
||||||
@ -67,12 +67,16 @@ impl TryFrom<u8> for FractionalResolution {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn convert_fractional_part_to_ns(fractional_part: FractionalPart) -> u64 {
|
pub fn convert_fractional_part_to_ns(fractional_part: FractionalPart) -> u64 {
|
||||||
let div = fractional_res_to_div(fractional_part.0);
|
let div = fractional_res_to_div(fractional_part.0);
|
||||||
assert!(fractional_part.1 < div);
|
assert!(fractional_part.1 <= div);
|
||||||
10_u64.pow(9) * fractional_part.1 as u64 / div as u64
|
10_u64.pow(9) * fractional_part.1 as u64 / div as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub const fn fractional_res_to_div(res: FractionalResolution) -> u32 {
|
pub const fn fractional_res_to_div(res: FractionalResolution) -> u32 {
|
||||||
|
// We do not use the full possible range for a given resolution. This is because if we did
|
||||||
|
// that, the largest value would be equal to the counter being incremented by one. Thus, the
|
||||||
|
// smallest allowed fractions value is 0 while the largest allowed fractions value is the
|
||||||
|
// closest fractions value to the next counter increment.
|
||||||
2_u32.pow(8 * res as u32) - 1
|
2_u32.pow(8 * res as u32) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,19 +96,9 @@ pub fn fractional_part_from_subsec_ns(
|
|||||||
panic!("passed nanosecond value larger than 1 second");
|
panic!("passed nanosecond value larger than 1 second");
|
||||||
}
|
}
|
||||||
let resolution = fractional_res_to_div(res) as u64;
|
let resolution = fractional_res_to_div(res) as u64;
|
||||||
// Use integer division because this can reduce code size of really small systems.
|
// This is probably the cheapest way to calculate the fractional part without using expensive
|
||||||
// First determine the nanoseconds for the smallest segment given the resolution.
|
// floating point division.
|
||||||
// Then divide by that to find out the fractional part. For the calculation of the smallest
|
let fractional_part = ns * (resolution + 1) / sec_as_ns;
|
||||||
// fraction, we perform a ceiling division. This is because if we would use the default
|
|
||||||
// flooring division, we would divide by a smaller value, thereby allowing the calculation to
|
|
||||||
// invalid fractional parts which are too large. For the division of the nanoseconds by the
|
|
||||||
// smallest fraction, a flooring division is correct.
|
|
||||||
// The multiplication with 100000 is necessary to avoid precision loss during integer division.
|
|
||||||
// TODO: Floating point division might actually be faster option, but requires additional
|
|
||||||
// code on small embedded systems..
|
|
||||||
let fractional_part = ns * 100000 / ((sec_as_ns * 100000 + resolution) / resolution);
|
|
||||||
// Floating point division.
|
|
||||||
//let fractional_part = (ns as f64 / ((sec_as_ns as f64) / resolution as f64)).floor() as u32;
|
|
||||||
Some(FractionalPart(res, fractional_part as u32))
|
Some(FractionalPart(res, fractional_part as u32))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,16 +288,22 @@ impl CucTime {
|
|||||||
leap_seconds: u32,
|
leap_seconds: u32,
|
||||||
) -> Result<Self, StdTimestampError> {
|
) -> Result<Self, StdTimestampError> {
|
||||||
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
||||||
let ccsds_epoch = unix_epoch_to_ccsds_epoch(now.as_secs() as i64);
|
let mut counter =
|
||||||
ccsds_epoch
|
u32::try_from(unix_epoch_to_ccsds_epoch(now.as_secs() as i64)).map_err(|_| {
|
||||||
.checked_add(i64::from(leap_seconds))
|
TimestampError::Cuc(CucError::InvalidCounter {
|
||||||
|
width: 4,
|
||||||
|
counter: now.as_secs(),
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
counter = counter
|
||||||
|
.checked_add(leap_seconds)
|
||||||
.ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?;
|
.ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?;
|
||||||
if fraction_resolution == FractionalResolution::Seconds {
|
if fraction_resolution == FractionalResolution::Seconds {
|
||||||
return Ok(Self::new(ccsds_epoch as u32));
|
return Ok(Self::new(counter));
|
||||||
}
|
}
|
||||||
let fractions =
|
let fractions =
|
||||||
fractional_part_from_subsec_ns(fraction_resolution, now.subsec_nanos() as u64);
|
fractional_part_from_subsec_ns(fraction_resolution, now.subsec_nanos() as u64);
|
||||||
Self::new_with_fractions(ccsds_epoch as u32, fractions.unwrap())
|
Self::new_with_fractions(counter, fractions.unwrap())
|
||||||
.map_err(|e| StdTimestampError::Timestamp(e.into()))
|
.map_err(|e| StdTimestampError::Timestamp(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +318,8 @@ impl CucTime {
|
|||||||
pub fn update_from_now(&mut self, leap_seconds: u32) -> Result<(), StdTimestampError> {
|
pub fn update_from_now(&mut self, leap_seconds: u32) -> Result<(), StdTimestampError> {
|
||||||
let now = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
|
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 = unix_epoch_to_ccsds_epoch(now.as_secs() as i64) as u32;
|
||||||
self.counter
|
self.counter.1 = self
|
||||||
|
.counter
|
||||||
.1
|
.1
|
||||||
.checked_add(leap_seconds)
|
.checked_add(leap_seconds)
|
||||||
.ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?;
|
.ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?;
|
||||||
@ -360,17 +361,17 @@ impl CucTime {
|
|||||||
res: FractionalResolution,
|
res: FractionalResolution,
|
||||||
leap_seconds: u32,
|
leap_seconds: u32,
|
||||||
) -> Result<Self, TimestampError> {
|
) -> Result<Self, TimestampError> {
|
||||||
let ccsds_epoch = unix_epoch_to_ccsds_epoch(unix_stamp.secs);
|
let mut counter = unix_epoch_to_ccsds_epoch(unix_stamp.secs);
|
||||||
// Negative CCSDS epoch is invalid.
|
// Negative CCSDS epoch is invalid.
|
||||||
if ccsds_epoch < 0 {
|
if counter < 0 {
|
||||||
return Err(TimestampError::DateBeforeCcsdsEpoch(*unix_stamp));
|
return Err(TimestampError::DateBeforeCcsdsEpoch(*unix_stamp));
|
||||||
}
|
}
|
||||||
ccsds_epoch
|
counter = counter
|
||||||
.checked_add(i64::from(leap_seconds))
|
.checked_add(i64::from(leap_seconds))
|
||||||
.ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?;
|
.ok_or(TimestampError::Cuc(CucError::LeapSecondCorrectionError))?;
|
||||||
let fractions =
|
let fractions =
|
||||||
fractional_part_from_subsec_ns(res, unix_stamp.subsec_millis() as u64 * 10_u64.pow(6));
|
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).map_err(|e| e.into())
|
Self::new_generic(WidthCounterPair(4, counter as u32), fractions).map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_u16_counter(counter: u16) -> Self {
|
pub fn new_u16_counter(counter: u16) -> Self {
|
||||||
@ -1194,13 +1195,53 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assert_largest_fractions() {
|
fn test_small_fraction_floored_to_zero() {
|
||||||
|
let fractions =
|
||||||
|
fractional_part_from_subsec_ns(FractionalResolution::SixtyNs, 59)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(fractions.1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_small_fraction_becomes_fractional_part() {
|
||||||
|
let fractions =
|
||||||
|
fractional_part_from_subsec_ns(FractionalResolution::SixtyNs, 61)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(fractions.1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_smallest_resolution_small_nanoseconds_floored_to_zero() {
|
||||||
|
let fractions =
|
||||||
|
fractional_part_from_subsec_ns(FractionalResolution::FourMs, 3800 * 1e3 as u64)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(fractions.1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_smallest_resolution_small_nanoseconds_becomes_one_fraction() {
|
||||||
|
let fractions =
|
||||||
|
fractional_part_from_subsec_ns(FractionalResolution::FourMs, 4000 * 1e3 as u64)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(fractions.1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_smallest_resolution_large_nanoseconds_becomes_largest_fraction() {
|
||||||
|
let fractions =
|
||||||
|
fractional_part_from_subsec_ns(FractionalResolution::FourMs, 10u64.pow(9) - 1)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(fractions.1, 2_u32.pow(8) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_largest_fractions_with_largest_resolution() {
|
||||||
let fractions =
|
let fractions =
|
||||||
fractional_part_from_subsec_ns(FractionalResolution::SixtyNs, 10u64.pow(9) - 1)
|
fractional_part_from_subsec_ns(FractionalResolution::SixtyNs, 10u64.pow(9) - 1)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// The value can not be larger than representable by 3 bytes
|
// The value can not be larger than representable by 3 bytes
|
||||||
// Assert that the maximum resolution can be reached
|
// Assert that the maximum resolution can be reached
|
||||||
assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 2);
|
assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_stamp_after_addition(cuc_stamp: &CucTime) {
|
fn check_stamp_after_addition(cuc_stamp: &CucTime) {
|
||||||
@ -1212,7 +1253,7 @@ mod tests {
|
|||||||
assert_eq!(cuc_stamp.width_counter_pair().1, 202);
|
assert_eq!(cuc_stamp.width_counter_pair().1, 202);
|
||||||
let fractions = cuc_stamp.width_fractions_pair().unwrap().1;
|
let fractions = cuc_stamp.width_fractions_pair().unwrap().1;
|
||||||
let expected_val =
|
let expected_val =
|
||||||
(0.5 * fractional_res_to_div(FractionalResolution::FifteenUs) as f64).floor() as u32;
|
(0.5 * fractional_res_to_div(FractionalResolution::FifteenUs) as f64).ceil() as u32;
|
||||||
assert_eq!(fractions, expected_val);
|
assert_eq!(fractions, expected_val);
|
||||||
let cuc_stamp2 = cuc_stamp + Duration::from_millis(501);
|
let cuc_stamp2 = cuc_stamp + Duration::from_millis(501);
|
||||||
// What I would roughly expect
|
// What I would roughly expect
|
||||||
@ -1300,7 +1341,7 @@ mod tests {
|
|||||||
.expect("failed to create cuc from unix stamp");
|
.expect("failed to create cuc from unix stamp");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cuc.counter(),
|
cuc.counter(),
|
||||||
(-DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32) as u32
|
(-DAYS_CCSDS_TO_UNIX * SECONDS_PER_DAY as i32) as u32 + LEAP_SECONDS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,16 +371,16 @@ impl UnixTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the difference in milliseconds between two UnixTimestamps
|
// Calculate the difference in milliseconds between two UnixTimestamps
|
||||||
pub fn diff_in_millis(&self, other: &UnixTime) -> i64 {
|
pub fn diff_in_millis(&self, other: &UnixTime) -> Option<i64> {
|
||||||
let seconds_difference = self.secs - other.secs;
|
let seconds_difference = self.secs.checked_sub(other.secs)?;
|
||||||
// Convert seconds difference to milliseconds
|
// Convert seconds difference to milliseconds
|
||||||
let milliseconds_difference = seconds_difference * 1000;
|
let milliseconds_difference = seconds_difference.checked_mul(1000)?;
|
||||||
|
|
||||||
// Calculate the difference in subsecond milliseconds directly
|
// Calculate the difference in subsecond milliseconds directly
|
||||||
let subsecond_difference_nanos = self.subsec_nanos as i64 - other.subsec_nanos as i64;
|
let subsecond_difference_nanos = self.subsec_nanos as i64 - other.subsec_nanos as i64;
|
||||||
|
|
||||||
// Combine the differences
|
// Combine the differences
|
||||||
milliseconds_difference + (subsecond_difference_nanos / 1_000_000)
|
Some(milliseconds_difference + (subsecond_difference_nanos / 1_000_000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,11 +447,11 @@ pub struct StampDiff {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Sub for UnixTime {
|
impl Sub for UnixTime {
|
||||||
type Output = StampDiff;
|
type Output = Option<StampDiff>;
|
||||||
|
|
||||||
fn sub(self, rhs: Self) -> Self::Output {
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
let difference = self.diff_in_millis(&rhs);
|
let difference = self.diff_in_millis(&rhs)?;
|
||||||
if difference < 0 {
|
Some(if difference < 0 {
|
||||||
StampDiff {
|
StampDiff {
|
||||||
positive_duration: false,
|
positive_duration: false,
|
||||||
duration_absolute: Duration::from_millis(-difference as u64),
|
duration_absolute: Duration::from_millis(-difference as u64),
|
||||||
@ -461,7 +461,7 @@ impl Sub for UnixTime {
|
|||||||
positive_duration: true,
|
positive_duration: true,
|
||||||
duration_absolute: Duration::from_millis(difference as u64),
|
duration_absolute: Duration::from_millis(difference as u64),
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,7 +690,7 @@ mod tests {
|
|||||||
let StampDiff {
|
let StampDiff {
|
||||||
positive_duration,
|
positive_duration,
|
||||||
duration_absolute,
|
duration_absolute,
|
||||||
} = stamp_later - UnixTime::new(1, 0);
|
} = (stamp_later - UnixTime::new(1, 0)).expect("stamp diff error");
|
||||||
assert!(positive_duration);
|
assert!(positive_duration);
|
||||||
assert_eq!(duration_absolute, Duration::from_secs(1));
|
assert_eq!(duration_absolute, Duration::from_secs(1));
|
||||||
}
|
}
|
||||||
@ -702,7 +702,7 @@ mod tests {
|
|||||||
let StampDiff {
|
let StampDiff {
|
||||||
positive_duration,
|
positive_duration,
|
||||||
duration_absolute,
|
duration_absolute,
|
||||||
} = stamp_later - stamp_earlier;
|
} = (stamp_later - stamp_earlier).expect("stamp diff error");
|
||||||
assert!(positive_duration);
|
assert!(positive_duration);
|
||||||
assert_eq!(duration_absolute, Duration::from_millis(1900));
|
assert_eq!(duration_absolute, Duration::from_millis(1900));
|
||||||
}
|
}
|
||||||
@ -714,7 +714,7 @@ mod tests {
|
|||||||
let StampDiff {
|
let StampDiff {
|
||||||
positive_duration,
|
positive_duration,
|
||||||
duration_absolute,
|
duration_absolute,
|
||||||
} = stamp_earlier - stamp_later;
|
} = (stamp_earlier - stamp_later).expect("stamp diff error");
|
||||||
assert!(!positive_duration);
|
assert!(!positive_duration);
|
||||||
assert_eq!(duration_absolute, Duration::from_millis(1900));
|
assert_eq!(duration_absolute, Duration::from_millis(1900));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user