statime/port/
actions.rs

1use core::iter::Fuse;
2
3use arrayvec::ArrayVec;
4
5use crate::{
6    datastructures::common::{PortIdentity, Tlv, TlvSetIterator},
7    filters::FilterUpdate,
8};
9
10#[derive(Debug, Clone)]
11/// TLV that needs to be forwarded in the announce messages of other ports.
12pub struct ForwardedTLV<'a> {
13    pub(super) tlv: Tlv<'a>,
14    pub(super) sender_identity: PortIdentity,
15}
16
17impl ForwardedTLV<'_> {
18    /// Wire size of the TLV. Can be used to determine how many TLV's to keep
19    pub fn size(&self) -> usize {
20        self.tlv.wire_size()
21    }
22
23    /// Get an owned version of the struct.
24    #[cfg(feature = "std")]
25    pub fn into_owned(self) -> ForwardedTLV<'static> {
26        ForwardedTLV {
27            tlv: self.tlv.into_owned(),
28            sender_identity: self.sender_identity,
29        }
30    }
31}
32
33/// Source of TLVs that need to be forwarded, provided to announce sender.
34pub trait ForwardedTLVProvider {
35    /// Should provide the next available TLV, unless it is larger than max_size
36    fn next_if_smaller(&mut self, max_size: usize) -> Option<ForwardedTLV>;
37}
38
39/// Simple implementation when
40#[derive(Debug, Copy, Clone)]
41pub struct NoForwardedTLVs;
42
43impl ForwardedTLVProvider for NoForwardedTLVs {
44    fn next_if_smaller(&mut self, _max_size: usize) -> Option<ForwardedTLV> {
45        None
46    }
47}
48
49/// Identification of a packet that should be sent out.
50///
51/// The caller receives this from a [`PortAction::SendEvent`] and should return
52/// it to the [`Port`](`super::Port`) with
53/// [`Port::handle_send_timestamp`](`super::Port::handle_send_timestamp`) once
54/// the transmit timestamp of that packet is known.
55///
56/// This type is non-copy and non-clone on purpose to ensures a single
57/// [`handle_send_timestamp`](`super::Port::handle_send_timestamp`) per
58/// [`SendEvent`](`PortAction::SendEvent`).
59#[derive(Debug)]
60pub struct TimestampContext {
61    pub(super) inner: TimestampContextInner,
62}
63
64#[derive(Debug)]
65pub(super) enum TimestampContextInner {
66    Sync {
67        id: u16,
68    },
69    DelayReq {
70        id: u16,
71    },
72    PDelayReq {
73        id: u16,
74    },
75    PDelayResp {
76        id: u16,
77        requestor_identity: PortIdentity,
78    },
79}
80
81/// An action the [`Port`](`super::Port`) needs the user to perform
82#[derive(Debug)]
83#[must_use]
84#[allow(missing_docs)] // Explaining the fields as well as the variants does not add value
85pub enum PortAction<'a> {
86    /// Send a time-critical packet
87    ///
88    /// Once the packet is sent and the transmit timestamp known the user should
89    /// return the given [`TimestampContext`] using
90    /// [`Port::handle_send_timestamp`](`super::Port::handle_send_timestamp`).
91    ///
92    /// Packets marked as link local should be sent per the instructions
93    /// for sending peer to peer delay mechanism messages of the relevant
94    /// transport specification of PTP.
95    SendEvent {
96        context: TimestampContext,
97        data: &'a [u8],
98        link_local: bool,
99    },
100    /// Send a general packet
101    ///
102    /// For a packet sent this way no timestamp needs to be captured.
103    ///
104    /// Packets marked as link local should be sent per the instructions
105    /// for sending peer to peer delay mechanism messages of the relevant
106    /// transport specification of PTP.
107    SendGeneral { data: &'a [u8], link_local: bool },
108    /// Call [`Port::handle_announce_timer`](`super::Port::handle_announce_timer`) in `duration` from now
109    ResetAnnounceTimer { duration: core::time::Duration },
110    /// Call [`Port::handle_sync_timer`](`super::Port::handle_sync_timer`) in
111    /// `duration` from now
112    ResetSyncTimer { duration: core::time::Duration },
113    /// Call [`Port::handle_delay_request_timer`](`super::Port::handle_delay_request_timer`) in `duration` from now
114    ResetDelayRequestTimer { duration: core::time::Duration },
115    /// Call [`Port::handle_announce_receipt_timer`](`super::Port::handle_announce_receipt_timer`) in `duration` from now
116    ResetAnnounceReceiptTimer { duration: core::time::Duration },
117    /// Call [`Port::handle_filter_update_timer`](`super::Port::handle_filter_update_timer`) in `duration` from now
118    ResetFilterUpdateTimer { duration: core::time::Duration },
119    /// Forward this TLV to the announce timer call of all other ports.
120    /// The receiver must ensure the TLV is yielded only once to the announce
121    /// method of a port.
122    ///
123    /// This can be ignored when implementing a single port or slave only ptp
124    /// instance.
125    ForwardTLV { tlv: ForwardedTLV<'a> },
126}
127
128const MAX_ACTIONS: usize = 2;
129
130/// An Iterator over [`PortAction`]s
131///
132/// These are returned by [`Port`](`super::Port`) when ever the library needs
133/// the user to perform actions to the system.
134///
135/// **Guarantees to end user:** Any set of actions will only ever contain a
136/// single event send
137#[derive(Debug)]
138#[must_use]
139pub struct PortActionIterator<'a> {
140    internal: Fuse<<ArrayVec<PortAction<'a>, MAX_ACTIONS> as IntoIterator>::IntoIter>,
141    tlvs: TlvSetIterator<'a>,
142    sender_identity: PortIdentity,
143}
144
145impl<'a> PortActionIterator<'a> {
146    /// Get an empty Iterator
147    ///
148    /// This can for example be used to have a default value in chained `if`
149    /// statements.
150    pub fn empty() -> Self {
151        Self {
152            internal: ArrayVec::new().into_iter().fuse(),
153            tlvs: TlvSetIterator::empty(),
154            sender_identity: Default::default(),
155        }
156    }
157    pub(super) fn from(list: ArrayVec<PortAction<'a>, MAX_ACTIONS>) -> Self {
158        Self {
159            internal: list.into_iter().fuse(),
160            tlvs: TlvSetIterator::empty(),
161            sender_identity: Default::default(),
162        }
163    }
164    pub(super) fn from_filter(update: FilterUpdate) -> Self {
165        if let Some(duration) = update.next_update {
166            actions![PortAction::ResetFilterUpdateTimer { duration }]
167        } else {
168            actions![]
169        }
170    }
171    pub(super) fn with_forward_tlvs(
172        self,
173        tlvs: TlvSetIterator<'a>,
174        sender_identity: PortIdentity,
175    ) -> Self {
176        Self {
177            internal: self.internal,
178            tlvs,
179            sender_identity,
180        }
181    }
182}
183
184impl<'a> Iterator for PortActionIterator<'a> {
185    type Item = PortAction<'a>;
186
187    fn next(&mut self) -> Option<Self::Item> {
188        self.internal.next().or_else(|| loop {
189            let tlv = self.tlvs.next()?;
190            if tlv.tlv_type.announce_propagate() {
191                return Some(PortAction::ForwardTLV {
192                    tlv: ForwardedTLV {
193                        tlv,
194                        sender_identity: self.sender_identity,
195                    },
196                });
197            }
198        })
199    }
200}