#ifndef _SYS_TIMEPPS_H_
#define _SYS_TIMEPPS_H_
#include <termios.h>
#define PPS_API_VERS_1 1
#define PPS_JAN_1970 2208988800UL
#define PPS_NANOSECOND 1000000000L
#define PPS_FRAC 4294967296.
#define PPS_NORMALIZE(x) \
do { \
if ((x).tv_nsec >= PPS_NANOSECOND) { \
(x).tv_nsec -= PPS_NANOSECOND; \
(x).tv_sec++; \
} else if ((x).tv_nsec < 0) { \
(x).tv_nsec += PPS_NANOSECOND; \
(x).tv_sec--; \
} \
} while (0)
#define PPS_TSPECTONTP(x) \
do { \
double d_temp; \
\
(x).integral += (unsigned int)PPS_JAN_1970; \
d_temp = (x).fractional * PPS_FRAC / PPS_NANOSECOND; \
if (d_temp >= PPS_FRAC) \
(x).integral++; \
(x).fractional = (unsigned int)d_temp; \
} while (0)
#define PPS_CAPTUREASSERT 0x01
#define PPS_CAPTURECLEAR 0x02
#define PPS_CAPTUREBOTH 0x03
#define PPS_OFFSETASSERT 0x10
#define PPS_OFFSETCLEAR 0x20
#define PPS_OFFSETBOTH 0x30
#define PPS_CANWAIT 0x100
#define PPS_CANPOLL 0x200
#define PPS_ECHOASSERT 0x40
#define PPS_ECHOCLEAR 0x80
#define PPS_TSFMT_TSPEC 0x1000
#define PPS_TSFMT_NTPFP 0x2000
#define PPS_KC_HARDPPS 0
#define PPS_KC_HARDPPS_PLL 1
#define PPS_KC_HARDPPS_FLL 2
typedef unsigned long pps_seq_t;
typedef struct ntp_fp {
unsigned int integral;
unsigned int fractional;
} ntp_fp_t;
typedef union pps_timeu {
struct timespec tspec;
ntp_fp_t ntpfp;
unsigned long longpad[3];
} pps_timeu_t;
typedef struct pps_info {
pps_seq_t assert_sequence;
pps_seq_t clear_sequence;
pps_timeu_t assert_tu;
pps_timeu_t clear_tu;
int current_mode;
} pps_info_t;
#define assert_timestamp assert_tu.tspec
#define clear_timestamp clear_tu.tspec
#define assert_timestamp_ntpfp assert_tu.ntpfp
#define clear_timestamp_ntpfp clear_tu.ntpfp
typedef struct pps_params {
int api_version;
int mode;
pps_timeu_t assert_off_tu;
pps_timeu_t clear_off_tu;
} pps_params_t;
#define assert_offset assert_off_tu.tspec
#define clear_offset clear_off_tu.tspec
#define assert_offset_ntpfp assert_off_tu.ntpfp
#define clear_offset_ntpfp clear_off_tu.ntpfp
#define NTPFP_M_ADD(r_i, r_f, a_i, a_f) \
do { \
register u_int32 lo_tmp; \
register u_int32 hi_tmp; \
\
lo_tmp = ((r_f) & 0xffff) + ((a_f) & 0xffff); \
hi_tmp = (((r_f) >> 16) & 0xffff) + (((a_f) >> 16) & 0xffff); \
if (lo_tmp & 0x10000) \
hi_tmp++; \
(r_f) = ((hi_tmp & 0xffff) << 16) | (lo_tmp & 0xffff); \
\
(r_i) += (a_i); \
if (hi_tmp & 0x10000) \
(r_i)++; \
} while (0)
#define NTPFP_L_ADDS(r, a) NTPFP_M_ADD((r)->integral, (r)->fractional, \
(int)(a)->integral, (a)->fractional)
#define PPS_CAP (PPS_CAPTUREASSERT | PPS_OFFSETASSERT | PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)
#define PPS_RO (PPS_CANWAIT | PPS_CANPOLL)
typedef struct {
int filedes;
pps_params_t params;
} pps_unit_t;
#include <errno.h>
typedef uintptr_t pps_handle_t;
static inline int
time_pps_create(
int filedes,
pps_handle_t *handle
)
{
pps_unit_t *punit;
int one = 1;
if (!handle) {
errno = EFAULT;
return (-1);
}
if (ioctl(filedes, TIOCSPPS, &one) < 0) {
perror("refclock_ioctl: TIOCSPPS failed:");
return (-1);
}
punit = malloc(sizeof(*punit));
if (NULL == punit) {
errno = ENOMEM;
return (-1);
}
memset(punit, 0, sizeof(*punit));
punit->filedes = filedes;
punit->params.api_version = PPS_API_VERS_1;
punit->params.mode = PPS_CAPTUREASSERT | PPS_TSFMT_TSPEC;
*handle = (pps_handle_t)punit;
return (0);
}
static inline int
time_pps_destroy(
pps_handle_t handle
)
{
pps_unit_t *punit;
if (!handle) {
errno = EBADF;
return (-1);
}
punit = (pps_unit_t *)handle;
free(punit);
return (0);
}
static inline int
time_pps_setparams(
pps_handle_t handle,
const pps_params_t *params
)
{
pps_unit_t * punit;
int mode, mode_in;
if (!handle) {
errno = EBADF;
return (-1);
}
if (!params) {
errno = EFAULT;
return (-1);
}
if (params->api_version != PPS_API_VERS_1) {
errno = EINVAL;
return(-1);
}
mode_in = params->mode;
punit = (pps_unit_t *)handle;
if ((mode_in & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) ==
(PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
if (punit->params.assert_offset.tv_sec ||
punit->params.assert_offset.tv_nsec) {
errno = EINVAL;
return(-1);
}
mode_in &= ~PPS_TSFMT_NTPFP;
}
mode_in &= ~PPS_RO;
if (mode_in & ~(PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) {
errno = EOPNOTSUPP;
return(-1);
}
mode = punit->params.mode;
memcpy(&punit->params, params, sizeof(punit->params));
punit->params.api_version = PPS_API_VERS_1;
punit->params.mode = mode | mode_in;
return (0);
}
static inline int
time_pps_getparams(
pps_handle_t handle,
pps_params_t *params
)
{
pps_unit_t * punit;
if (!handle) {
errno = EBADF;
return (-1);
}
if (!params) {
errno = EFAULT;
return (-1);
}
punit = (pps_unit_t *)handle;
memcpy(params, &punit->params, sizeof(params));
return (0);
}
static inline int
time_pps_getcap(
pps_handle_t handle,
int *mode
)
{
if (!handle) {
errno = EBADF;
return (-1);
}
if (!mode) {
errno = EFAULT;
return (-1);
}
*mode = PPS_CAP;
return (0);
}
static inline int
time_pps_fetch(
pps_handle_t handle,
const int tsformat,
pps_info_t *ppsinfo,
const struct timespec *timeout
)
{
struct ppsclockev {
struct timeval tv;
u_int serial;
} ev;
pps_info_t infobuf;
pps_unit_t * punit;
if (!handle) {
errno = EBADF;
return (-1);
}
if (!ppsinfo) {
errno = EFAULT;
return (-1);
}
memset(&infobuf, 0, sizeof(infobuf));
punit = (pps_unit_t *)handle;
if (!punit->params.mode & PPS_CAPTUREASSERT) {
memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
return (0);
}
if (ioctl(punit->filedes, TIOCGPPSEV, (caddr_t) &ev) < 0) {
perror("time_pps_fetch:");
errno = EOPNOTSUPP;
return(-1);
}
infobuf.assert_sequence = ev.serial;
infobuf.assert_timestamp.tv_sec = ev.tv.tv_sec;
infobuf.assert_timestamp.tv_nsec = ev.tv.tv_usec * 1000;
switch (tsformat) {
case PPS_TSFMT_TSPEC:
if (punit->params.mode & PPS_OFFSETASSERT) {
infobuf.assert_timestamp.tv_sec +=
punit->params.assert_offset.tv_sec;
infobuf.assert_timestamp.tv_nsec +=
punit->params.assert_offset.tv_nsec;
PPS_NORMALIZE(infobuf.assert_timestamp);
}
break;
case PPS_TSFMT_NTPFP:
PPS_TSPECTONTP(infobuf.assert_timestamp_ntpfp);
if (punit->params.mode & PPS_OFFSETASSERT)
NTPFP_L_ADDS(&infobuf.assert_timestamp_ntpfp,
&punit->params.assert_offset_ntpfp);
break;
default:
errno = EINVAL;
return (-1);
}
infobuf.current_mode = punit->params.mode;
memcpy(ppsinfo, &infobuf, sizeof(*ppsinfo));
return (0);
}
static inline int
time_pps_kcbind(
pps_handle_t handle,
const int kernel_consumer,
const int edge,
const int tsformat
)
{
if (!handle) {
errno = EBADF;
return (-1);
}
if (geteuid() != 0) {
errno = EPERM;
return (-1);
}
errno = EOPNOTSUPP;
return(-1);
}
#endif