File
Blob: firmware/vendor/str0m/src/util/mod.rs
| 1 | use std::time::{Duration, Instant}; |
| 2 | |
| 3 | mod bit_pattern; |
| 4 | |
| 5 | pub(crate) use bit_pattern::BitPattern; |
| 6 | |
| 7 | pub(crate) mod value_history; |
| 8 | |
| 9 | mod time_tricks; |
| 10 | pub(crate) use time_tricks::{InstantExt, SystemTimeExt, not_happening}; |
| 11 | pub(crate) use time_tricks::{already_happened, epoch_to_beginning}; |
| 12 | |
| 13 | mod average; |
| 14 | pub(crate) use average::MovingAverage; |
| 15 | |
| 16 | pub(crate) trait Soonest { |
| 17 | fn soonest(self, other: Self) -> Self; |
| 18 | } |
| 19 | |
| 20 | impl<T: Default> Soonest for (Option<Instant>, T) { |
| 21 | fn soonest(self, other: Self) -> Self { |
| 22 | match (self, other) { |
| 23 | ((Some(v1), s1), (Some(v2), s2)) => { |
| 24 | if v1 < v2 { |
| 25 | (Some(v1), s1) |
| 26 | } else { |
| 27 | (Some(v2), s2) |
| 28 | } |
| 29 | } |
| 30 | ((None, _), (None, _)) => (None, T::default()), |
| 31 | ((None, _), (v, s)) => (v, s), |
| 32 | ((v, s), (None, _)) => (v, s), |
| 33 | } |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | /// Calculate the round trip time for a given peer as described in |
| 38 | /// [RFC3550 6.4.1](https://datatracker.ietf.org/doc/html/rfc3550#section-6.4.1). |
| 39 | /// |
| 40 | /// ## Params |
| 41 | /// - `ntp_time` the offset since 1900-01-01. |
| 42 | /// - `delay` the delay(`DLSR`) since last sender report expressed as fractions of a second in 32 bits. |
| 43 | /// - `last_report` the middle 32 bits of an NTP timestamp for the most recent sender report(LSR) |
| 44 | /// or Receiver Report(LRR). |
| 45 | pub(crate) fn calculate_rtt(ntp_time: Duration, delay: u32, last_report: u32) -> Option<Duration> { |
| 46 | // [10 Nov 1995 11:33:25.125 UTC] [10 Nov 1995 11:33:36.5 UTC] |
| 47 | // n SR(n) A=b710:8000 (46864.500 s) |
| 48 | // ----------------------------------------------------------------> |
| 49 | // v ^ |
| 50 | // ntp_sec =0xb44db705 v ^ dlsr=0x0005:4000 ( 5.250s) |
| 51 | // ntp_frac=0x20000000 v ^ lsr =0xb705:2000 (46853.125s) |
| 52 | // (3024992005.125 s) v ^ |
| 53 | // r v ^ RR(n) |
| 54 | // ----------------------------------------------------------------> |
| 55 | // |<-DLSR->| |
| 56 | // (5.250 s) |
| 57 | // |
| 58 | // A 0xb710:8000 (46864.500 s) |
| 59 | // DLSR -0x0005:4000 ( 5.250 s) |
| 60 | // LSR -0xb705:2000 (46853.125 s) |
| 61 | // ------------------------------- |
| 62 | // delay 0x0006:2000 ( 6.125 s) |
| 63 | |
| 64 | // - we want the current middle 32 bits of an NTP timestamp for the current time. |
| 65 | // We treat the seconds separately to the fractions. |
| 66 | // [32 bit seconds].[32 bit fractions] |
| 67 | // [16 bit].[16 bit] |
| 68 | |
| 69 | // As per RFC delay is 0 in case no SR packet has been received yet. |
| 70 | if delay == 0 { |
| 71 | return None; |
| 72 | } |
| 73 | |
| 74 | let now_secs = ntp_time.as_secs(); |
| 75 | let now_fract_ns = ntp_time.subsec_nanos() as u64; |
| 76 | let now_fract = ((now_fract_ns * u32::MAX as u64) / 1_000_000_000) as u32; |
| 77 | |
| 78 | // Combine the final 2x16 bits together. |
| 79 | let now = (now_secs as u32) << 16 | (now_fract >> 16); |
| 80 | |
| 81 | let rtt = now.checked_sub(delay)?.checked_sub(last_report)?; |
| 82 | let rtt_seconds = rtt >> 16; |
| 83 | let rtt_fraction = (rtt & (u16::MAX as u32)) as f32 / (u16::MAX as u32) as f32; |
| 84 | |
| 85 | let nanos = (rtt_fraction * 1_000_000_000.0) as u32; |
| 86 | Some(Duration::new(rtt_seconds as u64, nanos)) |
| 87 | } |