1 /*
2   chronyd/chronyc - Programs for keeping computer clocks accurate.
3 
4  **********************************************************************
5  * Copyright (C) Miroslav Lichvar  2017
6  *
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.
10  *
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.
15  *
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.
19  *
20  **********************************************************************
21 
22   =======================================================================
23 
24   Null clock driver for operation with no clock control.
25   */
26 
27 #include "config.h"
28 
29 #include "sysincl.h"
30 
31 #include "sys_null.h"
32 
33 #include "local.h"
34 #include "localp.h"
35 #include "logging.h"
36 #include "util.h"
37 
38 /* Current frequency offset of the system clock (in ppm) */
39 static double freq;
40 
41 /* Offset of the system clock at the last update */
42 static double offset_register;
43 
44 /* Time of the last update */
45 static struct timespec last_update;
46 
47 /* Minimum interval between updates when frequency is constant */
48 #define MIN_UPDATE_INTERVAL 1000.0
49 
50 /* ================================================== */
51 
52 static void
update_offset(void)53 update_offset(void)
54 {
55   struct timespec now;
56   double duration;
57 
58   LCL_ReadRawTime(&now);
59   duration = UTI_DiffTimespecsToDouble(&now, &last_update);
60   offset_register += 1.0e-6 * freq * duration;
61   last_update = now;
62 
63   DEBUG_LOG("System clock offset=%e freq=%f", offset_register, freq);
64 }
65 
66 /* ================================================== */
67 
68 static double
read_frequency(void)69 read_frequency(void)
70 {
71   return freq;
72 }
73 
74 /* ================================================== */
75 
76 static double
set_frequency(double freq_ppm)77 set_frequency(double freq_ppm)
78 {
79   update_offset();
80   freq = freq_ppm;
81 
82   return freq;
83 }
84 
85 /* ================================================== */
86 
87 static void
accrue_offset(double offset,double corr_rate)88 accrue_offset(double offset, double corr_rate)
89 {
90   offset_register += offset;
91 }
92 
93 /* ================================================== */
94 
95 static int
apply_step_offset(double offset)96 apply_step_offset(double offset)
97 {
98   return 0;
99 }
100 
101 /* ================================================== */
102 
103 static void
offset_convert(struct timespec * raw,double * corr,double * err)104 offset_convert(struct timespec *raw, double *corr, double *err)
105 {
106   double duration;
107 
108   duration = UTI_DiffTimespecsToDouble(raw, &last_update);
109 
110   if (duration > MIN_UPDATE_INTERVAL) {
111     update_offset();
112     duration = 0.0;
113   }
114 
115   *corr = -1.0e-6 * freq * duration - offset_register;
116 
117   if (err)
118     *err = 0.0;
119 }
120 
121 /* ================================================== */
122 
123 void
SYS_Null_Initialise(void)124 SYS_Null_Initialise(void)
125 {
126   offset_register = 0.0;
127   LCL_ReadRawTime(&last_update);
128 
129   lcl_RegisterSystemDrivers(read_frequency, set_frequency, accrue_offset,
130                             apply_step_offset, offset_convert, NULL, NULL);
131 
132   LOG(LOGS_INFO, "Disabled control of system clock");
133 }
134 
135 /* ================================================== */
136 
137 void
SYS_Null_Finalise(void)138 SYS_Null_Finalise(void)
139 {
140 }
141