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}