use crate::message::{ClockQuality, PortIdentity};
use rtime_core::timestamp::NtpDuration;
#[derive(Debug, Clone)]
pub struct DefaultDS {
pub two_step_flag: bool,
pub clock_identity: [u8; 8],
pub number_ports: u16,
pub clock_quality: ClockQuality,
pub priority1: u8,
pub priority2: u8,
pub domain_number: u8,
pub slave_only: bool,
}
impl DefaultDS {
pub fn new(clock_identity: [u8; 8], domain_number: u8) -> Self {
Self {
two_step_flag: true,
clock_identity,
number_ports: 1,
clock_quality: ClockQuality {
clock_class: 248, clock_accuracy: 0xFE, offset_scaled_log_variance: 0xFFFF, },
priority1: 128,
priority2: 128,
domain_number,
slave_only: false,
}
}
pub fn port_identity(&self, port_number: u16) -> PortIdentity {
PortIdentity {
clock_identity: self.clock_identity,
port_number,
}
}
}
#[derive(Debug, Clone)]
pub struct CurrentDS {
pub steps_removed: u16,
pub offset_from_master: NtpDuration,
pub mean_delay: NtpDuration,
}
impl CurrentDS {
pub fn new() -> Self {
Self {
steps_removed: 0,
offset_from_master: NtpDuration::ZERO,
mean_delay: NtpDuration::ZERO,
}
}
pub fn update(&mut self, offset: NtpDuration, delay: NtpDuration) {
self.offset_from_master = offset;
self.mean_delay = delay;
}
}
impl Default for CurrentDS {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ParentDS {
pub parent_port_identity: PortIdentity,
pub parent_stats: bool,
pub observed_parent_offset_scaled_log_variance: u16,
pub observed_parent_clock_phase_change_rate: i32,
pub grandmaster_identity: [u8; 8],
pub grandmaster_clock_quality: ClockQuality,
pub grandmaster_priority1: u8,
pub grandmaster_priority2: u8,
}
impl ParentDS {
pub fn new(default_ds: &DefaultDS) -> Self {
Self {
parent_port_identity: default_ds.port_identity(0),
parent_stats: false,
observed_parent_offset_scaled_log_variance: 0xFFFF,
observed_parent_clock_phase_change_rate: 0,
grandmaster_identity: default_ds.clock_identity,
grandmaster_clock_quality: default_ds.clock_quality,
grandmaster_priority1: default_ds.priority1,
grandmaster_priority2: default_ds.priority2,
}
}
pub fn update_from_announce(
&mut self,
parent_port: PortIdentity,
grandmaster_identity: [u8; 8],
grandmaster_quality: ClockQuality,
grandmaster_priority1: u8,
grandmaster_priority2: u8,
) {
self.parent_port_identity = parent_port;
self.grandmaster_identity = grandmaster_identity;
self.grandmaster_clock_quality = grandmaster_quality;
self.grandmaster_priority1 = grandmaster_priority1;
self.grandmaster_priority2 = grandmaster_priority2;
}
}
#[derive(Debug, Clone)]
pub struct TimePropertiesDS {
pub current_utc_offset: i16,
pub current_utc_offset_valid: bool,
pub leap59: bool,
pub leap61: bool,
pub time_traceable: bool,
pub frequency_traceable: bool,
pub ptp_timescale: bool,
pub time_source: u8,
}
impl TimePropertiesDS {
pub fn new() -> Self {
Self {
current_utc_offset: 37, current_utc_offset_valid: false,
leap59: false,
leap61: false,
time_traceable: false,
frequency_traceable: false,
ptp_timescale: true,
time_source: 0xA0, }
}
}
impl Default for TimePropertiesDS {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_identity() -> [u8; 8] {
[0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77]
}
#[test]
fn default_ds_creation() {
let ds = DefaultDS::new(test_identity(), 0);
assert_eq!(ds.clock_identity, test_identity());
assert_eq!(ds.domain_number, 0);
assert_eq!(ds.priority1, 128);
assert_eq!(ds.priority2, 128);
assert!(ds.two_step_flag);
assert!(!ds.slave_only);
}
#[test]
fn default_ds_port_identity() {
let ds = DefaultDS::new(test_identity(), 0);
let pi = ds.port_identity(1);
assert_eq!(pi.clock_identity, test_identity());
assert_eq!(pi.port_number, 1);
}
#[test]
fn current_ds_update() {
let mut ds = CurrentDS::new();
assert_eq!(ds.offset_from_master, NtpDuration::ZERO);
assert_eq!(ds.mean_delay, NtpDuration::ZERO);
let offset = NtpDuration::from_nanos(500);
let delay = NtpDuration::from_nanos(1000);
ds.update(offset, delay);
assert_eq!(ds.offset_from_master.to_nanos(), 500);
assert_eq!(ds.mean_delay.to_nanos(), 1000);
}
#[test]
fn parent_ds_self_referencing() {
let default_ds = DefaultDS::new(test_identity(), 0);
let parent_ds = ParentDS::new(&default_ds);
assert_eq!(parent_ds.grandmaster_identity, test_identity());
assert_eq!(
parent_ds.parent_port_identity.clock_identity,
test_identity()
);
assert_eq!(parent_ds.grandmaster_priority1, 128);
}
#[test]
fn parent_ds_update_from_announce() {
let default_ds = DefaultDS::new(test_identity(), 0);
let mut parent_ds = ParentDS::new(&default_ds);
let remote_identity = [0xAA; 8];
let remote_port = PortIdentity {
clock_identity: remote_identity,
port_number: 1,
};
let quality = ClockQuality {
clock_class: 6,
clock_accuracy: 0x21,
offset_scaled_log_variance: 0x4E5D,
};
parent_ds.update_from_announce(remote_port, remote_identity, quality, 100, 128);
assert_eq!(parent_ds.grandmaster_identity, remote_identity);
assert_eq!(parent_ds.parent_port_identity, remote_port);
assert_eq!(parent_ds.grandmaster_priority1, 100);
assert_eq!(parent_ds.grandmaster_clock_quality.clock_class, 6);
}
#[test]
fn time_properties_defaults() {
let tp = TimePropertiesDS::new();
assert_eq!(tp.current_utc_offset, 37);
assert!(tp.ptp_timescale);
assert!(!tp.current_utc_offset_valid);
assert_eq!(tp.time_source, 0xA0);
}
}