refclock_phc: use sys_linux code for reading PHC

This drops support for non-ioctl reading of PHC.
This commit is contained in:
Miroslav Lichvar 2017-01-19 15:54:01 +01:00
parent b70f0b674f
commit 9df4d36157
4 changed files with 35 additions and 107 deletions

2
configure vendored
View file

@ -732,7 +732,7 @@ fi
if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \ if [ $feat_refclock = "1" ] && [ $feat_phc = "1" ] && [ $try_phc = "1" ] && \
grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \ grep '#define HAVE_CLOCK_GETTIME' config.h > /dev/null && \
test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \ test_code '<linux/ptp_clock.h>' 'sys/ioctl.h linux/ptp_clock.h' '' '' \
'ioctl(1, PTP_CLOCK_GETCAPS, 0);' 'ioctl(1, PTP_CLOCK_GETCAPS + PTP_SYS_OFFSET, 0);'
then then
add_def FEAT_PHC add_def FEAT_PHC
fi fi

View file

@ -505,6 +505,12 @@ RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second)
return 1; return 1;
} }
double
RCL_GetPrecision(RCL_Instance instance)
{
return instance->precision;
}
static int static int
valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked) valid_sample_time(RCL_Instance instance, struct timespec *raw, struct timespec *cooked)
{ {

View file

@ -71,5 +71,6 @@ extern char *RCL_GetDriverParameter(RCL_Instance instance);
extern char *RCL_GetDriverOption(RCL_Instance instance, char *name); extern char *RCL_GetDriverOption(RCL_Instance instance, char *name);
extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap); extern int RCL_AddSample(RCL_Instance instance, struct timespec *sample_time, double offset, int leap);
extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second); extern int RCL_AddPulse(RCL_Instance instance, struct timespec *pulse_time, double second);
extern double RCL_GetPrecision(RCL_Instance instance);
#endif #endif

View file

@ -33,144 +33,65 @@
#include "sysincl.h" #include "sysincl.h"
#include <linux/ptp_clock.h>
#include "refclock.h" #include "refclock.h"
#include "logging.h" #include "logging.h"
#include "memory.h"
#include "util.h" #include "util.h"
#include "sys_linux.h"
/* From linux/include/linux/posix-timers.h */ struct phc_instance {
#define CPUCLOCK_MAX 3 int fd;
#define CLOCKFD CPUCLOCK_MAX int mode;
#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK)
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
#define NUM_READINGS 10
static int no_sys_offset_ioctl = 0;
struct phc_reading {
struct timespec sys_ts1;
struct timespec phc_ts;;
struct timespec sys_ts2;
}; };
static int read_phc_ioctl(struct phc_reading *readings, int phc_fd, int n)
{
#if defined(PTP_SYS_OFFSET) && NUM_READINGS <= PTP_MAX_SAMPLES
struct ptp_sys_offset sys_off;
int i;
/* Silence valgrind */
memset(&sys_off, 0, sizeof (sys_off));
sys_off.n_samples = n;
if (ioctl(phc_fd, PTP_SYS_OFFSET, &sys_off)) {
LOG(LOGS_ERR, LOGF_Refclock, "ioctl(PTP_SYS_OFFSET) failed : %s", strerror(errno));
return 0;
}
for (i = 0; i < n; i++) {
readings[i].sys_ts1.tv_sec = sys_off.ts[i * 2].sec;
readings[i].sys_ts1.tv_nsec = sys_off.ts[i * 2].nsec;
readings[i].phc_ts.tv_sec = sys_off.ts[i * 2 + 1].sec;
readings[i].phc_ts.tv_nsec = sys_off.ts[i * 2 + 1].nsec;
readings[i].sys_ts2.tv_sec = sys_off.ts[i * 2 + 2].sec;
readings[i].sys_ts2.tv_nsec = sys_off.ts[i * 2 + 2].nsec;
}
return 1;
#else
/* Not available */
return 0;
#endif
}
static int read_phc_user(struct phc_reading *readings, int phc_fd, int n)
{
clockid_t phc_id;
int i;
phc_id = FD_TO_CLOCKID(phc_fd);
for (i = 0; i < n; i++) {
if (clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts1) ||
clock_gettime(phc_id, &readings[i].phc_ts) ||
clock_gettime(CLOCK_REALTIME, &readings[i].sys_ts2)) {
LOG(LOGS_ERR, LOGF_Refclock, "clock_gettime() failed : %s", strerror(errno));
return 0;
}
}
return 1;
}
static int phc_initialise(RCL_Instance instance) static int phc_initialise(RCL_Instance instance)
{ {
struct ptp_clock_caps caps; struct phc_instance *phc;
int phc_fd; int phc_fd;
char *path; char *path;
path = RCL_GetDriverParameter(instance); path = RCL_GetDriverParameter(instance);
phc_fd = open(path, O_RDONLY); phc_fd = SYS_Linux_OpenPHC(path, 0);
if (phc_fd < 0) { if (phc_fd < 0) {
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path); LOG_FATAL(LOGF_Refclock, "Could not open PHC");
return 0; return 0;
} }
/* Make sure it is a PHC */ phc = MallocNew(struct phc_instance);
if (ioctl(phc_fd, PTP_CLOCK_GETCAPS, &caps)) { phc->fd = phc_fd;
LOG_FATAL(LOGF_Refclock, "ioctl(PTP_CLOCK_GETCAPS) failed : %s", strerror(errno)); phc->mode = 0;
return 0;
}
UTI_FdSetCloexec(phc_fd); RCL_SetDriverData(instance, phc);
RCL_SetDriverData(instance, (void *)(long)phc_fd);
return 1; return 1;
} }
static void phc_finalise(RCL_Instance instance) static void phc_finalise(RCL_Instance instance)
{ {
close((long)RCL_GetDriverData(instance)); struct phc_instance *phc;
phc = (struct phc_instance *)RCL_GetDriverData(instance);
close(phc->fd);
Free(phc);
} }
static int phc_poll(RCL_Instance instance) static int phc_poll(RCL_Instance instance)
{ {
struct phc_reading readings[NUM_READINGS]; struct phc_instance *phc;
double offset = 0.0, delay, best_delay = 0.0; struct timespec phc_ts, sys_ts;
int i, phc_fd, best; double offset, err;
phc_fd = (long)RCL_GetDriverData(instance); phc = (struct phc_instance *)RCL_GetDriverData(instance);
if (!no_sys_offset_ioctl) { if (!SYS_Linux_GetPHCSample(phc->fd, RCL_GetPrecision(instance), &phc->mode,
if (!read_phc_ioctl(readings, phc_fd, NUM_READINGS)) { &phc_ts, &sys_ts, &err))
no_sys_offset_ioctl = 1; return 0;
return 0;
}
} else {
if (!read_phc_user(readings, phc_fd, NUM_READINGS))
return 0;
}
/* Find the fastest reading */ offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
for (i = 0; i < NUM_READINGS; i++) {
delay = UTI_DiffTimespecsToDouble(&readings[i].sys_ts2, &readings[i].sys_ts1);
if (!i || best_delay > delay) { DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f err: %.9f", offset, err);
best = i;
best_delay = delay;
}
}
offset = UTI_DiffTimespecsToDouble(&readings[best].phc_ts, &readings[best].sys_ts2) + return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
best_delay / 2.0;
DEBUG_LOG(LOGF_Refclock, "PHC offset: %+.9f delay: %.9f", offset, best_delay);
return RCL_AddSample(instance, &readings[best].sys_ts2, offset, LEAP_Normal);
} }
RefclockDriver RCL_PHC_driver = { RefclockDriver RCL_PHC_driver = {