]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
tvhtime: start adding time processing support to TVH
authorAdam Sutton <dev@adamsutton.me.uk>
Thu, 7 Feb 2013 14:26:23 +0000 (14:26 +0000)
committerAdam Sutton <dev@adamsutton.me.uk>
Fri, 15 Feb 2013 10:24:41 +0000 (10:24 +0000)
Makefile
src/dvb/dvb_tables.c
src/tvhtime.c [new file with mode: 0644]
src/tvhtime.h [new file with mode: 0644]
src/webui/extjs.c
src/webui/static/app/config.js

index cd011db208d44035d789f4d852eadcac9f6186d4..cd79dad8ca998c72a05af246e1c6b317c42353c0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -109,7 +109,8 @@ SRCS =  src/main.c \
   src/config2.c \
   src/lang_codes.c \
   src/lang_str.c \
-  src/imagecache.c
+  src/imagecache.c \
+  src/tvhtime.c
 
 SRCS += src/epggrab/module.c\
   src/epggrab/channel.c\
index 2dbe5474f2e42949e5eb48fa934162b2d00f4c65..18d6d7ad345e1372b29aeb576ca75b015b3b201f 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <time.h>
 
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/dmx.h>
@@ -41,6 +42,7 @@
 #include "psi.h"
 #include "notify.h"
 #include "cwc.h"
+#include "tvhtime.h"
 
 #if TDT_TRACE
 #define TRACE(_pre, _fmt, ...)\
@@ -1074,6 +1076,54 @@ dvb_pmt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len,
   return 0;
 }
 
+/*
+ * Time Offset table handler
+ */
+static int
+dvb_tot_callback(th_dvb_mux_instance_t *tdmi, uint8_t *buf, int len,
+    uint8_t tableid, void *opaque)
+{
+  uint16_t mjd;
+  uint8_t hour, min, sec;
+  int year, mon, day;
+  struct tm utc;
+
+  if (tableid != 0x73)
+    return -1;
+
+  /* DVB format MJD, Hour, Min, Sec */
+  mjd  = (buf[0] << 8) | buf[1];
+  hour = bcdtoint(buf[2]);
+  min  = bcdtoint(buf[3]);
+  sec  = bcdtoint(buf[4]);
+
+  /* Convert MJD (using algo from EN 300 468 v1.13.1 Annex C) */
+  year = (int)((mjd - 15078.2) / 365.25);
+  mon  = (int)((mjd - 14956.1 - (int)(year * 365.25)) / 30.6001);
+  day  = mjd - 14956 - (int)(year * 365.25) - (int)(mon * 30.6001);
+  if (mon == 14 || mon == 15) {
+    year++;
+    mon -= 12;
+  }
+  mon--;
+
+  tvhlog(LOG_DEBUG, "tdt-tot", "time is %04d/%02d/%02d %02d:%02d:%02d",
+         year+1900, mon, day, hour, min, sec);
+
+  /* Convert to UTC time_t */
+  utc.tm_wday  = 0;
+  utc.tm_yday  = 0;
+  utc.tm_isdst = 0;
+  utc.tm_year  = year;
+  utc.tm_mon   = mon - 1;
+  utc.tm_mday  = day;
+  utc.tm_hour  = hour;
+  utc.tm_min   = min;
+  utc.tm_sec   = sec;
+  tvhtime_update(&utc);
+
+  return 0;
+}
 
 /**
  * Demux for default DVB tables that we want
@@ -1097,6 +1147,10 @@ dvb_table_add_default_dvb(th_dvb_mux_instance_t *tdmi)
 
   tdt_add(tdmi, 0, 0, dvb_pidx11_callback, NULL, "pidx11", 
          TDT_QUICKREQ | TDT_CRC, 0x11);
+
+  /* Time Offset Table */
+
+  tdt_add(tdmi, 0, 0, dvb_tot_callback, NULL, "tot", TDT_CRC, 0x14);
 }
 
 
