[PATCH] Add support for temperature compensation

[ Thread Index | Date Index | More chrony.tuxfamily.org/chrony-dev Archives ]


File used to read temperatures, update interval and compensation
coefficients are specified with new tempcomp directive. The frequency
corrections are applied in local module and are invisible in upper
layers.
---
 Makefile.in |    2 +-
 conf.c      |   61 +++++++++++++++++++++++++++++++++++
 conf.h      |    3 ++
 local.c     |   35 ++++++++++++++++++--
 local.h     |    6 +++
 logging.c   |    2 +-
 main.c      |    3 ++
 tempcomp.c  |  101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tempcomp.h  |   29 +++++++++++++++++
 9 files changed, 236 insertions(+), 6 deletions(-)
 create mode 100644 tempcomp.c
 create mode 100644 tempcomp.h

diff --git a/Makefile.in b/Makefile.in
index 23a83fe..fd12f79 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -46,7 +46,7 @@ OBJS = util.o sched.o regress.o local.o \
 	nameserv.o acquire.o manual.o addrfilt.o \
 	cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
 	broadcast.o refclock.o refclock_shm.o refclock_sock.o \
-	refclock_pps.o
+	refclock_pps.o tempcomp.o
 
 EXTRA_OBJS=@EXTRA_OBJECTS@
 
diff --git a/conf.c b/conf.c
index 0fdf773..0fa115f 100644
--- a/conf.c
+++ b/conf.c
@@ -105,6 +105,7 @@ static void parse_linux_hz(const char *);
 static void parse_linux_freq_scale(const char *);
 static void parse_sched_priority(const char *);
 static void parse_lockall(const char *);
+static void parse_tempcomp(const char *);
 
 /* ================================================== */
 /* Configuration variables */
@@ -125,6 +126,7 @@ static int do_log_statistics = 0;
 static int do_log_tracking = 0;
 static int do_log_rtc = 0;
 static int do_log_refclocks = 0;
+static int do_log_tempcomp = 0;
 static int do_dump_on_exit = 0;
 static char *logdir = ".";
 static char *dumpdir = ".";
@@ -183,6 +185,11 @@ static IPAddr bind_cmd_address4, bind_cmd_address6;
  * chronyds being started. */
 static char *pidfile = "/var/run/chronyd.pid";
 
+/* Temperature sensor, update interval and compensation coefficients */
+static char *tempcomp_file = NULL;
+static double tempcomp_interval;
+static double tempcomp_T0, tempcomp_k0, tempcomp_k1, tempcomp_k2;
+
 /* Boolean for whether the Linux HZ value has been overridden, and the
  * new value. */
 static int set_linux_hz = 0;
@@ -239,6 +246,7 @@ static const Command commands[] = {
   {"rtcdevice", 9, parse_rtcdevice},
   {"pidfile", 7, parse_pidfile},
   {"broadcast", 9, parse_broadcast},
+  {"tempcomp", 8, parse_tempcomp},
   {"linux_hz", 8, parse_linux_hz},
   {"linux_freq_scale", 16, parse_linux_freq_scale},
   {"sched_priority", 14, parse_sched_priority},
@@ -679,6 +687,9 @@ parse_log(const char *line)
       } else if (!strncmp(line, "refclocks", 9)) {
         do_log_refclocks = 1;
         line += 9;
+      } else if (!strncmp(line, "tempcomp", 8)) {
+        do_log_tempcomp = 1;
+        line += 8;
       } else {
         break;
       }
@@ -1115,6 +1126,34 @@ parse_broadcast(const char *line)
 /* ================================================== */
 
 static void
