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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// socketcan/src/timestamp.rs
//
// Timestamp types and helpers for SocketCAN sockets.
//
// This file is part of the Rust 'socketcan-rs' library.
//
// Licensed under the MIT license:
// <LICENSE or http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according
// to those terms.
//! Timestamp support for SocketCAN sockets.
//!
//! Timestamps are delivered atomically with the frame data via `recvmsg()`
//! and ancillary control messages, avoiding the two-syscall race of the old
//! `SIOCGSTAMPNS` approach.
//!
//! # Usage
//!
//! 1. Enable the desired timestamp mode on the socket with
//! [`SocketOptions::set_recv_timestamp`] or [`SocketOptions::set_timestamping`].
//! 2. Call the corresponding read method on the socket.
//!
//! [`SocketOptions::set_recv_timestamp`]: crate::SocketOptions::set_recv_timestamp
//! [`SocketOptions::set_timestamping`]: crate::SocketOptions::set_timestamping
use ;
use ;
// --------------------------------------------------------------------------
// SOF_TIMESTAMPING_* flags
//
// The values come from `libc`, which has carried the full set since 0.2.186;
// only the subset this crate documents is named here. They are re-typed from
// `c_uint` to `u32` — the same type on every target Linux supports — to match
// `SocketOptions::set_timestamping()`, and each keeps the note explaining what
// it selects, which the C header does not.
/// Hardware transmit timestamp, generated by the network adapter at packet departure.
pub const SOF_TIMESTAMPING_TX_HARDWARE: u32 = SOF_TIMESTAMPING_TX_HARDWARE;
/// Software transmit timestamp, generated when the packet leaves the network stack.
pub const SOF_TIMESTAMPING_TX_SOFTWARE: u32 = SOF_TIMESTAMPING_TX_SOFTWARE;
/// Hardware receive timestamp.
pub const SOF_TIMESTAMPING_RX_HARDWARE: u32 = SOF_TIMESTAMPING_RX_HARDWARE;
/// Software receive timestamp, generated when the packet enters the network stack.
pub const SOF_TIMESTAMPING_RX_SOFTWARE: u32 = SOF_TIMESTAMPING_RX_SOFTWARE;
/// Report software timestamps in the ancillary data (distinct from `RX_SOFTWARE`,
/// which selects when the timestamp is taken).
pub const SOF_TIMESTAMPING_SOFTWARE: u32 = SOF_TIMESTAMPING_SOFTWARE;
/// Report the raw hardware clock value (not wall-clock time).
pub const SOF_TIMESTAMPING_RAW_HARDWARE: u32 = SOF_TIMESTAMPING_RAW_HARDWARE;
/// Deliver `SO_TIMESTAMPING` timestamps via a control message on receive.
///
/// Required for RX timestamps to actually appear in the ancillary data
/// returned by `recvmsg()`.
pub const SOF_TIMESTAMPING_OPT_CMSG: u32 = SOF_TIMESTAMPING_OPT_CMSG;
// --------------------------------------------------------------------------
// ethtool constants / structs
// TODO: These should be PR'd into libc
pub const ETHTOOL_GET_TS_INFO: u32 = 0x0000_0041;
/// Mirror of `ethtool_ts_info` from `<linux/ethtool.h>`.
pub
// ===== Conversion helpers =====
/// Converts a `libc::timespec` to a `SystemTime`.
///
/// This is what the socket read methods apply to the `timespec` in an
/// `SCM_TIMESTAMPNS` control message, and to the software timestamp in an
/// `SCM_TIMESTAMPING` one. It is public so that code implementing another CAN
/// protocol — J1939 or ISO-TP, on a socket this crate does not open — can
/// reuse it when parsing those same control messages off its own
/// `recvmsg()`.
///
/// The `timespec` is taken to be a non-negative offset from the UNIX epoch,
/// which is what the kernel reports for `CLOCK_REALTIME` socket timestamps.
/// Out-of-range values are clamped the same way
/// [`timespec_to_duration()`] clamps them, so this never panics.
/// Converts a `libc::timespec` to a `Duration`.
///
/// Used for hardware timestamps, which are reported in the adapter's own
/// clock domain rather than as wall-clock time, so a bare `Duration` is the
/// honest type: it is a counter reading, not a point in time. Public for the
/// same reason as [`timespec_to_system_time()`].
///
/// Negative `tv_sec` or `tv_nsec` values — which the kernel should never
/// produce here — are clamped to zero, and `tv_nsec` above one second is
/// clamped down, so the conversion never panics on `Duration::new()`.
/////////////////////////////////////////////////////////////////////////////
/// Timestamps associated with a received CAN frame.
///
/// Each field is `None` when the corresponding timestamp mode was not enabled
/// on the socket before the frame was read.
///
/// Enable socket-layer timestamps with [`SocketOptions::set_recv_timestamp`]
/// and network-stack / hardware timestamps with [`SocketOptions::set_timestamping`].
///
/// # Limitation
///
/// The kernel reports each unrequested timestamp source as all-zero rather
/// than omitting it from the cmsg. This implementation treats an exactly-zero
/// `sw` or `hw` value as "not delivered" and reports it as `None`, which
/// collapses three otherwise-distinct cases: the source was disabled, the
/// kernel returned zero, or (for `hw` only) the adapter's clock genuinely
/// read zero. In practice this is only ambiguous in the first nanosecond
/// after a hardware clock starts up.
///
/// # Filling this in yourself
///
/// The fields are public and the type is `Default`, so code that runs its own
/// `recvmsg()` — for a protocol this crate does not open a socket for — can
/// build one from the control messages it parsed, using
/// [`timespec_to_system_time()`] and [`timespec_to_duration()`] for the
/// conversions.
///
/// [`SocketOptions::set_recv_timestamp`]: crate::SocketOptions::set_recv_timestamp
/// [`SocketOptions::set_timestamping`]: crate::SocketOptions::set_timestamping
/////////////////////////////////////////////////////////////////////////////