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 
56 #ifndef PERIPH_PTP_H
57 #define PERIPH_PTP_H
58 
59 #include <stdint.h>
60 
61 #include "periph_cpu.h"
62 #include "timex.h"
63 
64 #ifdef __cplusplus
65 extern "C" {
66 #endif
67 
68 /* verify settings from periph_cpu.h */
69 #if !defined(HAVE_PTP_CLOCK_READ) && !defined(HAVE_PTP_CLOCK_READ_U64)
70 #error "Neither ptp_clock_read() nor ptp_clock_read_u64() implemented"
71 #endif
72 
73 #if !defined(HAVE_PTP_CLOCK_SET) && !defined(HAVE_PTP_CLOCK_SET_U64)
74 #error "Neither ptp_clock_set() nor ptp_clock_set_u64() implemented"
75 #endif
76 
77 #if \
78  !defined(HAVE_PTP_TIMER_SET_ABSOLUTE) && \
79  !defined(HAVE_PTP_TIMER_SET_ABSOLUTE_U64) && \
80  IS_USED(MODULE_PERIPH_PTP_TIMER)
81 #error "Neither ptp_timer_set_absolute() nor ptp_timer_set_absolute_u64() implemented"
82 #endif
83 
93 typedef uint32_t ptp_seconds_t;
94 
103 typedef struct {
105  uint32_t nanoseconds;
107 
118 static inline int ptp_cmp(const ptp_timestamp_t *a, const ptp_timestamp_t *b)
119 {
120  if (a->seconds < b->seconds) {
121  return -1;
122  }
123 
124  if (a->seconds > b->seconds) {
125  return 1;
126  }
127 
128  if (a->nanoseconds < b->nanoseconds) {
129  return -1;
130  }
131 
132  if (a->nanoseconds > b->nanoseconds) {
133  return 1;
134  }
135 
136  return 0;
137 }
138 
145 static inline void ptp_add(ptp_timestamp_t *t, int64_t offset)
146 {
147  /* Modulo for negative numbers should be avoided */
148  if (offset >= 0) {
149  uint64_t abs_offset = offset;
150  t->seconds += abs_offset / NS_PER_SEC;
151  t->nanoseconds += abs_offset % NS_PER_SEC;
152  /* correct overflow of nanosecond part */
153  if (t->nanoseconds >= NS_PER_SEC) {
154  t->nanoseconds -= NS_PER_SEC;
155  t->seconds++;
156  }
157  }
158  else {
159  uint64_t abs_offset = -offset;
160  t->seconds -= abs_offset / NS_PER_SEC;
161  t->nanoseconds -= abs_offset % NS_PER_SEC;
162  /* correct underflow of nanosecond part */
163  if (t->nanoseconds > NS_PER_SEC) {
164  t->nanoseconds += NS_PER_SEC;
165  t->seconds--;
166  }
167  }
168 }
169 
176 static inline void ptp_ns2ts(ptp_timestamp_t *dest, uint64_t ns_since_epoch)
177 {
178  dest->seconds = ns_since_epoch / NS_PER_SEC;
179  dest->nanoseconds = ns_since_epoch % NS_PER_SEC;
180 }
181 
189 static inline uint64_t ptp_ts2ns(const ptp_timestamp_t *t)
190 {
191  return t->seconds * NS_PER_SEC + t->nanoseconds;
192 }
193 
205 void ptp_init(void);
206 
230 void ptp_clock_adjust_speed(int32_t correction);
231 
241 void ptp_clock_adjust(int64_t offset);
242 
243 #if defined(HAVE_PTP_CLOCK_READ) || defined(DOXYGEN)
250 void ptp_clock_read(ptp_timestamp_t *timestamp);
251 #endif /* HAVE_PTP_CLOCK_READ */
252 
253 #if defined(HAVE_PTP_CLOCK_READ_U64) || defined(DOXYGEN)
264 uint64_t ptp_clock_read_u64(void);
265 #endif /* HAVE_PTP_CLOCK_READ_U64 */
266 
267 #if defined(HAVE_PTP_CLOCK_SET) || defined(DOXYGEN)
275 void ptp_clock_set(const ptp_timestamp_t *time);
276 #endif /* HAVE_PTP_CLOCK_SET */
277 
278 #if defined(HAVE_PTP_CLOCK_SET_U64) || defined(DOXYGEN)
286 void ptp_clock_set_u64(uint64_t ns_since_epoch);
287 #endif /* HAVE_PTP_CLOCK_SET_U64 */
288 
299 void ptp_timer_cb(void);
300 
301 #if defined(HAVE_PTP_TIMER_SET_ABSOLUTE) || defined(DOXYGEN)
314 void ptp_timer_set_absolute(const ptp_timestamp_t *target);
315 #endif /* HAVE_PTP_TIMER_SET_ABSOLUTE */
316 
317 #if defined(HAVE_PTP_TIMER_SET_ABSOLUTE_U64) || defined(DOXYGEN)
330 void ptp_timer_set_absolute_u64(uint64_t target);
331 #endif /* HAVE_PTP_TIMER_SET_ABSOLUTE_U64 */
332 
342 void ptp_timer_set_u64(uint64_t target);
343 
349 void ptp_timer_clear(void);
350 
351 /* Fallback implementations (the driver can implement either the
352  * functions using `ptp_timestamp_t` or `uint64_t`, the other flavor will
353  * be provided on top here): */
354 
355 #ifndef HAVE_PTP_CLOCK_READ
356 static inline void ptp_clock_read(struct ptp_timestamp_t *timestamp)
357 {
358  ptp_ns2ts(timestamp, ptp_clock_read_u64());
359 }
360 #endif /* !HAVE_PTP_CLOCK_READ */
361 
362 #ifndef HAVE_PTP_CLOCK_READ_U64
363 static inline uint64_t ptp_clock_read_u64(void)
364 {
365  ptp_timestamp_t ts;
366  ptp_clock_read(&ts);
367  return ptp_ts2ns(&ts);
368 }
369 #endif /* !HAVE_PTP_CLOCK_READ_U64 */
370 
371 #ifndef HAVE_PTP_CLOCK_SET
372 static inline void ptp_clock_set(const ptp_timestamp_t *time)
373 {
375 }
376 #endif /* !HAVE_PTP_CLOCK_SET */
377 
378 #ifndef HAVE_PTP_CLOCK_SET_U64
379 static inline void ptp_clock_set_u64(uint64_t ns_since_epoch)
380 {
381  ptp_timestamp_t time;
382  ptp_ns2ts(&time, ns_since_epoch);
383  ptp_clock_set(&time);
384 }
385 #endif /* !HAVE_PTP_CLOCK_SET_U64 */
386 
387 #ifndef HAVE_PTP_TIMER_SET_ABSOLUTE
388 static inline void ptp_timer_set_absolute(const ptp_timestamp_t *target)
389 {
391 }
392 #endif /* !HAVE_PTP_TIMER_SET_ABSOLUTE */
393 
394 #ifndef HAVE_PTP_TIMER_SET_ABSOLUTE_U64
395 static inline void ptp_timer_set_absolute_u64(uint64_t target)
396 {
397  ptp_timestamp_t ts;
398  ptp_ns2ts(&ts, target);
400 }
401 #endif /* !HAVE_PTP_TIMER_SET_ABSOLUTE_U64 */
402 
403 #ifdef __cplusplus
404 }
405 #endif
406 
407 #endif /* PERIPH_PTP_H */
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:145
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:176
uint32_t ptp_seconds_t
Unsigned integer type to store seconds since epoch for use in PTP.
Definition: ptp.h:93
void ptp_clock_set_u64(uint64_t ns_since_epoch)
Set the current system time in nanosecond since UNIX epoch.
Definition: ptp.h:379
static int ptp_cmp(const ptp_timestamp_t *a, const ptp_timestamp_t *b)
Compare two PTP timestamps.
Definition: ptp.h:118
uint64_t ptp_clock_read_u64(void)
Get the current system time in nanosecond since UNIX epoch.
Definition: ptp.h:363
void ptp_timer_set_absolute_u64(uint64_t target)
Set an absolute timeout value, possibly overwriting an existing timeout.
Definition: ptp.h:395
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:356
void ptp_timer_set_absolute(const ptp_timestamp_t *target)
Set an absolute timeout value, possibly overwriting an existing timeout.
Definition: ptp.h:388
void ptp_clock_set(const ptp_timestamp_t *time)
Set the current system time.
Definition: ptp.h:372
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:189
#define NS_PER_SEC
The number of nanoseconds per second.
Definition: time_units.h:110
A PTP timestamp in seconds + nanoseconds since UNIX epoch.
Definition: ptp.h:103
uint32_t nanoseconds
Nanoseconds part.
Definition: ptp.h:105
ptp_seconds_t seconds
Seconds since UNIX epoch.
Definition: ptp.h:104
Utility library for comparing and computing timestamps.