diff --git a/src/tvhtime.c b/src/tvhtime.c
new file mode 100644 (file)
index 0000000..66c55b8
--- /dev/null
@@ -0,0 +1,160 @@
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "tvhtime.h"
+#include "tvheadend.h"
+#include "settings.h"
+
+uint32_t tvhtime_update_enabled;
+uint32_t tvhtime_ntp_enabled;
+uint32_t tvhtime_tolerance;
+
+/*
+ * NTP processing
+ */
+#define NTPD_BASE      0x4e545030      /* "NTP0" */
+#define NTPD_UNIT      2
+
+typedef struct
+{
+  int    mode; /* 0 - if valid set
+                                       *       use values, 
+                                       *       clear valid
+                                       * 1 - if valid set 
+                                       *       if count before and after read of values is equal,
+                                       *         use values 
+                                       *       clear valid
+                                       */
+  int    count;
+  time_t clockTimeStampSec;
+  int    clockTimeStampUSec;
+  time_t receiveTimeStampSec;
+  int    receiveTimeStampUSec;
+  int    leap;
+  int    precision;
+  int    nsamples;
+  int    valid;
+  int    pad[10];
+} ntp_shm_t;
+
+static ntp_shm_t *
+ntp_shm_init ( void )
+{
+  int shmid, unit, mode;
+  static ntp_shm_t *shmptr = NULL;
+
+  if (shmptr != NULL)
+    return shmptr;
+
+  unit = getuid() ? 2 : 0;
+  mode = getuid() ? 0666 : 0600;
+
+  shmid = shmget((key_t)NTPD_BASE + unit, sizeof(ntp_shm_t), IPC_CREAT | mode);
+  if (shmid == -1)
+    return NULL;
+
+  shmptr = shmat(shmid, 0, 0);
+  memset(shmptr, 0, sizeof(ntp_shm_t));
+  if (shmptr) {
+    shmptr->mode      = 1;
+    shmptr->precision = -1;
+    shmptr->nsamples  = 1;
+  }
+
+  return shmptr;
+}
+
+/*
+ * Update time
+ */
+void
+tvhtime_update ( struct tm *tm )
+{
+  time_t now;
+  struct timeval tv;
+  ntp_shm_t *ntp_shm;
+  int64_t t1, t2;
+
+  /* Current and reported time */
+  now = mktime(tm);
+  gettimeofday(&tv, NULL);
+
+  /* Delta */
+  t1 = now * 1000000;
+  t2 = tv.tv_sec * 1000000 + tv.tv_usec;
+#if NTP_TRACE
+  tvhlog(LOG_DEBUG, "ntp", "delta = %"PRId64" us\n", t2 - t1);
+#endif
+
+  /* Update local clock */
+  if (tvhtime_update_enabled)
+    if (llabs(t2 - t1) > tvhtime_tolerance)
+      stime(&now);
+
+  /* NTP */
+  if (tvhtime_ntp_enabled) {
+    if (!(ntp_shm = ntp_shm_init()))
+      return;
+
+    ntp_shm->valid = 0;
+    ntp_shm->count++;
+    ntp_shm->clockTimeStampSec    = now;
+    ntp_shm->clockTimeStampUSec   = 0;
+    ntp_shm->receiveTimeStampSec  = tv.tv_sec;
+    ntp_shm->receiveTimeStampUSec = (int)tv.tv_usec;
+    ntp_shm->count++;
+    ntp_shm->valid = 1;
+  }
+}
+
+/* Initialise */
+void tvhtime_init ( void )
+{
+  htsmsg_t *m = hts_settings_load("tvhtime/config");
+  if (htsmsg_get_u32(m, "update_enabled", &tvhtime_update_enabled))
+    tvhtime_update_enabled = 0;
+  if (htsmsg_get_u32(m, "ntp_enabled", &tvhtime_ntp_enabled))
+    tvhtime_ntp_enabled = 0;
+  if (htsmsg_get_u32(m, "tolerance", &tvhtime_tolerance))
+    tvhtime_tolerance = 5000;
+}
+
+static void tvhtime_save ( void )
+{
+  htsmsg_t *m = htsmsg_create_map();
+  htsmsg_add_u32(m, "update_enabled", tvhtime_update_enabled);
+  htsmsg_add_u32(m, "ntp_enabled", tvhtime_ntp_enabled);
+  htsmsg_add_u32(m, "tolerance", tvhtime_tolerance);
+  hts_settings_save(m, "tvhtime/config");
+}
+
+void tvhtime_set_update_enabled ( uint32_t on )
+{
+  if (tvhtime_update_enabled == on)
+    return;
+  tvhtime_update_enabled = on;
+  tvhtime_save();
+}
+
+void tvhtime_set_ntp_enabled ( uint32_t on )
+{
+  if (tvhtime_ntp_enabled == on)
+    return;
+  tvhtime_ntp_enabled = on;
+  tvhtime_save();
+}
+
+void tvhtime_set_tolerance ( uint32_t v )
+{
+  if (tvhtime_tolerance == v)
+    return;
+  tvhtime_tolerance = v;
+  tvhtime_save();
+}
diff --git a/src/tvhtime.h b/src/tvhtime.h
new file mode 100644 (file)
index 0000000..3829ce5
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *  TVheadend - time processing
+ *
+ *  Copyright (C) 2013 Adam Sutton
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TVH_TIME_H__
+#define __TVH_TIME_H_
+
+extern uint32_t tvhtime_update_enabled;
+extern uint32_t tvhtime_ntp_enabled;
+extern uint32_t tvhtime_tolerance;
+
+void tvhtime_init ( void );
+void tvhtime_update ( struct tm *now );
+
+void tvhtime_set_update_enabled ( uint32_t on );
+void tvhtime_set_ntp_enabled ( uint32_t on );
+void tvhtime_set_tolerance ( uint32_t v );
+
+#endif /* __TVH_TIME_H__ */
index c11ec87ae353179e884ff4d9196809bebac0e4f8..45ecfed10c70334095a3ff67bfcc354be5f2a73b 100644 (file)
@@ -49,6 +49,7 @@
 #include "subscriptions.h"
 #include "imagecache.h"
 #include "timeshift.h"
