|
Packit |
96c956 |
/*
|
|
Packit |
96c956 |
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
**********************************************************************
|
|
Packit |
96c956 |
* Copyright (C) Miroslav Lichvar 2013, 2017
|
|
Packit |
96c956 |
*
|
|
Packit |
96c956 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
96c956 |
* it under the terms of version 2 of the GNU General Public License as
|
|
Packit |
96c956 |
* published by the Free Software Foundation.
|
|
Packit |
96c956 |
*
|
|
Packit |
96c956 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
96c956 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
96c956 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
96c956 |
* General Public License for more details.
|
|
Packit |
96c956 |
*
|
|
Packit |
96c956 |
* You should have received a copy of the GNU General Public License along
|
|
Packit |
96c956 |
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit |
96c956 |
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
96c956 |
*
|
|
Packit |
96c956 |
**********************************************************************
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
=======================================================================
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
PTP hardware clock (PHC) refclock driver.
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
*/
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#include "config.h"
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#include "refclock.h"
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#ifdef FEAT_PHC
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#include "sysincl.h"
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#include "refclock.h"
|
|
Packit |
96c956 |
#include "hwclock.h"
|
|
Packit |
96c956 |
#include "local.h"
|
|
Packit |
96c956 |
#include "logging.h"
|
|
Packit |
96c956 |
#include "memory.h"
|
|
Packit |
96c956 |
#include "util.h"
|
|
Packit |
96c956 |
#include "sched.h"
|
|
Packit |
96c956 |
#include "sys_linux.h"
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
struct phc_instance {
|
|
Packit |
96c956 |
int fd;
|
|
Packit |
96c956 |
int mode;
|
|
Packit |
96c956 |
int nocrossts;
|
|
Packit |
96c956 |
int extpps;
|
|
Packit |
96c956 |
int pin;
|
|
Packit |
96c956 |
int channel;
|
|
Packit |
96c956 |
HCL_Instance clock;
|
|
Packit |
96c956 |
};
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
static void read_ext_pulse(int sockfd, int event, void *anything);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
static int phc_initialise(RCL_Instance instance)
|
|
Packit |
96c956 |
{
|
|
Packit |
96c956 |
const char *options[] = {"nocrossts", "extpps", "pin", "channel", "clear", NULL};
|
|
Packit |
96c956 |
struct phc_instance *phc;
|
|
Packit |
96c956 |
int phc_fd, rising_edge;
|
|
Packit |
96c956 |
char *path, *s;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
RCL_CheckDriverOptions(instance, options);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
path = RCL_GetDriverParameter(instance);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
phc_fd = SYS_Linux_OpenPHC(path, 0);
|
|
Packit |
96c956 |
if (phc_fd < 0) {
|
|
Packit |
96c956 |
LOG_FATAL("Could not open PHC");
|
|
Packit |
96c956 |
return 0;
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
phc = MallocNew(struct phc_instance);
|
|
Packit |
96c956 |
phc->fd = phc_fd;
|
|
Packit |
96c956 |
phc->mode = 0;
|
|
Packit |
96c956 |
phc->nocrossts = RCL_GetDriverOption(instance, "nocrossts") ? 1 : 0;
|
|
Packit |
96c956 |
phc->extpps = RCL_GetDriverOption(instance, "extpps") ? 1 : 0;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (phc->extpps) {
|
|
Packit |
96c956 |
s = RCL_GetDriverOption(instance, "pin");
|
|
Packit |
96c956 |
phc->pin = s ? atoi(s) : 0;
|
|
Packit |
96c956 |
s = RCL_GetDriverOption(instance, "channel");
|
|
Packit |
96c956 |
phc->channel = s ? atoi(s) : 0;
|
|
Packit |
96c956 |
rising_edge = RCL_GetDriverOption(instance, "clear") ? 0 : 1;
|
|
Packit |
96c956 |
phc->clock = HCL_CreateInstance(0, 16, UTI_Log2ToDouble(RCL_GetDriverPoll(instance)));
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (!SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel,
|
|
Packit |
96c956 |
rising_edge, !rising_edge, 1))
|
|
Packit |
96c956 |
LOG_FATAL("Could not enable external PHC timestamping");
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
SCH_AddFileHandler(phc->fd, SCH_FILE_INPUT, read_ext_pulse, instance);
|
|
Packit |
96c956 |
} else {
|
|
Packit |
96c956 |
phc->pin = phc->channel = 0;
|
|
Packit |
96c956 |
phc->clock = NULL;
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
RCL_SetDriverData(instance, phc);
|
|
Packit |
96c956 |
return 1;
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
static void phc_finalise(RCL_Instance instance)
|
|
Packit |
96c956 |
{
|
|
Packit |
96c956 |
struct phc_instance *phc;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (phc->extpps) {
|
|
Packit |
96c956 |
SCH_RemoveFileHandler(phc->fd);
|
|
Packit |
96c956 |
SYS_Linux_SetPHCExtTimestamping(phc->fd, phc->pin, phc->channel, 0, 0, 0);
|
|
Packit |
96c956 |
HCL_DestroyInstance(phc->clock);
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
close(phc->fd);
|
|
Packit |
96c956 |
Free(phc);
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
static void read_ext_pulse(int fd, int event, void *anything)
|
|
Packit |
96c956 |
{
|
|
Packit |
96c956 |
RCL_Instance instance;
|
|
Packit |
96c956 |
struct phc_instance *phc;
|
|
Packit |
96c956 |
struct timespec phc_ts, local_ts;
|
|
Packit |
96c956 |
double local_err;
|
|
Packit |
96c956 |
int channel;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
instance = anything;
|
|
Packit |
96c956 |
phc = RCL_GetDriverData(instance);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (!SYS_Linux_ReadPHCExtTimestamp(phc->fd, &phc_ts, &channel))
|
|
Packit |
96c956 |
return;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (channel != phc->channel) {
|
|
Packit |
96c956 |
DEBUG_LOG("Unexpected extts channel %d\n", channel);
|
|
Packit |
96c956 |
return;
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (!HCL_CookTime(phc->clock, &phc_ts, &local_ts, &local_err))
|
|
Packit |
96c956 |
return;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
RCL_AddCookedPulse(instance, &local_ts, 1.0e-9 * local_ts.tv_nsec, local_err,
|
|
Packit |
96c956 |
UTI_DiffTimespecsToDouble(&phc_ts, &local_ts));
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
static int phc_poll(RCL_Instance instance)
|
|
Packit |
96c956 |
{
|
|
Packit |
96c956 |
struct phc_instance *phc;
|
|
Packit |
96c956 |
struct timespec phc_ts, sys_ts, local_ts;
|
|
Packit |
96c956 |
double offset, phc_err, local_err;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
phc = (struct phc_instance *)RCL_GetDriverData(instance);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (!SYS_Linux_GetPHCSample(phc->fd, phc->nocrossts, RCL_GetPrecision(instance),
|
|
Packit |
96c956 |
&phc->mode, &phc_ts, &sys_ts, &phc_err))
|
|
Packit |
96c956 |
return 0;
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
if (phc->extpps) {
|
|
Packit |
96c956 |
LCL_CookTime(&sys_ts, &local_ts, &local_err);
|
|
Packit |
96c956 |
HCL_AccumulateSample(phc->clock, &phc_ts, &local_ts, phc_err + local_err);
|
|
Packit |
96c956 |
return 0;
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
offset = UTI_DiffTimespecsToDouble(&phc_ts, &sys_ts);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
DEBUG_LOG("PHC offset: %+.9f err: %.9f", offset, phc_err);
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
return RCL_AddSample(instance, &sys_ts, offset, LEAP_Normal);
|
|
Packit |
96c956 |
}
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
RefclockDriver RCL_PHC_driver = {
|
|
Packit |
96c956 |
phc_initialise,
|
|
Packit |
96c956 |
phc_finalise,
|
|
Packit |
96c956 |
phc_poll
|
|
Packit |
96c956 |
};
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#else
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
RefclockDriver RCL_PHC_driver = { NULL, NULL, NULL };
|
|
Packit |
96c956 |
|
|
Packit |
96c956 |
#endif
|