+parse_tempcomp(const char *line)
+{
+  const char *tmp;
+
+  while (isspace(line[0]))
+    line++;
+  tmp = line;
+  while (line[0] != '\0' && !isspace(line[0]))
+    line++;
+
+  if (line == tmp) {
+    LOG(LOGS_WARN, LOGF_Configure, "Could not read tempcomp filename at line %d", line_number);
+    return;
+  }
+
+  if (sscanf(line, "%lf %lf %lf %lf %lf", &tempcomp_interval, &tempcomp_T0, &tempcomp_k0, &tempcomp_k1, &tempcomp_k2) != 5) {
+    LOG(LOGS_WARN, LOGF_Configure, "Could not read tempcomp interval or coefficients at line %d", line_number);
+    return;
+  }
+
+  tempcomp_file = MallocArray(char, 1 + line - tmp);
+  strncpy(tempcomp_file, tmp, line - tmp);
+  tempcomp_file[line - tmp] = '\0';
+}
+
+/* ================================================== */
+
+static void
 parse_linux_hz(const char *line)
 {
   if (1 == sscanf(line, "%d", &linux_hz)) {
@@ -1273,6 +1312,7 @@ CNF_GetLogRtc(void)
 }
 
 /* ================================================== */
+
 int
 CNF_GetLogRefclocks(void)
 {
@@ -1281,6 +1321,14 @@ CNF_GetLogRefclocks(void)
 
 /* ================================================== */
 
+int
+CNF_GetLogTempComp(void)
+{
+  return do_log_tempcomp;
+}
+
+/* ================================================== */
+
 char *
 CNF_GetKeysFile(void)
 {
@@ -1514,3 +1562,16 @@ CNF_GetLockMemory(void)
 {
   return lock_memory;
 }
+
+/* ================================================== */
+
+void
+CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2)
+{
+  *file = tempcomp_file;
+  *interval = tempcomp_interval;
+  *T0 = tempcomp_T0;
+  *k0 = tempcomp_k0;
+  *k1 = tempcomp_k1;
+  *k2 = tempcomp_k2;
+}
diff --git a/conf.h b/conf.h
index 1ec99f2..31f4cf0 100644
--- a/conf.h
+++ b/conf.h
@@ -53,6 +53,7 @@ extern int CNF_GetLogStatistics(void);
 extern int CNF_GetLogTracking(void);
 extern int CNF_GetLogRtc(void);
 extern int CNF_GetLogRefclocks(void);
+extern int CNF_GetLogTempComp(void);
 extern char *CNF_GetKeysFile(void);
 extern char *CNF_GetRtcFile(void);
 extern unsigned long CNF_GetCommandKey(void);
@@ -81,4 +82,6 @@ extern void CNF_SetupAccessRestrictions(void);
 extern int CNF_GetSchedPriority(void);
 extern int CNF_GetLockMemory(void);
 
+extern void CNF_GetTempComp(char **file, double *interval, double *T0, double *k0, double *k1, double *k2);
+
 #endif /* GOT_CONF_H */
diff --git a/local.c b/local.c
index 1be6117..c1fb158 100644
--- a/local.c
+++ b/local.c
@@ -45,6 +45,9 @@
 /* Variable to store the current frequency, in ppm */
 static double current_freq_ppm;
 
+/* Temperature compensation, in ppm */
+static double temp_comp_ppm;
+
 /* ================================================== */
 /* Store the system dependent drivers */
 
@@ -152,6 +155,7 @@ LCL_Initialise(void)
 
   /* This ought to be set from the system driver layer */
   current_freq_ppm = 0.0;
+  temp_comp_ppm = 0.0;
 
   calculate_sys_precision();
 }
@@ -360,7 +364,7 @@ LCL_GetOffsetCorrection(struct timeval *raw, double *correction, double *err)
 double
 LCL_ReadAbsoluteFrequency(void)
 {
-  return (*drv_read_freq)();
+  return (*drv_read_freq)() + temp_comp_ppm;
 }
 
 /* ================================================== */
@@ -376,7 +380,7 @@ LCL_SetAbsoluteFrequency(double afreq_ppm)
   
   /* Call the system-specific driver for setting the frequency */
   
-  (*drv_set_freq)(afreq_ppm);
+  (*drv_set_freq)(afreq_ppm - temp_comp_ppm);
 
   dfreq = 1.0e-6 * (afreq_ppm - current_freq_ppm) / (1.0 - 1.0e-6 * current_freq_ppm);
 
@@ -408,7 +412,7 @@ LCL_AccumulateDeltaFrequency(double dfreq)
     (1.0e6 * dfreq);
 
   /* Call the system-specific driver for setting the frequency */
-  (*drv_set_freq)(current_freq_ppm);
+  (*drv_set_freq)(current_freq_ppm - temp_comp_ppm);
 
   LCL_ReadRawTime(&raw);
   LCL_CookTime(&raw, &cooked, NULL);
@@ -494,7 +498,7 @@ LCL_AccumulateFrequencyAndOffset(double dfreq, double doffset)
 #endif
 
   /* Call the system-specific driver for setting the frequency */
-  (*drv_set_freq)(current_freq_ppm);
+  (*drv_set_freq)(current_freq_ppm - temp_comp_ppm);
   (*drv_accrue_offset)(doffset);
 
   /* Dispatch to all handlers */
@@ -582,3 +586,26 @@ LCL_SetLeap(int leap)
 }
 
 /* ================================================== */
+
+void
+LCL_SetTempComp(double freq)
+{
+  if (temp_comp_ppm == freq)
+    return;
+
+  temp_comp_ppm = freq;
+  /* Call the system-specific driver for setting the frequency */
+  (*drv_set_freq)(current_freq_ppm - temp_comp_ppm);
+
+  return;
+}
+
+/* ================================================== */
+
+double
+LCL_GetTempComp(void)
+{
+  return temp_comp_ppm;
+}
+
+/* ================================================== */
diff --git a/local.h b/local.h
index bef1a3e..55f60e7 100644
--- a/local.h
+++ b/local.h
@@ -188,4 +188,10 @@ extern int LCL_MakeStep(double threshold);
    and zero cancels scheduled leap second. */
 extern void LCL_SetLeap(int leap);
 