+#include "tvhtime.h"
 
 /**
  *
@@ -1974,6 +1975,12 @@ extjs_config(http_connection_t *hc, const char *remain, void *opaque)
     /* Misc */
     pthread_mutex_lock(&global_lock);
     m = config_get_all();
+
+    /* Time */
+    htsmsg_add_u32(m, "tvhtime_update_enabled", tvhtime_update_enabled);
+    htsmsg_add_u32(m, "tvhtime_ntp_enabled", tvhtime_ntp_enabled);
+    htsmsg_add_u32(m, "tvhtime_tolerance", tvhtime_tolerance);
+
     pthread_mutex_unlock(&global_lock);
 
     /* Image cache */
@@ -2001,6 +2008,15 @@ extjs_config(http_connection_t *hc, const char *remain, void *opaque)
       save |= config_set_language(str);
     if (save)
       config_save();
+
+    /* Time */
+    if ((str = http_arg_get(&hc->hc_req_args, "tvhtime_update_enabled")))
+      tvhtime_set_update_enabled(!!str);
+    if ((str = http_arg_get(&hc->hc_req_args, "tvhtime_ntp_enabled")))
+      tvhtime_set_ntp_enabled(!!str);
+    if ((str = http_arg_get(&hc->hc_req_args, "tvhtime_tolerance")))
+      tvhtime_set_tolerance(atoi(str));
+
     pthread_mutex_unlock(&global_lock);
   
     /* Image Cache */
index 183b8eef6a9b22150a94d803483b828dc692459e..a7d84bbb70e5a00c49fd0546bc38c84f4a71b203 100644 (file)
@@ -39,7 +39,9 @@ tvheadend.miscconf = function() {
                root : 'config'
        }, [ 'muxconfpath', 'language',
        'imagecache_enabled', 'imagecache_ok_period',
-       'imagecache_fail_period', 'imagecache_ignore_sslcert']);
+       'imagecache_fail_period', 'imagecache_ignore_sslcert',
+       'tvhtime_update_enabled', 'tvhtime_ntp_enabled',
+       'tvhtime_tolerance']);
 
        /* ****************************************************************
         * Form Fields
@@ -75,6 +77,32 @@ tvheadend.miscconf = function() {
                fromLegend: 'Available'
        });
 
+  /*
+   * Time/Date
+   */
+  var tvhtimeUpdateEnabled = new Ext.form.Checkbox({
+    name: 'tvhtime_update_enabled',
+    fieldLabel: 'Update time'
+  });
+  
+  var tvhtimeNtpEnabled = new Ext.form.Checkbox({
+    name: 'tvhtime_ntp_enabled',
+    fieldLabel: 'Enable NTP driver'
+  });
+
+  var tvhtimeTolerance = new Ext.form.NumberField({
+    name: 'tvhtime_tolerance',
+    fieldLabel: 'Update tolerance (ms)'
+  });
+
+  var tvhtimePanel = new Ext.form.FieldSet({
+    title: 'Time Update',
+    width: 700,
+    autoHeight: true,
+    collapsible: true,
+    items : [ tvhtimeUpdateEnabled, tvhtimeNtpEnabled, tvhtimeTolerance ]
+  });
+
   /*
    * Image cache
    */
@@ -140,7 +168,7 @@ tvheadend.miscconf = function() {
                defaultType : 'textfield',
                autoHeight : true,
                items : [ language, dvbscanPath,
-              imagecachePanel ],
+              imagecachePanel, tvhtimePanel ],
                tbar : [ saveButton, '->', helpButton ]
        });