2 chronyd/chronyc - Programs for keeping computer clocks accurate.
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2013, 2017
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **********************************************************************
22 =======================================================================
24 PTP hardware clock (PHC) refclock driver.
43 #include "sys_linux.h"
55 static void read_ext_pulse(int sockfd
, int event
, void *anything
);
57 static int phc_initialise(RCL_Instance instance
)
59 const char *options
[] = {"nocrossts", "extpps", "pin", "channel", "clear", NULL
};
60 struct phc_instance
*phc
;
61 int phc_fd
, rising_edge
;
64 RCL_CheckDriverOptions(instance
, options
);
66 path
= RCL_GetDriverParameter(instance
);
68 phc_fd
= SYS_Linux_OpenPHC(path
, 0);
70 LOG_FATAL("Could not open PHC");
74 phc
= MallocNew(struct phc_instance
);
77 phc
->nocrossts
= RCL_GetDriverOption(instance
, "nocrossts") ? 1 : 0;
78 phc
->extpps
= RCL_GetDriverOption(instance
, "extpps") ? 1 : 0;
81 s
= RCL_GetDriverOption(instance
, "pin");
82 phc
->pin
= s
? atoi(s
) : 0;
83 s
= RCL_GetDriverOption(instance
, "channel");
84 phc
->channel
= s
? atoi(s
) : 0;
85 rising_edge
= RCL_GetDriverOption(instance
, "clear") ? 0 : 1;
86 phc
->clock
= HCL_CreateInstance(0, 16, UTI_Log2ToDouble(RCL_GetDriverPoll(instance
)));
88 if (!SYS_Linux_SetPHCExtTimestamping(phc
->fd
, phc
->pin
, phc
->channel
,
89 rising_edge
, !rising_edge
, 1))
90 LOG_FATAL("Could not enable external PHC timestamping");
92 SCH_AddFileHandler(phc
->fd
, SCH_FILE_INPUT
, read_ext_pulse
, instance
);
94 phc
->pin
= phc
->channel
= 0;
98 RCL_SetDriverData(instance
, phc
);
102 static void phc_finalise(RCL_Instance instance
)
104 struct phc_instance
*phc
;
106 phc
= (struct phc_instance
*)RCL_GetDriverData(instance
);
109 SCH_RemoveFileHandler(phc
->fd
);
110 SYS_Linux_SetPHCExtTimestamping(phc
->fd
, phc
->pin
, phc
->channel
, 0, 0, 0);
111 HCL_DestroyInstance(phc
->clock
);
118 static void read_ext_pulse(int fd
, int event
, void *anything
)
120 RCL_Instance instance
;
121 struct phc_instance
*phc
;
122 struct timespec phc_ts
, local_ts
;
127 phc
= RCL_GetDriverData(instance
);
129 if (!SYS_Linux_ReadPHCExtTimestamp(phc
->fd
, &phc_ts
, &channel
))
132 if (channel
!= phc
->channel
) {
133 DEBUG_LOG("Unexpected extts channel %d\n", channel
);
137 if (!HCL_CookTime(phc
->clock
, &phc_ts
, &local_ts
, &local_err
))
140 RCL_AddCookedPulse(instance
, &local_ts
, 1.0e-9 * local_ts
.tv_nsec
, local_err
,
141 UTI_DiffTimespecsToDouble(&phc_ts
, &local_ts
));
144 static int phc_poll(RCL_Instance instance
)
146 struct phc_instance
*phc
;
147 struct timespec phc_ts
, sys_ts
, local_ts
;
148 double offset
, phc_err
, local_err
;
150 phc
= (struct phc_instance
*)RCL_GetDriverData(instance
);
152 if (!SYS_Linux_GetPHCSample(phc
->fd
, phc
->nocrossts
, RCL_GetPrecision(instance
),
153 &phc
->mode
, &phc_ts
, &sys_ts
, &phc_err
))
157 LCL_CookTime(&sys_ts
, &local_ts
, &local_err
);
158 HCL_AccumulateSample(phc
->clock
, &phc_ts
, &local_ts
, phc_err
+ local_err
);
162 offset
= UTI_DiffTimespecsToDouble(&phc_ts
, &sys_ts
);
164 DEBUG_LOG("PHC offset: %+.9f err: %.9f", offset
, phc_err
);
166 return RCL_AddSample(instance
, &sys_ts
, offset
, LEAP_Normal
);
169 RefclockDriver RCL_PHC_driver
= {
177 RefclockDriver RCL_PHC_driver
= { NULL
, NULL
, NULL
};