use crate::dma::desc::Descriptor;
use super::{Subseconds, NANOS_PER_SECOND};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Timestamp(i64);
#[cfg(feature = "defmt")]
impl defmt::Format for Timestamp {
fn format(&self, fmt: defmt::Formatter) {
if self.is_positive() {
defmt::write!(fmt, "{}.{:09}", self.seconds(), self.nanos());
} else {
defmt::write!(fmt, "-{}.{:09}", self.seconds(), self.nanos());
}
}
}
impl Timestamp {
const SIGN_BIT: u32 = 0x8000_0000;
pub const fn new(negative: bool, seconds: u32, subseconds: Subseconds) -> Self {
Self::new_unchecked(negative, seconds, subseconds.raw())
}
pub const fn new_raw(value: i64) -> Self {
Self(value)
}
pub const fn raw(&self) -> i64 {
self.0
}
pub const fn is_negative(&self) -> bool {
self.0.is_negative()
}
pub const fn is_positive(&self) -> bool {
!self.is_negative()
}
pub(crate) const fn new_unchecked(negative: bool, seconds: u32, subseconds: u32) -> Self {
let seconds: i64 = (seconds as i64) << 31;
let subseconds: i64 = subseconds as i64;
let mut total = seconds + subseconds;
if negative {
total = -total;
};
Self(total)
}
pub const fn seconds(&self) -> u32 {
(self.0.abs() >> 31) as u32
}
pub const fn subseconds(&self) -> Subseconds {
Subseconds::new_unchecked(self.0.abs() as u32 & Subseconds::MAX_VALUE)
}
pub const fn subseconds_signed(&self) -> u32 {
let mut subseconds = self.subseconds().raw();
if self.0.is_negative() {
subseconds |= Self::SIGN_BIT;
}
subseconds
}
pub const fn nanos(&self) -> u32 {
self.subseconds().nanos()
}
pub const fn total_nanos(&self) -> i64 {
let nanos = self.seconds() as i64 * NANOS_PER_SECOND as i64 + self.nanos() as i64;
if self.is_positive() {
nanos
} else {
-nanos
}
}
pub const fn from_parts(high: u32, low: u32) -> Timestamp {
let negative = (low & Self::SIGN_BIT) == Self::SIGN_BIT;
let subseconds = low & !(Self::SIGN_BIT);
Timestamp::new_unchecked(negative, high, subseconds)
}
pub fn from_descriptor(desc: &Descriptor) -> Option<Self> {
#[cfg(not(feature = "stm32f1xx-hal"))]
{
let (high, low) = { (desc.read(7), desc.read(6)) };
Some(Self::from_parts(high, low))
}
#[cfg(feature = "stm32f1xx-hal")]
{
let (high, low) = { (desc.read(3), desc.read(2)) };
if high == 0xFFFF_FFFF && low == 0xFFFF_FFFF {
None
} else {
Some(Self::from_parts(high, low))
}
}
}
}
impl core::ops::Add<Timestamp> for Timestamp {
type Output = Self;
fn add(self, rhs: Timestamp) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl core::ops::AddAssign<Timestamp> for Timestamp {
fn add_assign(&mut self, rhs: Timestamp) {
self.0 += rhs.0;
}
}
impl core::ops::Sub<Timestamp> for Timestamp {
type Output = Self;
fn sub(self, rhs: Timestamp) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl core::ops::SubAssign<Timestamp> for Timestamp {
fn sub_assign(&mut self, rhs: Timestamp) {
self.0 -= rhs.0
}
}
#[cfg(all(test, not(target_os = "none")))]
mod test {
use crate::ptp::SUBSECONDS_PER_SECOND;
use super::{Subseconds, Timestamp};
fn subs(val: u32) -> Subseconds {
Subseconds::new(val).unwrap()
}
#[test]
fn timestamp_add() {
let one = Timestamp::new(false, 1, subs(1));
let one_big = Timestamp::new(false, 1, subs(SUBSECONDS_PER_SECOND - 1));
let two = Timestamp::new(false, 2, subs(2));
let three = Timestamp::new(false, 3, subs(3));
let one_neg = Timestamp::new(true, 1, subs(1));
let one_big_neg = Timestamp::new(true, 1, subs(SUBSECONDS_PER_SECOND - 1));
let two_neg = Timestamp::new(true, 2, subs(2));
let three_neg = Timestamp::new(true, 3, subs(3));
let one_minus_two = Timestamp::new(true, 1, subs(1));
let one_big_plus_two = Timestamp::new(false, 4, subs(0));
let two_minus_one_big = Timestamp::new(false, 0, subs(4));
let one_big_neg_plus_two_neg = Timestamp::new(true, 4, subs(0));
assert_eq!(one + two, three);
assert_eq!(two + one, three);
assert_eq!(one_big + two, one_big_plus_two);
assert_eq!(two + one_big, one_big_plus_two);
assert_eq!(one + two_neg, one_minus_two);
assert_eq!(two + one_big_neg, two_minus_one_big);
assert_eq!(one_neg + two, one);
assert_eq!(two + one_neg, one);
assert_eq!(one_neg + two_neg, three_neg);
assert_eq!(two_neg + one_neg, three_neg);
assert_eq!(one_big_neg + two_neg, one_big_neg_plus_two_neg);
assert_eq!(two_neg + one_big_neg, one_big_neg_plus_two_neg);
}
#[test]
fn timestamp_sub() {
let one = Timestamp::new(false, 1, subs(1));
let one_big = Timestamp::new(false, 1, subs(SUBSECONDS_PER_SECOND - 1));
let two = Timestamp::new(false, 2, subs(2));
let three = Timestamp::new(false, 3, subs(3));
let one_neg = Timestamp::new(true, 1, subs(1));
let two_neg = Timestamp::new(true, 2, subs(2));
let three_neg = Timestamp::new(true, 3, subs(3));
let one_minus_two = Timestamp::new(true, 1, subs(1));
let one_minus_one_big = Timestamp::new(true, 0, subs(SUBSECONDS_PER_SECOND - 2));
assert_eq!(one - one_big, one_minus_one_big);
assert_eq!(two - one, one);
assert_eq!(one - two, one_minus_two);
assert_eq!(two - one_neg, three);
assert_eq!(one_neg - two, three_neg);
assert_eq!(one_neg - two, three_neg);
assert_eq!(two - one_neg, three);
assert_eq!(one_neg - two_neg, one);
assert_eq!(two_neg - one_neg, one_minus_two);
}
}