1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Time-related types based on the DW1000's system time


use core::ops::Add;
use serde::{Serialize, Deserialize};


/// The maximum value of 40-bit system time stamps.
pub const TIME_MAX: u64 = 0xffffffffff;


/// Represents an instant in time
///
/// You can get the current DW1000 system time by calling [`DW1000::sys_time`].
///
/// Internally uses the same 40-bit timestamps that the DW1000 uses.
///
/// [`DW1000::sys_time`]: ../hl/struct.DW1000.html#method.sys_time
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[repr(C)]
pub struct Instant(u64);

impl Instant {
    /// Creates a new instance of `Instant`
    ///
    /// The given value must fit in a 40-bit timestamp, so:
    /// 0 <= `value` <= 2^40 - 1
    ///
    /// Returns `Some(...)`, if `value` is within the valid range, `None` if it
    /// isn't.
    ///
    /// # Example
    ///
    /// ``` rust
    /// use dw1000::time::{
    ///     TIME_MAX,
    ///     Instant,
    /// };
    ///
    /// let valid_instant   = Instant::new(TIME_MAX);
    /// let invalid_instant = Instant::new(TIME_MAX + 1);
    ///
    /// assert!(valid_instant.is_some());
    /// assert!(invalid_instant.is_none());
    /// ```
    pub fn new(value: u64) -> Option<Self> {
        if value <= TIME_MAX {
            Some(Instant(value))
        }
        else {
            None
        }
    }

    /// Returns the raw 40-bit timestamp
    ///
    /// The returned value is guaranteed to be in the following range:
    /// 0 <= `value` <= 2^40 - 1
    pub fn value(&self) -> u64 {
        self.0
    }

    /// Returns the amount of time passed between the two `Instant`s
    ///
    /// Assumes that `&self` represents a later time than the argument
    /// `earlier`. Please make sure that this is the case, as this method has no
    /// way of knowing (DW1000 timestamps can overflow, so comparing the
    /// numerical value of the timestamp doesn't tell anything about order).
    ///
    /// # Example
    ///
    /// ``` rust
    /// use dw1000::time::{
    ///     TIME_MAX,
    ///     Instant,
    /// };
    ///
    /// // `unwrap`ing here is okay, since we're passing constants that we know
    /// // are in the valid range.
    /// let instant_1 = Instant::new(TIME_MAX - 50).unwrap();
    /// let instant_2 = Instant::new(TIME_MAX).unwrap();
    /// let instant_3 = Instant::new(49).unwrap();
    ///
    /// // Works as expected, if the later timestamp is larger than the earlier
    /// // one.
    /// let duration = instant_2.duration_since(instant_1);
    /// assert_eq!(duration.value(), 50);
    ///
    /// // Still works as expected, if the later timestamp is the numerically
    /// // smaller value.
    /// let duration = instant_3.duration_since(instant_2);
    /// assert_eq!(duration.value(), 50);
    /// ```
    pub fn duration_since(&self, earlier: Instant) -> Duration {
        if self.value() >= earlier.value() {
            Duration(self.value() - earlier.value())
        }
        else {
            Duration(TIME_MAX - earlier.value() + self.value() + 1)
        }
    }
}

impl Add<Duration> for Instant {
    type Output = Instant;

    fn add(self, rhs: Duration) -> Self::Output {
        // Both `Instant` and `Duration` are guaranteed to contain 40-bit
        // numbers, so this addition will never overflow.
        let value = (self.value() + rhs.value()) % (TIME_MAX + 1);

        // We made sure to keep the result of the addition within `TIME_MAX`, so
        // the following will never panic.
        Instant::new(value).unwrap()
    }
}


/// A duration between two instants in DW1000 system time
///
/// Internally uses the same 40-bit timestamps that the DW1000 uses.
#[derive(Clone, Copy, Debug, Deserialize, Serialize, Eq, PartialEq)]
#[repr(C)]
pub struct Duration(u64);

impl Duration {
    /// Creates a new instance of `Duration`
    ///
    /// The given value must fit in a 40-bit timestamp, so:
    /// 0 <= `value` <= 2^40 - 1
    ///
    /// Returns `Some(...)`, if `value` is within the valid range, `None` if it
    /// isn't.
    ///
    /// # Example
    ///
    /// ``` rust
    /// use dw1000::time::{
    ///     TIME_MAX,
    ///     Duration,
    /// };
    ///
    /// let valid_duration   = Duration::new(TIME_MAX);
    /// let invalid_duration = Duration::new(TIME_MAX + 1);
    ///
    /// assert!(valid_duration.is_some());
    /// assert!(invalid_duration.is_none());
    /// ```
    pub fn new(value: u64) -> Option<Self> {
        if value <= TIME_MAX {
            Some(Duration(value))
        }
        else {
            None
        }
    }

    /// Creates an instance of `Duration` from a number of nanoseconds
    pub fn from_nanos(nanos: u32) -> Self {
        // `nanos` takes up at most 32 bits before it is cast to `u64`. That
        // means the result of the multiplication fits within 38 bits, so the
        // following should never panic.
        Duration::new(nanos as u64 * 64).unwrap()
    }

    /// Returns the raw 40-bit timestamp
    ///
    /// The returned value is guaranteed to be in the following range:
    /// 0 <= `value` <= 2^40 - 1
    pub fn value(&self) -> u64 {
        self.0
    }
}