+/* Routine to set a frequency correction (in ppm) that should be substracted
+   from clock frequency to compensate for temperature changes. */
+extern void LCL_SetTempComp(double freq);
+
+extern double LCL_GetTempComp(void);
+
 #endif /* GOT_LOCAL_H */
diff --git a/logging.c b/logging.c
index 8271c00..a2f471e 100644
--- a/logging.c
+++ b/logging.c
@@ -58,7 +58,7 @@ struct LogFile {
 static int n_filelogs = 0;
 
 /* Increase this when adding a new logfile */
-#define MAX_FILELOGS 5
+#define MAX_FILELOGS 6
 
 static struct LogFile logfiles[MAX_FILELOGS];
 
diff --git a/main.c b/main.c
index 31f4a5c..7da6250 100644
--- a/main.c
+++ b/main.c
@@ -53,6 +53,7 @@
 #include "clientlog.h"
 #include "broadcast.h"
 #include "nameserv.h"
+#include "tempcomp.h"
 
 /* ================================================== */
 
@@ -86,6 +87,7 @@ MAI_CleanupAndExit(void)
     SRC_DumpSources();
   }
 
+  TMC_Finalise();
   MNL_Finalise();
   ACQ_Finalise();
   KEY_Finalise();
@@ -326,6 +328,7 @@ int main
   KEY_Initialise();
   ACQ_Initialise();
   MNL_Initialise();
+  TMC_Initialise();
 
   LOG_CreateLogFileDir();
 
diff --git a/tempcomp.c b/tempcomp.c
new file mode 100644
index 0000000..d7f02ad
--- /dev/null
+++ b/tempcomp.c
@@ -0,0 +1,101 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2010
+ * 
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Routines implementing temperature compensation.
+
+  */
+
+#include "conf.h"
+#include "local.h"
+#include "memory.h"
+#include "util.h"
+#include "logging.h"
+#include "sched.h"
+#include "tempcomp.h"
+
+static SCH_TimeoutID timeout_id;
+
+static LOG_FileID logfileid;
+
+static char *filename;
+static double update_interval;
+static double T0, k0, k1, k2;
+
+static void
+read_timeout(void *arg)
+{
+  FILE *f;
+  double temp, comp;
+
+  f = fopen(filename, "r");
+
+  if (f && fscanf(f, "%lf", &temp) == 1) {
+    comp = k0 + (temp - T0) * k1 + (temp - T0) * (temp - T0) * k2;
+
+    /* Don't allow corrections above 10 ppm */
+    if (fabs(comp) < 10.0) {
+      LCL_SetTempComp(comp);
+
+      if (logfileid != -1) {
+        struct timeval now;
+
+        LCL_ReadCookedTime(&now, NULL);
+        LOG_FileWrite(logfileid, "%s %11.4e %11.4e",
+            UTI_TimeToLogForm(now.tv_sec), temp, comp);
+      }
+    }
+  }
+
+  if (f)
+    fclose(f);
+
+  timeout_id = SCH_AddTimeoutByDelay(update_interval, read_timeout, NULL);
+}
+
+void
+TMC_Initialise(void)
+{
+  CNF_GetTempComp(&filename, &update_interval, &T0, &k0, &k1, &k2);
+
+  if (filename == NULL)
+    return;
+
+  if (update_interval <= 0.0)
+    update_interval = 1.0;
+
+  logfileid = CNF_GetLogTempComp() ? LOG_FileOpen("tempcomp",
+      "   Date (UTC) Time        Temp.       Comp.")
+    : -1;
+
+  read_timeout(NULL);
+}
+
+void
+TMC_Finalise(void)
+{
+  if (filename == NULL)
+    return;
+
+  SCH_RemoveTimeout(timeout_id);
+  Free(filename);
+}
diff --git a/tempcomp.h b/tempcomp.h
new file mode 100644
index 0000000..de65469
--- /dev/null
+++ b/tempcomp.h
@@ -0,0 +1,29 @@
+/*
+  chronyd/chronyc - Programs for keeping computer clocks accurate.
+
+ **********************************************************************
+ * Copyright (C) Miroslav Lichvar  2010
+ * 
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ **********************************************************************
+
+  =======================================================================
+
+  Header file for temperature compensation.
+
+  */
+
+extern void TMC_Initialise(void);
+extern void TMC_Finalise(void);
-- 
1.6.6.1


--ZGiS0Q5IWpPtfppv--

---
To unsubscribe email chrony-dev-request@xxxxxxxxxxxxxxxxxxxx with "unsubscribe" in the subject.
For help email chrony-dev-request@xxxxxxxxxxxxxxxxxxxx with "help" in the subject.
Trouble?  Email listmaster@xxxxxxxxxxxxxxxxxxxx.


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/