2 chronyd/chronyc - Programs for keeping computer clocks accurate.
4 **********************************************************************
5 * Copyright (C) Richard P. Curnow 1997-2003
6 * Copyright (C) Miroslav Lichvar 2012-2014
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of version 2 of the GNU General Public License as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 **********************************************************************
23 =======================================================================
25 Real-time clock driver for linux. This interfaces the program with
26 the clock that keeps time when the machine is turned off.
34 #include <linux/rtc.h>
40 #include "sys_linux.h"
41 #include "reference.h"
44 #include "rtc_linux.h"
48 /* ================================================== */
49 /* Forward prototypes */
51 static void measurement_timeout(void *any
);
53 static void read_from_device(int fd_
, int event
, void *any
);
55 /* ================================================== */
63 static OperatingMode operating_mode
= OM_NORMAL
;
65 /* ================================================== */
69 #define LOWEST_MEASUREMENT_PERIOD 15
70 #define HIGHEST_MEASUREMENT_PERIOD 480
71 #define N_SAMPLES_PER_REGRESSION 1
73 static int measurement_period
= LOWEST_MEASUREMENT_PERIOD
;
75 static SCH_TimeoutID timeout_id
= 0;
77 static int skip_interrupts
;
79 /* ================================================== */
81 /* Maximum number of samples held */
82 #define MAX_SAMPLES 64
84 /* Real time clock samples. We store the seconds count as originally
85 measured, together with a 'trim' that compensates these values for
86 any steps made to the RTC to bring it back into line
87 occasionally. The trim is in seconds. */
88 static time_t *rtc_sec
= NULL
;
89 static double *rtc_trim
= NULL
;
91 /* Reference time, against which delta times on the RTC scale are measured */
92 static time_t rtc_ref
;
95 /* System clock samples associated with the above samples. */
96 static struct timespec
*system_times
= NULL
;
98 /* Number of samples currently stored. */
101 /* Number of new samples since last regression */
102 static int n_samples_since_regression
;
104 /* Number of runs of residuals in last regression (for logging) */
108 /* Whether they are valid */
109 static int coefs_valid
;
112 static time_t coef_ref_time
;
113 /* Number of seconds by which RTC was fast of the system time at coef_ref_time */
114 static double coef_seconds_fast
;
116 /* Estimated number of seconds that RTC gains relative to system time
117 for each second of ITS OWN time */
118 static double coef_gain_rate
;
120 /* Gain rate saved just before we step the RTC to correct it to the
121 nearest second, so that we can write a useful set of coefs to the
122 RTC data file once we have reacquired its offset after the step */
123 static double saved_coef_gain_rate
;
125 /* Threshold for automatic RTC trimming in seconds, zero when disabled */
126 static double autotrim_threshold
;
128 /* Filename supplied by config file where RTC coefficients are
130 static char *coefs_file_name
;
132 /* ================================================== */
133 /* Coefficients read from file at start of run. */
135 /* Whether we have tried to load the coefficients */
136 static int tried_to_load_coefs
= 0;
138 /* Whether valid coefficients were read */
139 static int valid_coefs_from_file
= 0;
142 static time_t file_ref_time
;
143 static double file_ref_offset
, file_rate_ppm
;
145 /* ================================================== */
147 /* Flag to remember whether to assume the RTC is running on UTC */
148 static int rtc_on_utc
= 1;
150 /* ================================================== */
152 static LOG_FileID logfileid
;
154 /* ================================================== */
156 static void (*after_init_hook
)(void *) = NULL
;
157 static void *after_init_hook_arg
= NULL
;
159 /* ================================================== */
162 discard_samples(int new_first
)
166 assert(new_first
>= 0 && new_first
< n_samples
);
168 n_to_save
= n_samples
- new_first
;
170 memmove(rtc_sec
, rtc_sec
+ new_first
, n_to_save
* sizeof(time_t));
171 memmove(rtc_trim
, rtc_trim
+ new_first
, n_to_save
* sizeof(double));
172 memmove(system_times
, system_times
+ new_first
, n_to_save
* sizeof(struct timespec
));
174 n_samples
= n_to_save
;
177 /* ================================================== */
179 #define NEW_FIRST_WHEN_FULL 4
182 accumulate_sample(time_t rtc
, struct timespec
*sys
)
185 if (n_samples
== MAX_SAMPLES
) {
186 /* Discard oldest samples */
187 discard_samples(NEW_FIRST_WHEN_FULL
);
190 /* Discard all samples if the RTC was stepped back (not our trim) */
191 if (n_samples
> 0 && rtc_sec
[n_samples
- 1] - rtc
>= rtc_trim
[n_samples
- 1]) {
192 DEBUG_LOG("RTC samples discarded");
196 /* Always use most recent sample as reference */
197 /* use sample only if n_sample is not negative*/
201 rtc_sec
[n_samples
] = rtc
;
202 rtc_trim
[n_samples
] = 0.0;
203 system_times
[n_samples
] = *sys
;
204 ++n_samples_since_regression
;
209 /* ================================================== */
210 /* The new_sample flag is to indicate whether to adjust the
211 measurement period depending on the behaviour of the standard
215 run_regression(int new_sample
,
221 double rtc_rel
[MAX_SAMPLES
]; /* Relative times on RTC axis */
222 double offsets
[MAX_SAMPLES
]; /* How much the RTC is fast of the system clock */
224 double est_intercept
, est_slope
;
229 for (i
=0; i
<n_samples
; i
++) {
230 rtc_rel
[i
] = rtc_trim
[i
] + (double)(rtc_sec
[i
] - rtc_ref
);
231 offsets
[i
] = ((double) (rtc_ref
- system_times
[i
].tv_sec
) -
232 (1.0e-9 * system_times
[i
].tv_nsec
) +
237 if (RGR_FindBestRobustRegression
240 &est_intercept
, &est_slope
,
244 /* Calculate and store coefficients. We don't do any error
245 bounds processing on any of these. */
248 *fast
= est_intercept
;
251 if (best_new_start
> 0) {
252 discard_samples(best_new_start
);
257 /* Keep existing coefficients. */
260 /* Keep existing coefficients. */
265 /* ================================================== */
269 (struct timespec
*raw
, struct timespec
*cooked
,
272 LCL_ChangeType change_type
,
277 double old_seconds_fast
, old_gain_rate
;
279 if (change_type
== LCL_ChangeUnknownStep
) {
280 /* Drop all samples. */
284 for (i
=0; i
<n_samples
; i
++) {
285 UTI_AdjustTimespec(system_times
+ i
, cooked
, system_times
+ i
, &delta_time
,
289 old_seconds_fast
= coef_seconds_fast
;
290 old_gain_rate
= coef_gain_rate
;
293 coef_seconds_fast
+= doffset
;
294 coef_gain_rate
+= dfreq
* (1.0 - coef_gain_rate
);
297 DEBUG_LOG("dfreq=%.8f doffset=%.6f old_fast=%.6f old_rate=%.3f new_fast=%.6f new_rate=%.3f",
299 old_seconds_fast
, 1.0e6
* old_gain_rate
,
300 coef_seconds_fast
, 1.0e6
* coef_gain_rate
);
303 /* ================================================== */
305 /* Function to convert from a time_t value represenging UTC to the
306 corresponding real time clock 'DMY HMS' form, taking account of
307 whether the user runs his RTC on the local time zone or UTC */
310 rtc_from_t(const time_t *t
)
319 /* ================================================== */
321 /* Inverse function to get back from RTC 'DMY HMS' form to time_t UTC
322 form. This essentially uses mktime(), but involves some awful
323 complexity to cope with timezones. The problem is that mktime's
324 behaviour with regard to the daylight saving flag in the 'struct
325 tm' does not seem to be reliable across all systems, unless that
328 tm_isdst = -1 does not seem to work with all libc's - it is treated
329 as meaning there is DST, or fails completely. (It is supposed to
330 use the timezone info to work out whether summer time is active at
331 the specified epoch).
333 tm_isdst = 1 fails if the local timezone has no summer time defined.
335 The approach taken is as follows. Suppose the RTC is on localtime.
336 We perform all mktime calls with the tm_isdst field set to zero.
338 Let y be the RTC reading in 'DMY HMS' form. Let M be the mktime
339 function with tm_isdst=0 and L be the localtime function.
341 We seek x such that y = L(x). Now there will exist a value Z(t)
342 such that M(L(t)) = t + Z(t) for all t, where Z(t) depends on
343 whether daylight saving is active at time t.
345 We want L(x) = y. Therefore M(L(x)) = x + Z = M(y). But
346 M(L(M(y))) = M(y) + Z. Therefore x = M(y) - Z = M(y) - (M(L(M(y)))
349 The case for the RTC running on UTC is identical but without the
350 potential complication that Z depends on t.
354 t_from_rtc(struct tm
*stm
) {
355 struct tm temp1
, temp2
, *tm
;
364 tm
= rtc_on_utc
? gmtime(&t1
) : localtime(&t1
);
366 DEBUG_LOG("gmtime()/localtime() failed");
376 DEBUG_LOG("Could not convert RTC time");
381 /* ================================================== */
384 read_hwclock_file(const char *hwclock_file
)
390 if (!hwclock_file
|| !hwclock_file
[0])
393 in
= UTI_OpenFile(NULL
, hwclock_file
, NULL
, 'r', 0);
397 /* Read third line from the file. */
398 for (i
= 0; i
< 3; i
++) {
399 if (!fgets(line
, sizeof(line
), in
))
405 if (i
== 3 && !strncmp(line
, "LOCAL", 5)) {
407 } else if (i
== 3 && !strncmp(line
, "UTC", 3)) {
410 LOG(LOGS_WARN
, "Could not read RTC LOCAL/UTC setting from %s", hwclock_file
);
414 /* ================================================== */
419 if (CNF_GetRtcOnUtc()) {
425 read_hwclock_file(CNF_GetHwclockFile());
427 autotrim_threshold
= CNF_GetRtcAutotrim();
430 /* ================================================== */
431 /* Read the coefficients from the file where they were saved
432 the last time the program was run. */
435 read_coefs_from_file(void)
439 if (!tried_to_load_coefs
) {
441 valid_coefs_from_file
= 0; /* only gets set true if we succeed */
443 tried_to_load_coefs
= 1;
445 if (coefs_file_name
&&
446 (in
= UTI_OpenFile(NULL
, coefs_file_name
, NULL
, 'r', 0))) {
447 if (fscanf(in
, "%d%ld%lf%lf",
448 &valid_coefs_from_file
,
451 &file_rate_ppm
) == 4) {
453 LOG(LOGS_WARN
, "Could not read coefficients from %s", coefs_file_name
);
460 /* ================================================== */
461 /* Write the coefficients to the file where they will be read
462 the next time the program is run. */
465 write_coefs_to_file(int valid
,time_t ref_time
,double offset
,double rate
)
469 /* Create a temporary file with a '.tmp' extension. */
470 out
= UTI_OpenFile(NULL
, coefs_file_name
, ".tmp", 'w', 0644);
472 return RTC_ST_BADFILE
;
474 /* Gain rate is written out in ppm */
475 fprintf(out
, "%1d %ld %.6f %.3f\n", valid
, ref_time
, offset
, 1.0e6
* rate
);
478 /* Rename the temporary file to the correct location */
479 if (!UTI_RenameTempFile(NULL
, coefs_file_name
, ".tmp", NULL
))
480 return RTC_ST_BADFILE
;
485 /* ================================================== */
488 switch_interrupts(int on_off
)
490 if (ioctl(fd
, on_off
? RTC_UIE_ON
: RTC_UIE_OFF
, 0) < 0) {
491 LOG(LOGS_ERR
, "Could not %s RTC interrupt : %s",
492 on_off
? "enable" : "disable", strerror(errno
));
502 /* ================================================== */
503 /* file_name is the name of the file where we save the RTC params
504 between executions. Return status is whether we could initialise
505 on this version of the system. */
508 RTC_Linux_Initialise(void)
510 /* Try to open the device */
511 fd
= open(CNF_GetRtcDevice(), O_RDWR
);
513 LOG(LOGS_ERR
, "Could not open RTC device %s : %s",
514 CNF_GetRtcDevice(), strerror(errno
));
518 /* Make sure the RTC supports interrupts */
519 if (!switch_interrupts(1) || !switch_interrupts(0)) {
525 UTI_FdSetCloexec(fd
);
527 rtc_sec
= MallocArray(time_t, MAX_SAMPLES
);
528 rtc_trim
= MallocArray(double, MAX_SAMPLES
);
529 system_times
= MallocArray(struct timespec
, MAX_SAMPLES
);
531 /* Setup details depending on configuration options */
534 /* In case it didn't get done by pre-init */
535 coefs_file_name
= CNF_GetRtcFile();
538 n_samples_since_regression
= 0;
542 measurement_period
= LOWEST_MEASUREMENT_PERIOD
;
544 operating_mode
= OM_NORMAL
;
546 /* Register file handler */
547 SCH_AddFileHandler(fd
, SCH_FILE_INPUT
, read_from_device
, NULL
);
549 /* Register slew handler */
550 LCL_AddParameterChangeHandler(slew_samples
, NULL
);
552 logfileid
= CNF_GetLogRtc() ? LOG_FileOpen("rtc",
553 " Date (UTC) Time RTC fast (s) Val Est fast (s) Slope (ppm) Ns Nr Meas")
558 /* ================================================== */
561 RTC_Linux_Finalise(void)
563 SCH_RemoveTimeout(timeout_id
);
566 /* Remove input file handler */
568 SCH_RemoveFileHandler(fd
);
569 switch_interrupts(0);
572 /* Save the RTC data */
573 (void) RTC_Linux_WriteParameters();
578 LCL_RemoveParameterChangeHandler(slew_samples
, NULL
);
585 /* ================================================== */
588 measurement_timeout(void *any
)
591 switch_interrupts(1);
594 /* ================================================== */
597 set_rtc(time_t new_rtc_time
)
600 struct rtc_time rtc_raw
;
603 rtc_tm
= *rtc_from_t(&new_rtc_time
);
605 rtc_raw
.tm_sec
= rtc_tm
.tm_sec
;
606 rtc_raw
.tm_min
= rtc_tm
.tm_min
;
607 rtc_raw
.tm_hour
= rtc_tm
.tm_hour
;
608 rtc_raw
.tm_mday
= rtc_tm
.tm_mday
;
609 rtc_raw
.tm_mon
= rtc_tm
.tm_mon
;
610 rtc_raw
.tm_year
= rtc_tm
.tm_year
;
611 rtc_raw
.tm_wday
= rtc_tm
.tm_wday
;
612 rtc_raw
.tm_yday
= rtc_tm
.tm_yday
;
613 rtc_raw
.tm_isdst
= rtc_tm
.tm_isdst
;
615 status
= ioctl(fd
, RTC_SET_TIME
, &rtc_raw
);
617 LOG(LOGS_ERR
, "Could not set RTC time");
622 /* ================================================== */
625 handle_initial_trim(void)
629 double rtc_error_now
, sys_error_now
;
631 /* The idea is to accumulate some number of samples at 1 second
632 intervals, then do a robust regression fit to this. This
633 should give a good fix on the intercept (=system clock error
634 rel to RTC) at a particular time, removing risk of any
635 particular sample being an outlier. We can then look at the
636 elapsed interval since the epoch recorded in the RTC file,
637 and correct the system time accordingly. */
639 run_regression(1, &coefs_valid
, &coef_ref_time
, &coef_seconds_fast
, &coef_gain_rate
);
641 n_samples_since_regression
= 0;
643 /* Set sample number to -1 so the next sample is not used, as it will not yet be corrected for System Trim*/
648 read_coefs_from_file();
650 if (valid_coefs_from_file
) {
651 /* Can process data */
652 delta_time
= coef_ref_time
- file_ref_time
;
653 rate
= 1.0e-6 * file_rate_ppm
;
654 rtc_error_now
= file_ref_offset
+ rate
* (double) delta_time
;
656 /* sys_error_now is positive if the system clock is fast */
657 sys_error_now
= rtc_error_now
- coef_seconds_fast
;
659 LCL_AccumulateOffset(sys_error_now
, 0.0);
660 LOG(LOGS_INFO
, "System clock off from RTC by %f seconds (slew)",
663 LOG(LOGS_WARN
, "No valid rtcfile coefficients");
668 (after_init_hook
)(after_init_hook_arg
);
670 operating_mode
= OM_NORMAL
;
673 /* ================================================== */
676 handle_relock_after_trim(void)
683 run_regression(1, &valid
, &ref
, &fast
, &slope
);
686 write_coefs_to_file(1,ref
,fast
,saved_coef_gain_rate
);
688 DEBUG_LOG("Could not do regression after trim");
693 n_samples_since_regression
= 0;
694 operating_mode
= OM_NORMAL
;
695 measurement_period
= LOWEST_MEASUREMENT_PERIOD
;
698 /* ================================================== */
703 /* Trim only when in normal mode, the coefficients are fresh, the current
704 offset is above the threshold and the system clock is synchronized */
706 if (operating_mode
!= OM_NORMAL
|| !coefs_valid
|| n_samples_since_regression
)
709 if (autotrim_threshold
<= 0.0 || fabs(coef_seconds_fast
) < autotrim_threshold
)
712 if (REF_GetOurStratum() >= 16)
718 /* ================================================== */
721 process_reading(time_t rtc_time
, struct timespec
*system_time
)
725 accumulate_sample(rtc_time
, system_time
);
727 switch (operating_mode
) {
730 if (n_samples_since_regression
>= N_SAMPLES_PER_REGRESSION
) {
731 run_regression(1, &coefs_valid
, &coef_ref_time
, &coef_seconds_fast
, &coef_gain_rate
);
732 n_samples_since_regression
= 0;
738 if (n_samples_since_regression
>= 8) {
739 handle_initial_trim();
743 if (n_samples_since_regression
>= 8) {
744 handle_relock_after_trim();
753 if (logfileid
!= -1) {
754 rtc_fast
= (rtc_time
- system_time
->tv_sec
) - 1.0e-9 * system_time
->tv_nsec
;
756 LOG_FileWrite(logfileid
, "%s %14.6f %1d %14.6f %12.3f %2d %2d %4d",
757 UTI_TimeToLogForm(system_time
->tv_sec
),
760 coef_seconds_fast
, coef_gain_rate
* 1.0e6
, n_samples
, n_runs
, measurement_period
);
765 /* ================================================== */
768 read_from_device(int fd_
, int event
, void *any
)
772 struct timespec sys_time
;
773 struct rtc_time rtc_raw
;
778 status
= read(fd
, &data
, sizeof(data
));
781 /* This looks like a bad error : the file descriptor was indicating it was
782 * ready to read but we couldn't read anything. Give up. */
783 LOG(LOGS_ERR
, "Could not read flags %s : %s", CNF_GetRtcDevice(), strerror(errno
));
784 SCH_RemoveFileHandler(fd
);
785 switch_interrupts(0); /* Likely to raise error too, but just to be sure... */
791 if (skip_interrupts
> 0) {
792 /* Wait for the next interrupt, this one may be bogus */
797 if ((data
& RTC_UF
) == RTC_UF
) {
798 /* Update interrupt detected */
800 /* Read RTC time, sandwiched between two polls of the system clock
801 so we can bound any error. */
803 SCH_GetLastEventTime(&sys_time
, NULL
, NULL
);
805 status
= ioctl(fd
, RTC_RD_TIME
, &rtc_raw
);
807 LOG(LOGS_ERR
, "Could not read time from %s : %s", CNF_GetRtcDevice(), strerror(errno
));
809 goto turn_off_interrupt
;
812 /* Convert RTC time into a struct timespec */
813 rtc_tm
.tm_sec
= rtc_raw
.tm_sec
;
814 rtc_tm
.tm_min
= rtc_raw
.tm_min
;
815 rtc_tm
.tm_hour
= rtc_raw
.tm_hour
;
816 rtc_tm
.tm_mday
= rtc_raw
.tm_mday
;
817 rtc_tm
.tm_mon
= rtc_raw
.tm_mon
;
818 rtc_tm
.tm_year
= rtc_raw
.tm_year
;
820 rtc_t
= t_from_rtc(&rtc_tm
);
822 if (rtc_t
== (time_t)(-1)) {
824 goto turn_off_interrupt
;
827 process_reading(rtc_t
, &sys_time
);
830 measurement_period
= LOWEST_MEASUREMENT_PERIOD
;
831 } else if (n_samples
< 6) {
832 measurement_period
= LOWEST_MEASUREMENT_PERIOD
<< 1;
833 } else if (n_samples
< 10) {
834 measurement_period
= LOWEST_MEASUREMENT_PERIOD
<< 2;
835 } else if (n_samples
< 14) {
836 measurement_period
= LOWEST_MEASUREMENT_PERIOD
<< 3;
838 measurement_period
= LOWEST_MEASUREMENT_PERIOD
<< 4;
845 switch (operating_mode
) {
848 DEBUG_LOG("Could not complete initial step due to errors");
849 operating_mode
= OM_NORMAL
;
850 (after_init_hook
)(after_init_hook_arg
);
852 switch_interrupts(0);
854 timeout_id
= SCH_AddTimeoutByDelay((double) measurement_period
, measurement_timeout
, NULL
);
861 DEBUG_LOG("Could not complete after trim relock due to errors");
862 operating_mode
= OM_NORMAL
;
864 switch_interrupts(0);
866 timeout_id
= SCH_AddTimeoutByDelay((double) measurement_period
, measurement_timeout
, NULL
);
872 switch_interrupts(0);
874 timeout_id
= SCH_AddTimeoutByDelay((double) measurement_period
, measurement_timeout
, NULL
);
884 /* ================================================== */
887 RTC_Linux_TimeInit(void (*after_hook
)(void *), void *anything
)
889 after_init_hook
= after_hook
;
890 after_init_hook_arg
= anything
;
892 operating_mode
= OM_INITIAL
;
894 switch_interrupts(1);
897 /* ================================================== */
900 RTC_Linux_StartMeasurements(void)
902 measurement_timeout(NULL
);
905 /* ================================================== */
908 RTC_Linux_WriteParameters(void)
917 retval
= write_coefs_to_file(1,coef_ref_time
, coef_seconds_fast
, coef_gain_rate
);
919 /* Don't change the existing file, it may not be 100% valid but is our
920 current best guess. */
921 retval
= RTC_ST_OK
; /*write_coefs_to_file(0,0,0.0,0.0); */
927 /* ================================================== */
928 /* Try to set the system clock from the RTC, in the same manner as
929 /sbin/hwclock -s would do. We're not as picky about OS version
930 etc in this case, since we have fewer requirements regarding the
931 RTC behaviour than we do for the rest of the module. */
934 RTC_Linux_TimePreInit(time_t driftfile_time
)
937 struct rtc_time rtc_raw
, rtc_raw_retry
;
940 double accumulated_error
, sys_offset
;
941 struct timespec new_sys_time
, old_sys_time
;
943 coefs_file_name
= CNF_GetRtcFile();
946 read_coefs_from_file();
948 fd
= open(CNF_GetRtcDevice(), O_RDONLY
);
951 return 0; /* Can't open it, and won't be able to later */
954 /* Retry reading the rtc until both read attempts give the same sec value.
955 This way the race condition is prevented that the RTC has updated itself
956 during the first read operation. */
958 status
= ioctl(fd
, RTC_RD_TIME
, &rtc_raw
);
960 status
= ioctl(fd
, RTC_RD_TIME
, &rtc_raw_retry
);
962 } while (status
>= 0 && rtc_raw
.tm_sec
!= rtc_raw_retry
.tm_sec
);
964 /* Read system clock */
965 LCL_ReadCookedTime(&old_sys_time
, NULL
);
970 /* Convert to seconds since 1970 */
971 rtc_tm
.tm_sec
= rtc_raw
.tm_sec
;
972 rtc_tm
.tm_min
= rtc_raw
.tm_min
;
973 rtc_tm
.tm_hour
= rtc_raw
.tm_hour
;
974 rtc_tm
.tm_mday
= rtc_raw
.tm_mday
;
975 rtc_tm
.tm_mon
= rtc_raw
.tm_mon
;
976 rtc_tm
.tm_year
= rtc_raw
.tm_year
;
978 rtc_t
= t_from_rtc(&rtc_tm
);
980 if (rtc_t
!= (time_t)(-1)) {
982 /* Work out approximatation to correct time (to about the
984 if (valid_coefs_from_file
) {
985 accumulated_error
= file_ref_offset
+
986 (rtc_t
- file_ref_time
) * 1.0e-6 * file_rate_ppm
;
988 accumulated_error
= 0.0;
993 new_sys_time
.tv_sec
= rtc_t
;
994 /* Average error in the RTC reading */
995 new_sys_time
.tv_nsec
= 500000000;
997 UTI_AddDoubleToTimespec(&new_sys_time
, -accumulated_error
, &new_sys_time
);
999 if (new_sys_time
.tv_sec
< driftfile_time
) {
1000 LOG(LOGS_WARN
, "RTC time before last driftfile modification (ignored)");
1004 sys_offset
= UTI_DiffTimespecsToDouble(&old_sys_time
, &new_sys_time
);
1006 /* Set system time only if the step is larger than 1 second */
1007 if (fabs(sys_offset
) >= 1.0) {
1008 if (LCL_ApplyStepOffset(sys_offset
))
1009 LOG(LOGS_INFO
, "System time set from RTC");
1021 /* ================================================== */
1024 RTC_Linux_GetReport(RPT_RTC_Report
*report
)
1026 report
->ref_time
.tv_sec
= coef_ref_time
;
1027 report
->ref_time
.tv_nsec
= 0;
1028 report
->n_samples
= n_samples
;
1029 report
->n_runs
= n_runs
;
1030 if (n_samples
> 1) {
1031 report
->span_seconds
= ((rtc_sec
[n_samples
-1] - rtc_sec
[0]) +
1032 (long)(rtc_trim
[n_samples
-1] - rtc_trim
[0]));
1034 report
->span_seconds
= 0;
1036 report
->rtc_seconds_fast
= coef_seconds_fast
;
1037 report
->rtc_gain_rate_ppm
= 1.0e6
* coef_gain_rate
;
1041 /* ================================================== */
1044 RTC_Linux_Trim(void)
1046 struct timespec now
;
1048 /* Remember the slope coefficient - we won't be able to determine a
1049 good one in a few seconds when we determine the new offset! */
1050 saved_coef_gain_rate
= coef_gain_rate
;
1052 if (fabs(coef_seconds_fast
) > 1.0) {
1054 LOG(LOGS_INFO
, "RTC wrong by %.3f seconds (step)",
1057 /* Do processing to set clock. Let R be the value we set the
1058 RTC to, then in 500ms the RTC ticks (R+1) (see comments in
1059 arch/i386/kernel/time.c about the behaviour of the real time
1060 clock chip). If S is the system time now, the error at the
1061 next RTC tick is given by E = (R+1) - (S+0.5). Ideally we
1062 want |E| <= 0.5, which implies R <= S <= R+1, i.e. R is just
1063 the rounded down part of S, i.e. the seconds part. */
1065 LCL_ReadCookedTime(&now
, NULL
);
1067 set_rtc(now
.tv_sec
);
1069 /* All old samples will now look bogus under the new
1072 operating_mode
= OM_AFTERTRIM
;
1074 /* Estimate the offset in case writertc is called or chronyd
1075 is terminated during rapid sampling */
1076 coef_seconds_fast
= -now
.tv_nsec
/ 1.0e9
+ 0.5;
1077 coef_ref_time
= now
.tv_sec
;
1079 /* And start rapid sampling, interrupts on now */
1080 SCH_RemoveTimeout(timeout_id
);
1082 switch_interrupts(1);