]> git.ipfire.org Git - thirdparty/chrony.git/blame - tempcomp.c
examples: harden systemd services
[thirdparty/chrony.git] / tempcomp.c
CommitLineData
c386d117
ML
1/*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
cb74f3e7 5 * Copyright (C) Miroslav Lichvar 2011, 2014
c386d117
ML
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 Routines implementing temperature compensation.
25
26 */
27
da2c8d90
ML
28#include "config.h"
29
ed862c8d 30#include "array.h"
c386d117
ML
31#include "conf.h"
32#include "local.h"
33#include "memory.h"
34#include "util.h"
35#include "logging.h"
36#include "sched.h"
37#include "tempcomp.h"
38
0a56c0e8
ML
39/* Sanity limit (in ppm) */
40#define MAX_COMP 10.0
41
c386d117
ML
42static SCH_TimeoutID timeout_id;
43
44static LOG_FileID logfileid;
45
46static char *filename;
47static double update_interval;
48static double T0, k0, k1, k2;
49
ed862c8d
ML
50struct Point {
51 double temp;
52 double comp;
53};
54
55static ARR_Instance points;
56
57static double
58get_tempcomp(double temp)
59{
60 unsigned int i;
61 struct Point *p1 = NULL, *p2 = NULL;
62
63 /* If not configured with points, calculate the compensation from the
64 specified quadratic function */
65 if (!points)
66 return k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
67
68 /* Otherwise interpolate/extrapolate between two nearest points */
69
70 for (i = 1; i < ARR_GetSize(points); i++) {
71 p2 = (struct Point *)ARR_GetElement(points, i);
72 if (p2->temp >= temp)
73 break;
74 }
75 p1 = p2 - 1;
76
77 return (temp - p1->temp) / (p2->temp - p1->temp) *
78 (p2->comp - p1->comp) + p1->comp;
79}
80
c386d117
ML
81static void
82read_timeout(void *arg)
83{
84 FILE *f;
85 double temp, comp;
86
e18903a6 87 f = UTI_OpenFile(NULL, filename, NULL, 'r', 0);
c386d117
ML
88
89 if (f && fscanf(f, "%lf", &temp) == 1) {
ed862c8d 90 comp = get_tempcomp(temp);
c386d117 91
0a56c0e8 92 if (fabs(comp) <= MAX_COMP) {
1a7415a6 93 comp = LCL_SetTempComp(comp);
c386d117 94
f282856c 95 DEBUG_LOG("tempcomp updated to %f for %f", comp, temp);
ed862c8d 96
c386d117 97 if (logfileid != -1) {
d0dfa1de 98 struct timespec now;
c386d117
ML
99
100 LCL_ReadCookedTime(&now, NULL);
101 LOG_FileWrite(logfileid, "%s %11.4e %11.4e",
102 UTI_TimeToLogForm(now.tv_sec), temp, comp);
103 }
7a512ad9 104 } else {
f282856c 105 LOG(LOGS_WARN, "Temperature compensation of %.3f ppm exceeds sanity limit of %.1f",
7a512ad9 106 comp, MAX_COMP);
c386d117 107 }
7a512ad9 108 } else {
f282856c 109 LOG(LOGS_WARN, "Could not read temperature from %s", filename);
c386d117
ML
110 }
111
112 if (f)
113 fclose(f);
114
115 timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL);
116}
117
ed862c8d
ML
118static void
119read_points(const char *filename)
120{
121 FILE *f;
122 char line[256];
123 struct Point *p;
124
e18903a6 125 f = UTI_OpenFile(NULL, filename, NULL, 'R', 0);
ed862c8d
ML
126
127 points = ARR_CreateInstance(sizeof (struct Point));
128
129 while (fgets(line, sizeof (line), f)) {
130 p = (struct Point *)ARR_GetNewElement(points);
131 if (sscanf(line, "%lf %lf", &p->temp, &p->comp) != 2) {
f282856c 132 LOG_FATAL("Could not read tempcomp point from %s", filename);
ed862c8d
ML
133 break;
134 }
135 }
136
137 fclose(f);
138
139 if (ARR_GetSize(points) < 2)
f282856c 140 LOG_FATAL("Not enough points in %s", filename);
ed862c8d
ML
141}
142
c386d117
ML
143void
144TMC_Initialise(void)
145{
ed862c8d
ML
146 char *point_file;
147
148 CNF_GetTempComp(&filename, &update_interval, &point_file, &T0, &k0, &k1, &k2);
c386d117
ML
149
150 if (filename == NULL)
151 return;
152
153 if (update_interval <= 0.0)
154 update_interval = 1.0;
155
ed862c8d
ML
156 if (point_file)
157 read_points(point_file);
158
c386d117
ML
159 logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
160 " Date (UTC) Time Temp. Comp.")
161 : -1;
162
163 read_timeout(NULL);
164}
165
166void
167TMC_Finalise(void)
168{
169 if (filename == NULL)
170 return;
171
ed862c8d
ML
172 if (points)
173 ARR_DestroyInstance(points);
174
c386d117 175 SCH_RemoveTimeout(timeout_id);
c386d117 176}