ptp.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
3  *
4  * This file is subject to the terms and conditions of the GNU Lesser
5  * General Public License v2.1. See the file LICENSE in the top level
6  * directory for more details.
7  */
8 
9 #pragma once
10 
58 #include <stdint.h>
59 
60 #include "periph_cpu.h"
61 #include "timex.h"
62 
63 #ifdef __cplusplus
64 extern "C" {
65 #endif
66 
67 /* verify settings from periph_cpu.h */
68 #if !defined(HAVE_PTP_CLOCK_READ) && !defined(HAVE_PTP_CLOCK_READ_U64)
69 #error "Neither ptp_clock_read() nor ptp_clock_read_u64() implemented"
70 #endif
71 
72 #if !defined(HAVE_PTP_CLOCK_SET) && !defined(HAVE_PTP_CLOCK_SET_U64)
73 #error "Neither ptp_clock_set() nor ptp_clock_set_u64() implemented"
74 #endif
75 
76 #if \
77  !defined(HAVE_PTP_TIMER_SET_ABSOLUTE) && \
78  !defined(HAVE_PTP_TIMER_SET_ABSOLUTE_U64) && \
79  IS_USED(MODULE_PERIPH_PTP_TIMER)
80 #error "Neither ptp_timer_set_absolute() nor ptp_timer_set_absolute_u64() implemented"
81 #endif
82 
92 typedef uint32_t ptp_seconds_t;
93 
102 typedef struct {
104  uint32_t nanoseconds;
106 
117 static inline int ptp_cmp(const ptp_timestamp_t *a, const ptp_timestamp_t *b)
118 {
119  if (a->seconds < b->seconds) {
120  return -1;
121  }
122 
123  if (a->seconds > b->seconds) {
124  return 1;
125  }
126 
127  if (a->nanoseconds < b->nanoseconds) {
128  return -1;
129  }
130 
131  if (a->nanoseconds > b->nanoseconds) {
132  return 1;
133  }
134 
135  return 0;
136 }
137 
144 static inline void ptp_add(ptp_timestamp_t *t, int64_t offset)
145 {
146  /* Modulo for negative numbers should be avoided */
147  if (offset >= 0) {
148  uint64_t abs_offset = offset;
149  t->seconds += abs_offset / NS_PER_SEC;
150  t->nanoseconds += abs_offset % NS_PER_SEC;
151  /* correct overflow of nanosecond part */
152  if (t->nanoseconds >= NS_PER_SEC) {
153  t->nanoseconds -= NS_PER_SEC;
154  t->seconds++;
155  }
156  }
157  else {
158  uint64_t abs_offset = -offset;
159  t->seconds -= abs_offset / NS_PER_SEC;
160  t->nanoseconds -= abs_offset % NS_PER_SEC;
161  /* correct underflow of nanosecond part */
162  if (t->nanoseconds > NS_PER_SEC) {
163  t->nanoseconds += NS_PER_SEC;
164  t->seconds--;
165  }
166  }
167 }
168 
175 static inline void ptp_ns2ts(ptp_timestamp_t *dest, uint64_t ns_since_epoch)
176 {
177  dest->seconds = ns_since_epoch / NS_PER_SEC;
178  dest->nanoseconds = ns_since_epoch % NS_PER_SEC;
179 }
180 
188 static inline uint64_t ptp_ts2ns(const ptp_timestamp_t *t)
189 {
190  return t->seconds * NS_PER_SEC + t->nanoseconds;
191 }
192 
204 void ptp_init(void);
205 
229 void ptp_clock_adjust_speed(int32_t correction);
230 
240 void ptp_clock_adjust(int64_t offset);
241 
242 #if defined(HAVE_PTP_CLOCK_READ) || defined(DOXYGEN)
249 void ptp_clock_read(ptp_timestamp_t *timestamp);
250 #endif /* HAVE_PTP_CLOCK_READ */
251 
252 #if defined(HAVE_PTP_CLOCK_READ_U64) || defined(DOXYGEN)
263 uint64_t ptp_clock_read_u64(void);
264 #endif /* HAVE_PTP_CLOCK_READ_U64 */
265 
266 #if defined(HAVE_PTP_CLOCK_SET) || defined(DOXYGEN)
274 void ptp_clock_set(const ptp_timestamp_t *time);
275 #endif /* HAVE_PTP_CLOCK_SET */
276 
277 #if defined(HAVE_PTP_CLOCK_SET_U64) || defined(DOXYGEN)
285 void ptp_clock_set_u64(uint64_t ns_since_epoch);
286 #endif /* HAVE_PTP_CLOCK_SET_U64 */
287 
298 void ptp_timer_cb(void);
299 
300 #if defined(HAVE_PTP_TIMER_SET_ABSOLUTE) || defined(DOXYGEN)
313 void ptp_timer_set_absolute(const ptp_timestamp_t *target);
314 #endif /* HAVE_PTP_TIMER_SET_ABSOLUTE */
315 
316 #if defined(HAVE_PTP_TIMER_SET_ABSOLUTE_U64) || defined(DOXYGEN)
329 void ptp_timer_set_absolute_u64(uint64_t target);
330 #endif /* HAVE_PTP_TIMER_SET_ABSOLUTE_U64 */
331 
341 void ptp_timer_set_u64(uint64_t target);
342 
348 void ptp_timer_clear(void);
349 
350 /* Fallback implementations (the driver can implement either the
351  * functions using `ptp_timestamp_t` or `uint64_t`, the other flavor will
352  * be provided on top here): */
353 
354 #ifndef HAVE_PTP_CLOCK_READ
355 static inline void ptp_clock_read(struct ptp_timestamp_t *timestamp)
356 {
357  ptp_ns2ts(timestamp, ptp_clock_read_u64());
358 }
359 #endif /* !HAVE_PTP_CLOCK_READ */
360 
361 #ifndef HAVE_PTP_CLOCK_READ_U64
362 static inline uint64_t ptp_clock_read_u64(void)
363 {
364  ptp_timestamp_t ts;
365  ptp_clock_read(&ts);
366  return ptp_ts2ns(&ts);
367 }
368 #endif /* !HAVE_PTP_CLOCK_READ_U64 */
369 
370 #ifndef HAVE_PTP_CLOCK_SET
371 static inline void ptp_clock_set(const ptp_timestamp_t *time)
372 {
374 }
375 #endif /* !HAVE_PTP_CLOCK_SET */
376 
377 #ifndef HAVE_PTP_CLOCK_SET_U64
378 static inline void ptp_clock_set_u64(uint64_t ns_since_epoch)
379 {
380  ptp_timestamp_t time;
381  ptp_ns2ts(&time, ns_since_epoch);
382  ptp_clock_set(&time);
383 }
384 #endif /* !HAVE_PTP_CLOCK_SET_U64 */
385 
386 #ifndef HAVE_PTP_TIMER_SET_ABSOLUTE
387 static inline void ptp_timer_set_absolute(const ptp_timestamp_t *target)
388 {
390 }
391 #endif /* !HAVE_PTP_TIMER_SET_ABSOLUTE */
392 
393 #ifndef HAVE_PTP_TIMER_SET_ABSOLUTE_U64
394 static inline void ptp_timer_set_absolute_u64(uint64_t target)
395 {
396  ptp_timestamp_t ts;
397  ptp_ns2ts(&ts, target);
399 }
400 #endif /* !HAVE_PTP_TIMER_SET_ABSOLUTE_U64 */
401 
402 #ifdef __cplusplus
403 }
404 #endif
405 
void ptp_timer_set_u64(uint64_t target)
Set an relative timeout value, possibly overwriting an existing timeout.
static void ptp_add(ptp_timestamp_t *t, int64_t offset)
Add a given offset onto the given timestamp.
Definition: ptp.h:144
static void ptp_ns2ts(ptp_timestamp_t *dest, uint64_t ns_since_epoch)
Convert time from nanoseconds since epoch to ptp_timestamp_t format.
Definition: ptp.h:175
uint32_t ptp_seconds_t
Unsigned integer type to store seconds since epoch for use in PTP.
Definition: ptp.h:92
void ptp_clock_set_u64(uint64_t ns_since_epoch)
Set the current system time in nanosecond since UNIX epoch.
Definition: ptp.h:378
static int ptp_cmp(const ptp_timestamp_t *a, const ptp_timestamp_t *b)
Compare two PTP timestamps.
Definition: ptp.h:117
uint64_t ptp_clock_read_u64(void)
Get the current system time in nanosecond since UNIX epoch.
Definition: ptp.h:362
void ptp_timer_set_absolute_u64(uint64_t target)
Set an absolute timeout value, possibly overwriting an existing timeout.
Definition: ptp.h:394
void ptp_clock_adjust_speed(int32_t correction)
Adjust the PTP clock speed as given.
void ptp_clock_read(ptp_timestamp_t *timestamp)
Get the current system time as PTP timestamp.
Definition: ptp.h:355
void ptp_timer_set_absolute(const ptp_timestamp_t *target)
Set an absolute timeout value, possibly overwriting an existing timeout.
Definition: ptp.h:387
void ptp_clock_set(const ptp_timestamp_t *time)
Set the current system time.
Definition: ptp.h:371
void ptp_timer_cb(void)
External function to call when the PTP clock timer fired.
void ptp_timer_clear(void)
Clears any pending timeout on the PTP timer.
void ptp_clock_adjust(int64_t offset)
Adjust the PTP clock as given.
void ptp_init(void)
Initialize the given PTP peripheral.
static uint64_t ptp_ts2ns(const ptp_timestamp_t *t)
Convert time from nanoseconds since epoch to ptp_timestamp_t format.
Definition: ptp.h:188
#define NS_PER_SEC
The number of nanoseconds per second.
Definition: time_units.h:109
A PTP timestamp in seconds + nanoseconds since UNIX epoch.
Definition: ptp.h:102
uint32_t nanoseconds
Nanoseconds part.
Definition: ptp.h:104
ptp_seconds_t seconds
Seconds since UNIX epoch.
Definition: ptp.h:103
Utility library for comparing and computing timestamps.