Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017 Intel Corporation. |
| 3 | * |
| 4 | * SPDX-License-Identifier: Apache-2.0 |
| 5 | */ |
| 6 | |
| 7 | /** |
| 8 | * @file |
| 9 | * @brief Public functions for the Precision Time Protocol Stack. |
| 10 | * |
| 11 | */ |
| 12 | |
Flavio Ceolin | 67ca176 | 2018-09-14 10:43:44 -0700 | [diff] [blame] | 13 | #ifndef ZEPHYR_INCLUDE_NET_GPTP_H_ |
| 14 | #define ZEPHYR_INCLUDE_NET_GPTP_H_ |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 15 | |
| 16 | /** |
| 17 | * @brief generic Precision Time Protocol (gPTP) support |
| 18 | * @defgroup gptp gPTP support |
| 19 | * @ingroup networking |
| 20 | * @{ |
| 21 | */ |
| 22 | |
| 23 | #include <net/net_core.h> |
| 24 | #include <net/ptp_time.h> |
Flavio Ceolin | 6fdc56d | 2018-09-18 12:32:27 -0700 | [diff] [blame] | 25 | #include <stdbool.h> |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 26 | |
| 27 | #ifdef __cplusplus |
| 28 | extern "C" { |
| 29 | #endif |
| 30 | |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 31 | #define GPTP_OFFSET_SCALED_LOG_VAR_UNKNOWN 0x436A |
| 32 | |
| 33 | #define GPTP_PRIORITY1_NON_GM_CAPABLE 255 |
Tomasz Gorochowik | 68127a3 | 2018-08-29 15:29:46 +0200 | [diff] [blame] | 34 | #define GPTP_PRIORITY1_GM_CAPABLE 248 |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 35 | #define GPTP_PRIORITY2_DEFAULT 248 |
| 36 | |
| 37 | /** |
| 38 | * @brief Scaled Nanoseconds. |
| 39 | */ |
| 40 | struct gptp_scaled_ns { |
| 41 | /** High half. */ |
| 42 | s32_t high; |
| 43 | |
| 44 | /** Low half. */ |
| 45 | s64_t low; |
| 46 | } __packed; |
| 47 | |
| 48 | /** |
| 49 | * @brief UScaled Nanoseconds. |
| 50 | */ |
| 51 | struct gptp_uscaled_ns { |
| 52 | /** High half. */ |
| 53 | u32_t high; |
| 54 | |
| 55 | /** Low half. */ |
| 56 | u64_t low; |
| 57 | } __packed; |
| 58 | |
| 59 | #if defined(CONFIG_NEWLIB_LIBC) |
| 60 | #include <math.h> |
| 61 | |
| 62 | #define GPTP_POW2(exp) pow(2, exp) |
| 63 | #else |
| 64 | |
| 65 | static inline double _gptp_pow2(int exp) |
| 66 | { |
| 67 | double res; |
| 68 | |
| 69 | if (exp >= 0) { |
| 70 | res = 1 << exp; |
| 71 | } else { |
| 72 | res = 1.0; |
| 73 | |
| 74 | while (exp++) { |
| 75 | res /= 2; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | return res; |
| 80 | } |
| 81 | |
| 82 | #define GPTP_POW2(exp) _gptp_pow2(exp) |
| 83 | #endif |
| 84 | |
| 85 | /* Message types. Event messages have BIT(3) set to 0, and general messages |
| 86 | * have that bit set to 1. IEEE 802.1AS chapter 10.5.2.2.2 |
| 87 | */ |
| 88 | #define GPTP_SYNC_MESSAGE 0x00 |
| 89 | #define GPTP_DELAY_REQ_MESSAGE 0x01 |
| 90 | #define GPTP_PATH_DELAY_REQ_MESSAGE 0x02 |
| 91 | #define GPTP_PATH_DELAY_RESP_MESSAGE 0x03 |
| 92 | #define GPTP_FOLLOWUP_MESSAGE 0x08 |
| 93 | #define GPTP_DELAY_RESP_MESSAGE 0x09 |
| 94 | #define GPTP_PATH_DELAY_FOLLOWUP_MESSAGE 0x0a |
| 95 | #define GPTP_ANNOUNCE_MESSAGE 0x0b |
| 96 | #define GPTP_SIGNALING_MESSAGE 0x0c |
| 97 | #define GPTP_MANAGEMENT_MESSAGE 0x0d |
| 98 | |
| 99 | #define GPTP_IS_EVENT_MSG(msg_type) (!((msg_type) & BIT(3))) |
| 100 | |
| 101 | #define GPTP_CLOCK_ID_LEN 8 |
| 102 | |
| 103 | /** |
| 104 | * @brief Port Identity. |
| 105 | */ |
| 106 | struct gptp_port_identity { |
| 107 | /** Clock identity of the port. */ |
| 108 | u8_t clk_id[GPTP_CLOCK_ID_LEN]; |
| 109 | |
| 110 | /** Number of the port. */ |
| 111 | u16_t port_number; |
| 112 | } __packed; |
| 113 | |
| 114 | struct gptp_flags { |
| 115 | union { |
| 116 | /** Byte access. */ |
| 117 | u8_t octets[2]; |
| 118 | |
| 119 | /** Whole field access. */ |
| 120 | u16_t all; |
| 121 | }; |
| 122 | } __packed; |
| 123 | |
| 124 | struct gptp_hdr { |
| 125 | /** Type of the message. */ |
| 126 | u8_t message_type:4; |
| 127 | |
| 128 | /** Transport specific, always 1. */ |
| 129 | u8_t transport_specific:4; |
| 130 | |
| 131 | /** Version of the PTP, always 2. */ |
| 132 | u8_t ptp_version:4; |
| 133 | |
| 134 | /** Reserved field. */ |
| 135 | u8_t reserved0:4; |
| 136 | |
| 137 | /** Total length of the message from the header to the last TLV. */ |
| 138 | u16_t message_length; |
| 139 | |
| 140 | /** Domain number, always 0. */ |
| 141 | u8_t domain_number; |
| 142 | |
| 143 | /** Reserved field. */ |
| 144 | u8_t reserved1; |
| 145 | |
| 146 | /** Message flags. */ |
| 147 | struct gptp_flags flags; |
| 148 | |
| 149 | /** Correction Field. The content depends of the message type. */ |
| 150 | s64_t correction_field; |
| 151 | |
| 152 | /** Reserved field. */ |
| 153 | u32_t reserved2; |
| 154 | |
| 155 | /** Port Identity of the sender. */ |
| 156 | struct gptp_port_identity port_id; |
| 157 | |
| 158 | /** Sequence Id. */ |
| 159 | u16_t sequence_id; |
| 160 | |
| 161 | /** Control value. Sync: 0, Follow-up: 2, Others: 5. */ |
| 162 | u8_t control; |
| 163 | |
| 164 | /** Message Interval in Log2 for Sync and Announce messages. */ |
| 165 | s8_t log_msg_interval; |
| 166 | } __packed; |
| 167 | |
Jukka Rissanen | cf272e6 | 2018-04-20 13:58:10 +0300 | [diff] [blame] | 168 | #define GPTP_GET_CURRENT_TIME_USCALED_NS(port, uscaled_ns_ptr) \ |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 169 | do { \ |
| 170 | (uscaled_ns_ptr)->low = \ |
Jukka Rissanen | cf272e6 | 2018-04-20 13:58:10 +0300 | [diff] [blame] | 171 | gptp_get_current_time_nanosecond(port) << 16; \ |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 172 | (uscaled_ns_ptr)->high = 0; \ |
Flavio Ceolin | 6fdc56d | 2018-09-18 12:32:27 -0700 | [diff] [blame] | 173 | } while (false) |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 174 | |
| 175 | /** |
| 176 | * @typedef gptp_phase_dis_callback_t |
| 177 | * @brief Define callback that is called after a phase discontinuity has been |
| 178 | * sent by the grandmaster. |
| 179 | * @param "u8_t *gm_identity" A pointer to first element of a |
| 180 | * ClockIdentity array. The size of the array is GPTP_CLOCK_ID_LEN. |
| 181 | * @param "u16_t *gm_time_base" A pointer to the value of timeBaseIndicator |
| 182 | * of the current grandmaster. |
| 183 | * @param "struct scaled_ns *last_gm_ph_change" A pointer to the value of |
| 184 | * lastGmPhaseChange received from grandmaster. |
| 185 | * @param "double *last_gm_freq_change" A pointer to the value of |
| 186 | * lastGmFreqChange received from the grandmaster. |
| 187 | */ |
| 188 | typedef void (*gptp_phase_dis_callback_t)( |
| 189 | u8_t *gm_identity, |
| 190 | u16_t *time_base, |
| 191 | struct gptp_scaled_ns *last_gm_ph_change, |
| 192 | double *last_gm_freq_change); |
| 193 | |
| 194 | /** |
| 195 | * @brief Phase discontinuity callback structure. |
| 196 | * |
| 197 | * Stores the phase discontinuity callback information. Caller must make sure |
| 198 | * that the variable pointed by this is valid during the lifetime of |
| 199 | * registration. Typically this means that the variable cannot be |
| 200 | * allocated from stack. |
| 201 | */ |
| 202 | struct gptp_phase_dis_cb { |
| 203 | /** Node information for the slist. */ |
| 204 | sys_snode_t node; |
| 205 | |
| 206 | /** Phase discontinuity callback. */ |
| 207 | gptp_phase_dis_callback_t cb; |
| 208 | }; |
| 209 | |
| 210 | /** |
Tomasz Gorochowik | 68127a3 | 2018-08-29 15:29:46 +0200 | [diff] [blame] | 211 | * @brief ClockSourceTime.invoke function parameters |
| 212 | * |
| 213 | * Parameters passed by ClockSourceTime.invoke function. |
| 214 | */ |
| 215 | struct gptp_clk_src_time_invoke_params { |
| 216 | /** Frequency change on the last Time Base Indicator Change. */ |
| 217 | double last_gm_freq_change; |
| 218 | |
| 219 | /** The time this function is invoked. */ |
| 220 | struct net_ptp_extended_time src_time; |
| 221 | |
| 222 | /** Phase change on the last Time Base Indicator Change. */ |
| 223 | struct gptp_scaled_ns last_gm_phase_change; |
| 224 | |
| 225 | /** Time Base - changed only if Phase or Frequency changes. */ |
| 226 | u16_t time_base_indicator; |
| 227 | }; |
| 228 | |
| 229 | /** |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 230 | * @brief Register a phase discontinuity callback. |
| 231 | * |
| 232 | * @param phase_dis Caller specified handler for the callback. |
| 233 | * @param cb Callback to register. |
| 234 | */ |
| 235 | void gptp_register_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis, |
| 236 | gptp_phase_dis_callback_t cb); |
| 237 | |
| 238 | /** |
| 239 | * @brief Unregister a phase discontinuity callback. |
| 240 | * |
| 241 | * @param phase_dis Caller specified handler for the callback. |
| 242 | */ |
| 243 | void gptp_unregister_phase_dis_cb(struct gptp_phase_dis_cb *phase_dis); |
| 244 | |
| 245 | /** |
| 246 | * @brief Call a phase discontinuity callback function. |
| 247 | */ |
| 248 | void gptp_call_phase_dis_cb(void); |
| 249 | |
| 250 | /** |
| 251 | * @brief Get gPTP time. |
| 252 | * |
| 253 | * @param slave_time A pointer to structure where timestamp will be saved. |
| 254 | * @param gm_present A pointer to a boolean where status of the |
| 255 | * presence of a grand master will be saved. |
| 256 | * |
| 257 | * @return Error code. 0 if no error. |
| 258 | */ |
| 259 | int gptp_event_capture(struct net_ptp_time *slave_time, bool *gm_present); |
| 260 | |
| 261 | /** |
| 262 | * @brief Utility function to print clock id to a user supplied buffer. |
| 263 | * |
| 264 | * @param clk_id Clock id |
| 265 | * @param output Output buffer |
| 266 | * @param output_len Output buffer len |
| 267 | * |
| 268 | * @return Pointer to output buffer |
| 269 | */ |
| 270 | char *gptp_sprint_clock_id(const u8_t *clk_id, char *output, |
| 271 | size_t output_len); |
| 272 | |
| 273 | /** |
| 274 | * @typedef gptp_port_cb_t |
| 275 | * @brief Callback used while iterating over gPTP ports |
| 276 | * |
| 277 | * @param port Port number |
| 278 | * @param iface Pointer to network interface |
| 279 | * @param user_data A valid pointer to user data or NULL |
| 280 | */ |
| 281 | typedef void (*gptp_port_cb_t)(int port, struct net_if *iface, |
| 282 | void *user_data); |
| 283 | |
| 284 | /** |
| 285 | * @brief Go through all the gPTP ports and call callback for each of them. |
| 286 | * |
| 287 | * @param cb User-supplied callback function to call |
| 288 | * @param user_data User specified data |
| 289 | */ |
| 290 | void gptp_foreach_port(gptp_port_cb_t cb, void *user_data); |
| 291 | |
| 292 | /** |
| 293 | * @brief Get gPTP domain. |
| 294 | * @details This contains all the configuration / status of the gPTP domain. |
| 295 | * |
| 296 | * @return Pointer to domain or NULL if not found. |
| 297 | */ |
| 298 | struct gptp_domain *gptp_get_domain(void); |
| 299 | |
Tomasz Gorochowik | 68127a3 | 2018-08-29 15:29:46 +0200 | [diff] [blame] | 300 | /** |
| 301 | * @brief This interface is used by the ClockSource entity to provide time to |
| 302 | * the ClockMaster entity of a time-aware system. |
| 303 | * |
| 304 | * @param arg Current state and parameters of the ClockSource entity. |
| 305 | */ |
| 306 | void gptp_clk_src_time_invoke(struct gptp_clk_src_time_invoke_params *arg); |
| 307 | |
Jukka Rissanen | 45b06a2 | 2018-01-24 14:33:35 +0200 | [diff] [blame] | 308 | #ifdef __cplusplus |
| 309 | } |
| 310 | #endif |
| 311 | |
| 312 | /** |
| 313 | * @} |
| 314 | */ |
| 315 | |
Flavio Ceolin | 67ca176 | 2018-09-14 10:43:44 -0700 | [diff] [blame] | 316 | #endif /* ZEPHYR_INCLUDE_NET_GPTP_H_ */ |