mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 16:35:06 -05:00
Add PPS API refclock driver
This commit is contained in:
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
|
||||
Reference in New Issue
Block a user