Add PPS API refclock driver
This commit is contained in:
parent
352f03d487
commit
b4069a4c3b
8 changed files with 328 additions and 4 deletions
|
@ -41,7 +41,8 @@ OBJS = util.o sched.o regress.o local.o \
|
||||||
logging.o conf.o cmdmon.o md5.o keys.o \
|
logging.o conf.o cmdmon.o md5.o keys.o \
|
||||||
nameserv.o acquire.o manual.o addrfilt.o \
|
nameserv.o acquire.o manual.o addrfilt.o \
|
||||||
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
|
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
|
||||||
broadcast.o refclock.o refclock_shm.o refclock_sock.o
|
broadcast.o refclock.o refclock_shm.o refclock_sock.o \
|
||||||
|
refclock_pps.o
|
||||||
|
|
||||||
EXTRA_OBJS=@EXTRA_OBJECTS@
|
EXTRA_OBJS=@EXTRA_OBJECTS@
|
||||||
|
|
||||||
|
|
7
conf.c
7
conf.c
|
@ -429,7 +429,7 @@ parse_peer(const char *line)
|
||||||
static void
|
static void
|
||||||
parse_refclock(const char *line)
|
parse_refclock(const char *line)
|
||||||
{
|
{
|
||||||
int i, n, poll, dpoll, filter_length;
|
int i, n, poll, dpoll, filter_length, pps_rate;
|
||||||
unsigned long ref_id;
|
unsigned long ref_id;
|
||||||
double offset, delay;
|
double offset, delay;
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
|
@ -443,6 +443,7 @@ parse_refclock(const char *line)
|
||||||
poll = 4;
|
poll = 4;
|
||||||
dpoll = 0;
|
dpoll = 0;
|
||||||
filter_length = 15;
|
filter_length = 15;
|
||||||
|
pps_rate = 0;
|
||||||
offset = 0.0;
|
offset = 0.0;
|
||||||
delay = 1e-9;
|
delay = 1e-9;
|
||||||
ref_id = 0;
|
ref_id = 0;
|
||||||
|
@ -486,6 +487,9 @@ parse_refclock(const char *line)
|
||||||
if (sscanf(line, "%d%n", &filter_length, &n) != 1) {
|
if (sscanf(line, "%d%n", &filter_length, &n) != 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (!strncasecmp(cmd, "rate", 4)) {
|
||||||
|
if (sscanf(line, "%d%n", &pps_rate, &n) != 1)
|
||||||
|
break;
|
||||||
} else if (!strncasecmp(cmd, "offset", 6)) {
|
} else if (!strncasecmp(cmd, "offset", 6)) {
|
||||||
if (sscanf(line, "%lf%n", &offset, &n) != 1)
|
if (sscanf(line, "%lf%n", &offset, &n) != 1)
|
||||||
break;
|
break;
|
||||||
|
@ -504,6 +508,7 @@ parse_refclock(const char *line)
|
||||||
refclock_sources[i].driver_poll = dpoll;
|
refclock_sources[i].driver_poll = dpoll;
|
||||||
refclock_sources[i].poll = poll;
|
refclock_sources[i].poll = poll;
|
||||||
refclock_sources[i].filter_length = filter_length;
|
refclock_sources[i].filter_length = filter_length;
|
||||||
|
refclock_sources[i].pps_rate = pps_rate;
|
||||||
refclock_sources[i].offset = offset;
|
refclock_sources[i].offset = offset;
|
||||||
refclock_sources[i].delay = delay;
|
refclock_sources[i].delay = delay;
|
||||||
refclock_sources[i].ref_id = ref_id;
|
refclock_sources[i].ref_id = ref_id;
|
||||||
|
|
32
configure
vendored
32
configure
vendored
|
@ -132,6 +132,30 @@ EOF
|
||||||
echo $result
|
echo $result
|
||||||
}
|
}
|
||||||
#}}}
|
#}}}
|
||||||
|
#{{{ test_for_ppsapi
|
||||||
|
test_for_ppsapi () {
|
||||||
|
cat >docheck.c <<EOF;
|
||||||
|
#include <timepps.h>
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
pps_handle_t h;
|
||||||
|
pps_info_t i;
|
||||||
|
struct timespec ts;
|
||||||
|
return time_pps_fetch(&h, PPS_TSFMT_TSPEC, &i, &ts);
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
${MYCC} ${MYCFLAGS} -c -o docheck.o docheck.c >/dev/null 2>&1
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
result=0
|
||||||
|
else
|
||||||
|
result=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f docheck.c docheck.o
|
||||||
|
echo $result
|
||||||
|
}
|
||||||
|
#}}}
|
||||||
#{{{ usage
|
#{{{ usage
|
||||||
usage () {
|
usage () {
|
||||||
cat <<EOF;
|
cat <<EOF;
|
||||||
|
@ -378,6 +402,14 @@ else
|
||||||
printf "No\n"
|
printf "No\n"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
printf "Checking for PPS API : "
|
||||||
|
if [ `test_for_ppsapi` -eq 0 ]; then
|
||||||
|
printf "Yes\n"
|
||||||
|
SYSDEFS="${SYSDEFS} -DHAVE_PPSAPI"
|
||||||
|
else
|
||||||
|
printf "No\n"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "x${MYCC}" = "xgcc" ]; then
|
if [ "x${MYCC}" = "xgcc" ]; then
|
||||||
CCWARNFLAGS="-Wmissing-prototypes -Wall"
|
CCWARNFLAGS="-Wmissing-prototypes -Wall"
|
||||||
else
|
else
|
||||||
|
|
112
refclock.c
112
refclock.c
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "refclock.h"
|
#include "refclock.h"
|
||||||
|
#include "reference.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "local.h"
|
#include "local.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
@ -37,6 +38,7 @@
|
||||||
/* list of refclock drivers */
|
/* list of refclock drivers */
|
||||||
extern RefclockDriver RCL_SHM_driver;
|
extern RefclockDriver RCL_SHM_driver;
|
||||||
extern RefclockDriver RCL_SOCK_driver;
|
extern RefclockDriver RCL_SOCK_driver;
|
||||||
|
extern RefclockDriver RCL_PPS_driver;
|
||||||
|
|
||||||
struct FilterSample {
|
struct FilterSample {
|
||||||
double offset;
|
double offset;
|
||||||
|
@ -59,6 +61,7 @@ struct RCL_Instance_Record {
|
||||||
int poll;
|
int poll;
|
||||||
int missed_samples;
|
int missed_samples;
|
||||||
int leap_status;
|
int leap_status;
|
||||||
|
int pps_rate;
|
||||||
struct MedianFilter filter;
|
struct MedianFilter filter;
|
||||||
unsigned long ref_id;
|
unsigned long ref_id;
|
||||||
double offset;
|
double offset;
|
||||||
|
@ -72,6 +75,7 @@ struct RCL_Instance_Record {
|
||||||
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
|
static struct RCL_Instance_Record refclocks[MAX_RCL_SOURCES];
|
||||||
static int n_sources = 0;
|
static int n_sources = 0;
|
||||||
|
|
||||||
|
static int pps_stratum(RCL_Instance instance, struct timeval *tv);
|
||||||
static void poll_timeout(void *arg);
|
static void poll_timeout(void *arg);
|
||||||
static void slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
|
static void slew_samples(struct timeval *raw, struct timeval *cooked, double dfreq, double afreq,
|
||||||
double doffset, int is_step_change, void *anything);
|
double doffset, int is_step_change, void *anything);
|
||||||
|
@ -111,6 +115,8 @@ RCL_Finalise(void)
|
||||||
int
|
int
|
||||||
RCL_AddRefclock(RefclockParameters *params)
|
RCL_AddRefclock(RefclockParameters *params)
|
||||||
{
|
{
|
||||||
|
int pps_source = 0;
|
||||||
|
|
||||||
RCL_Instance inst = &refclocks[n_sources];
|
RCL_Instance inst = &refclocks[n_sources];
|
||||||
|
|
||||||
if (n_sources == MAX_RCL_SOURCES)
|
if (n_sources == MAX_RCL_SOURCES)
|
||||||
|
@ -120,11 +126,19 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||||
inst->driver = &RCL_SHM_driver;
|
inst->driver = &RCL_SHM_driver;
|
||||||
} else if (strncmp(params->driver_name, "SOCK", 4) == 0) {
|
} else if (strncmp(params->driver_name, "SOCK", 4) == 0) {
|
||||||
inst->driver = &RCL_SOCK_driver;
|
inst->driver = &RCL_SOCK_driver;
|
||||||
|
} else if (strncmp(params->driver_name, "PPS", 4) == 0) {
|
||||||
|
inst->driver = &RCL_PPS_driver;
|
||||||
|
pps_source = 1;
|
||||||
} else {
|
} else {
|
||||||
LOG_FATAL(LOGF_Refclock, "unknown refclock driver %s", params->driver_name);
|
LOG_FATAL(LOGF_Refclock, "unknown refclock driver %s", params->driver_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!inst->driver->init && !inst->driver->poll) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "refclock driver %s is not compiled in", params->driver_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
inst->data = NULL;
|
inst->data = NULL;
|
||||||
inst->driver_parameter = params->driver_parameter;
|
inst->driver_parameter = params->driver_parameter;
|
||||||
inst->driver_poll = params->driver_poll;
|
inst->driver_poll = params->driver_poll;
|
||||||
|
@ -132,11 +146,19 @@ RCL_AddRefclock(RefclockParameters *params)
|
||||||
inst->missed_samples = 0;
|
inst->missed_samples = 0;
|
||||||
inst->driver_polled = 0;
|
inst->driver_polled = 0;
|
||||||
inst->leap_status = 0;
|
inst->leap_status = 0;
|
||||||
|
inst->pps_rate = params->pps_rate;
|
||||||
inst->offset = params->offset;
|
inst->offset = params->offset;
|
||||||
inst->delay = params->delay;
|
inst->delay = params->delay;
|
||||||
inst->timeout_id = -1;
|
inst->timeout_id = -1;
|
||||||
inst->source = NULL;
|
inst->source = NULL;
|
||||||
|
|
||||||
|
if (pps_source) {
|
||||||
|
if (inst->pps_rate < 1)
|
||||||
|
inst->pps_rate = 1;
|
||||||
|
} else {
|
||||||
|
inst->pps_rate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (inst->driver_poll > inst->poll)
|
if (inst->driver_poll > inst->poll)
|
||||||
inst->driver_poll = inst->poll;
|
inst->driver_poll = inst->poll;
|
||||||
|
|
||||||
|
@ -239,6 +261,85 @@ RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second)
|
||||||
|
{
|
||||||
|
double correction, offset;
|
||||||
|
struct timeval cooked_time;
|
||||||
|
int rate;
|
||||||
|
|
||||||
|
struct timeval ref_time;
|
||||||
|
int is_synchronised, stratum;
|
||||||
|
double root_delay, root_dispersion, distance;
|
||||||
|
NTP_Leap leap;
|
||||||
|
unsigned long ref_id;
|
||||||
|
|
||||||
|
correction = LCL_GetOffsetCorrection(pulse_time);
|
||||||
|
UTI_AddDoubleToTimeval(pulse_time, correction, &cooked_time);
|
||||||
|
|
||||||
|
rate = instance->pps_rate;
|
||||||
|
assert(rate > 0);
|
||||||
|
|
||||||
|
/* Ignore the pulse if we are not well synchronized */
|
||||||
|
|
||||||
|
REF_GetReferenceParams(&cooked_time, &is_synchronised, &leap, &stratum,
|
||||||
|
&ref_id, &ref_time, &root_delay, &root_dispersion);
|
||||||
|
distance = fabs(root_delay) / 2 + root_dispersion;
|
||||||
|
|
||||||
|
if (!is_synchronised || distance >= 0.5 / rate) {
|
||||||
|
#if 0
|
||||||
|
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse dropped second=%.9f sync=%d dist=%.9f",
|
||||||
|
second, is_synchronised, distance);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = -second - correction + instance->offset;
|
||||||
|
|
||||||
|
/* Adjust the offset to [-0.5/rate, 0.5/rate) interval */
|
||||||
|
offset -= (long)(offset * rate) / (double)rate;
|
||||||
|
if (offset < -0.5 / rate)
|
||||||
|
offset += 1.0 / rate;
|
||||||
|
else if (offset >= 0.5 / rate)
|
||||||
|
offset -= 1.0 / rate;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
LOG(LOGS_INFO, LOGF_Refclock, "refclock pulse second=%.9f offset=%.9f",
|
||||||
|
second, offset + instance->offset);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
filter_add_sample(&instance->filter, &cooked_time, offset);
|
||||||
|
instance->leap_status = LEAP_Normal;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pps_stratum(RCL_Instance instance, struct timeval *tv)
|
||||||
|
{
|
||||||
|
struct timeval ref_time;
|
||||||
|
int is_synchronised, stratum, i;
|
||||||
|
double root_delay, root_dispersion;
|
||||||
|
NTP_Leap leap;
|
||||||
|
unsigned long ref_id;
|
||||||
|
|
||||||
|
REF_GetReferenceParams(tv, &is_synchronised, &leap, &stratum,
|
||||||
|
&ref_id, &ref_time, &root_delay, &root_dispersion);
|
||||||
|
|
||||||
|
/* Don't change our stratum if local stratum is active
|
||||||
|
or this is the current source */
|
||||||
|
if (ref_id == instance->ref_id || REF_IsLocalActive())
|
||||||
|
return stratum - 1;
|
||||||
|
|
||||||
|
/* Or the current source is another PPS refclock */
|
||||||
|
for (i = 0; i < n_sources; i++) {
|
||||||
|
if (refclocks[i].ref_id == ref_id && refclocks[i].pps_rate)
|
||||||
|
return stratum - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
poll_timeout(void *arg)
|
poll_timeout(void *arg)
|
||||||
{
|
{
|
||||||
|
@ -258,7 +359,7 @@ poll_timeout(void *arg)
|
||||||
if (!(inst->driver->poll && inst->driver_polled < (1 << (inst->poll - inst->driver_poll)))) {
|
if (!(inst->driver->poll && inst->driver_polled < (1 << (inst->poll - inst->driver_poll)))) {
|
||||||
double offset, dispersion;
|
double offset, dispersion;
|
||||||
struct timeval sample_time;
|
struct timeval sample_time;
|
||||||
int sample_ok;
|
int sample_ok, stratum;
|
||||||
|
|
||||||
sample_ok = filter_get_sample(&inst->filter, &sample_time, &offset, &dispersion);
|
sample_ok = filter_get_sample(&inst->filter, &sample_time, &offset, &dispersion);
|
||||||
filter_reset(&inst->filter);
|
filter_reset(&inst->filter);
|
||||||
|
@ -269,9 +370,16 @@ poll_timeout(void *arg)
|
||||||
LOG(LOGS_INFO, LOGF_Refclock, "refclock filtered sample: offset=%.9f dispersion=%.9f [%s]",
|
LOG(LOGS_INFO, LOGF_Refclock, "refclock filtered sample: offset=%.9f dispersion=%.9f [%s]",
|
||||||
offset, dispersion, UTI_TimevalToString(&sample_time));
|
offset, dispersion, UTI_TimevalToString(&sample_time));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (inst->pps_rate)
|
||||||
|
/* Handle special case when PPS is used with local stratum */
|
||||||
|
stratum = pps_stratum(inst, &sample_time);
|
||||||
|
else
|
||||||
|
stratum = 0;
|
||||||
|
|
||||||
SRC_SetReachable(inst->source);
|
SRC_SetReachable(inst->source);
|
||||||
SRC_AccumulateSample(inst->source, &sample_time, offset,
|
SRC_AccumulateSample(inst->source, &sample_time, offset,
|
||||||
inst->delay, dispersion, inst->delay, dispersion, 0, inst->leap_status);
|
inst->delay, dispersion, inst->delay, dispersion, stratum, inst->leap_status);
|
||||||
inst->missed_samples = 0;
|
inst->missed_samples = 0;
|
||||||
} else {
|
} else {
|
||||||
inst->missed_samples++;
|
inst->missed_samples++;
|
||||||
|
|
|
@ -37,6 +37,7 @@ typedef struct {
|
||||||
int driver_poll;
|
int driver_poll;
|
||||||
int poll;
|
int poll;
|
||||||
int filter_length;
|
int filter_length;
|
||||||
|
int pps_rate;
|
||||||
unsigned long ref_id;
|
unsigned long ref_id;
|
||||||
double offset;
|
double offset;
|
||||||
double delay;
|
double delay;
|
||||||
|
@ -62,5 +63,6 @@ extern void RCL_SetDriverData(RCL_Instance instance, void *data);
|
||||||
extern void *RCL_GetDriverData(RCL_Instance instance);
|
extern void *RCL_GetDriverData(RCL_Instance instance);
|
||||||
extern char *RCL_GetDriverParameter(RCL_Instance instance);
|
extern char *RCL_GetDriverParameter(RCL_Instance instance);
|
||||||
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status);
|
extern int RCL_AddSample(RCL_Instance instance, struct timeval *sample_time, double offset, NTP_Leap leap_status);
|
||||||
|
extern int RCL_AddPulse(RCL_Instance instance, struct timeval *pulse_time, double second);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
167
refclock_pps.c
Normal file
167
refclock_pps.c
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
|
**********************************************************************
|
||||||
|
* Copyright (C) Miroslav Lichvar 2009
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
PPSAPI refclock driver.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "refclock.h"
|
||||||
|
|
||||||
|
#if HAVE_PPSAPI
|
||||||
|
|
||||||
|
#include <timepps.h>
|
||||||
|
|
||||||
|
#include "logging.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct pps_instance {
|
||||||
|
pps_handle_t handle;
|
||||||
|
unsigned long last_seq;
|
||||||
|
int edge_clear;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pps_initialise(RCL_Instance instance) {
|
||||||
|
pps_handle_t handle;
|
||||||
|
pps_params_t params;
|
||||||
|
struct pps_instance *pps;
|
||||||
|
int fd, edge_clear, mode;
|
||||||
|
char *path, *s;
|
||||||
|
|
||||||
|
path = RCL_GetDriverParameter(instance);
|
||||||
|
|
||||||
|
edge_clear = 0;
|
||||||
|
if ((s = strrchr(path, ':')) != NULL) {
|
||||||
|
*s = '\0';
|
||||||
|
edge_clear = atoi(s + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(path, O_RDWR);
|
||||||
|
if (fd < 0) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "open() failed on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_pps_create(fd, &handle) < 0) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "time_pps_create() failed on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_pps_getcap(handle, &mode) < 0) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "time_pps_getcap() failed on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_pps_getparams(handle, ¶ms) < 0) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "time_pps_getparams() failed on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!edge_clear) {
|
||||||
|
if (!(mode & PPS_CAPTUREASSERT)) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "CAPTUREASSERT not supported on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
params.mode |= PPS_CAPTUREASSERT;
|
||||||
|
params.mode &= ~PPS_CAPTURECLEAR;
|
||||||
|
} else {
|
||||||
|
if (!(mode & PPS_CAPTURECLEAR)) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "CAPTURECLEAR not supported on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
params.mode |= PPS_CAPTURECLEAR;
|
||||||
|
params.mode &= ~PPS_CAPTUREASSERT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_pps_setparams(handle, ¶ms) < 0) {
|
||||||
|
LOG_FATAL(LOGF_Refclock, "time_pps_setparams() failed on %s", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pps = MallocNew(struct pps_instance);
|
||||||
|
pps->handle = handle;
|
||||||
|
pps->last_seq = 0;
|
||||||
|
pps->edge_clear = edge_clear;
|
||||||
|
|
||||||
|
RCL_SetDriverData(instance, pps);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pps_finalise(RCL_Instance instance)
|
||||||
|
{
|
||||||
|
struct pps_instance *pps;
|
||||||
|
|
||||||
|
pps = (struct pps_instance *)RCL_GetDriverData(instance);
|
||||||
|
time_pps_destroy(pps->handle);
|
||||||
|
Free(pps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pps_poll(RCL_Instance instance)
|
||||||
|
{
|
||||||
|
struct pps_instance *pps;
|
||||||
|
struct timespec ts;
|
||||||
|
struct timeval tv;
|
||||||
|
pps_info_t pps_info;
|
||||||
|
unsigned long seq;
|
||||||
|
|
||||||
|
pps = (struct pps_instance *)RCL_GetDriverData(instance);
|
||||||
|
|
||||||
|
ts.tv_sec = 0;
|
||||||
|
ts.tv_nsec = 0;
|
||||||
|
|
||||||
|
if (time_pps_fetch(pps->handle, PPS_TSFMT_TSPEC, &pps_info, &ts) < 0) {
|
||||||
|
#if 0
|
||||||
|
LOG(LOGS_INFO, LOGF_Refclock, "time_pps_fetch error");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pps->edge_clear) {
|
||||||
|
seq = pps_info.assert_sequence;
|
||||||
|
ts = pps_info.assert_timestamp;
|
||||||
|
} else {
|
||||||
|
seq = pps_info.clear_sequence;
|
||||||
|
ts = pps_info.clear_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq == pps->last_seq || (ts.tv_sec == 0 && ts.tv_nsec == 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tv.tv_sec = ts.tv_sec;
|
||||||
|
tv.tv_usec = ts.tv_nsec / 1000;
|
||||||
|
|
||||||
|
return RCL_AddPulse(instance, &tv, ts.tv_nsec / 1e9);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefclockDriver RCL_PPS_driver = {
|
||||||
|
pps_initialise,
|
||||||
|
pps_finalise,
|
||||||
|
pps_poll
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
RefclockDriver RCL_PPS_driver = { NULL, NULL, NULL };
|
||||||
|
|
||||||
|
#endif
|
|
@ -695,6 +695,14 @@ REF_DisableLocal(void)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
REF_IsLocalActive(void)
|
||||||
|
{
|
||||||
|
return !are_we_synchronised && enable_local_stratum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
void
|
void
|
||||||
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
REF_GetTrackingReport(RPT_TrackingReport *rep)
|
||||||
{
|
{
|
||||||
|
|
|
@ -140,6 +140,7 @@ extern void REF_ModifyMaxupdateskew(double new_max_update_skew);
|
||||||
|
|
||||||
extern void REF_EnableLocal(int stratum);
|
extern void REF_EnableLocal(int stratum);
|
||||||
extern void REF_DisableLocal(void);
|
extern void REF_DisableLocal(void);
|
||||||
|
extern int REF_IsLocalActive(void);
|
||||||
|
|
||||||
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
extern void REF_GetTrackingReport(RPT_TrackingReport *rep);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue