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
//! Statime is a library providing an implementation of PTP version 2.1
//! (IEEE1588-2019). It provides all the building blocks to setup PTP ordinary
//! and boundary clocks.
//!
//! `statime` is designed to be able to work with many different underlying
//! platforms, including embedded targets. This does mean that it cannot use the
//! standard library and platform specific libraries to interact with the system
//! clock and to access the network. That needs to be provided by the user of
//! the library.
//!
//! On modern linux kernels, the `statime-linux` crate provides ready to use
//! implementations of these interfaces. For other platforms the user will need
//! to implement these themselves.
//!
//! The `statime-stm32` crate gives an example of how to use `statime` on an
//! embedded target.
//!
//! # Implementing a PTP clock with `statime`
//! Implementing a clock device requires three parts. The [`PtpInstance`]
//! handles the logic for the Best Master Clock Algorithm (BMCA). A
//! [`Port`](`port::Port`) handles the logic for a single network interface of
//! the device. And a [`Clock`] per [`Port`](`port::Port`) that is a struct
//! provided by the user that can read and control a clock device that is
//! associated with a [`Port`](`port::Port`).
//!
//! ## Setup
//! The first step for a new implementation is to gather the configurations
//! needed, these are:
//! * A [`InstanceConfig`](`config::InstanceConfig`) that describes the device
//! * A [`TimePropertiesDS`](`config::TimePropertiesDS`) that describes the
//!   timescale that is used
//! * A [`PortConfig`](`config::PortConfig`) per [`Port`](`port::Port`) to
//!   configure its behavior
//!
//! The [`PtpInstance`] can then be created with [`PtpInstance::new`], providing
//! [`InstanceConfig`](`config::InstanceConfig`) and
//! [`TimePropertiesDS`](`config::TimePropertiesDS`). From that instance
//! [`Port`](`port::Port`)s can be created using [`PtpInstance::add_port`]
//! proviging it [`PortConfig`](`config::PortConfig`), its [`Clock`] and a
//! [`Filter`](`filters::Filter`).
//!
//! ## Running
//! The [`PtpInstance`] expects to execute the BMCA periodically. For this the
//! user must provide a slice containing all ports in the
//! [`InBmca`](`port::InBmca`) state.
//!
//! [`Port`](`port::Port`)s start out in the [`InBmca`](`port::InBmca`) state
//! and can be turned into [`Running`](`port::Running`) mode by calling
//! [`Port::end_bmca`](`port::Port::end_bmca`). And for running the BMCA
//! [`Port::start_bmca`](`port::Port::start_bmca`) turns it back into the
//! [`InBmca`](`port::InBmca`) state.
//!
//! While [`Running`](`port::Running`) a [`Port`](`port::Port`) expects the user
//! to keep track of a few different timers as well as two network sockets. The
//! [`Port`](`port::Port`) is informed about any events via one of the
//! [`Port::handle_*`](`port::Port::handle_send_timestamp`) methods. Actions the
//! [`Port`](`port::Port`) expects to be performed are returned in the form of
//! [`PortAction`](`port::PortAction`)s.
//!
//! # Testing a new implementation
//! A basic option for testing is to run `statime-linux` on your developer
//! machine and connecting your new implementation to a dedicated network port.
//! Now both the time synchronization can be observed e.g. by using a
//! pulse-per-second (PPS) pin. Additionally the protocol excahnge can be
//! observed with a tool like [Wireshark](https://www.wireshark.org/).
//!
//! # Cargo Features
//! This crate exposes two features `std` and `fuzz`. `std` enables a dependency
//! on the Rust standard library providing:
//! * [`std::error::Error`] implementations for error types
//! * Implementations of the [`config::AcceptableMasterList`] trait on types in
//!   [`std`]
//! * Usage of methods on [`f32`] and [`f64`] directly from [`std`] instead of
//!   [`libm`]
//!
//! The `fuzz` feature exposes internal types for fuzzing implementations in the
//! `statime::fuzz` module.

#![no_std]
#![deny(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![warn(rustdoc::unescaped_backticks)]
#[cfg(feature = "std")]
extern crate std;

mod bmc;
mod clock;
pub mod config;
pub(crate) mod datastructures;
pub mod filters;
mod float_polyfill;
pub mod observability;
mod overlay_clock;
pub mod port;
mod ptp_instance;
#[cfg(feature = "std")]
mod shared_clock;
pub mod time;

pub use clock::Clock;
pub use overlay_clock::OverlayClock;
pub use ptp_instance::{PtpInstance, PtpInstanceState, PtpInstanceStateMutex};
#[cfg(feature = "std")]
pub use shared_clock::SharedClock;

/// Helper types used for fuzzing
///
/// Enabled by the `fuzz` `feature`
#[cfg(feature = "fuzz")]
pub mod fuzz {
    pub use crate::datastructures::messages::FuzzMessage;
}