summaryrefslogtreecommitdiffstats
path: root/contrib/ntp/libparse/clk_rawdcf.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/libparse/clk_rawdcf.c')
-rw-r--r--contrib/ntp/libparse/clk_rawdcf.c116
1 files changed, 103 insertions, 13 deletions
diff --git a/contrib/ntp/libparse/clk_rawdcf.c b/contrib/ntp/libparse/clk_rawdcf.c
index 132fbc3..ca43263 100644
--- a/contrib/ntp/libparse/clk_rawdcf.c
+++ b/contrib/ntp/libparse/clk_rawdcf.c
@@ -5,7 +5,7 @@
*
* Raw DCF77 pulse clock support
*
- * Copyright (c) 1995-2006 by Frank Kardel <kardel <AT> ntp.org>
+ * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org>
* Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany
*
* Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,7 @@
#if defined(REFCLOCK) && defined(CLOCK_PARSE) && defined(CLOCK_RAWDCF)
#include "ntp_fp.h"
+#include "timevalops.h"
#include "ntp_unixtime.h"
#include "ntp_calendar.h"
@@ -107,7 +108,9 @@ static parse_cvt_fnc_t cvt_rawdcf;
static parse_inp_fnc_t inp_rawdcf;
typedef struct last_tcode {
- time_t tcode; /* last converted time code */
+ time_t tcode; /* last converted time code */
+ timestamp_t tminute; /* sample time for minute start */
+ timestamp_t timeout; /* last timeout timestamp */
} last_tcode_t;
#define BUFFER_MAX 61
@@ -230,14 +233,14 @@ convert_rawdcf(
const unsigned char *c = dcfprm->zerobits;
int i;
- parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer));
+ parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%.*s\"\n", size, buffer));
if (size < 57)
{
#ifndef PARSEKERNEL
msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits", size);
#endif
- return CVT_NONE;
+ return CVT_FAIL|CVT_BADFMT;
}
for (i = 0; i < size; i++)
@@ -250,7 +253,7 @@ convert_rawdcf(
#ifndef PARSEKERNEL
msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion");
#endif
- return CVT_NONE;
+ return CVT_FAIL|CVT_BADFMT;
}
if (*b) b++;
if (*c) c++;
@@ -270,7 +273,7 @@ convert_rawdcf(
*/
parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n"));
- clock_time->flags = PARSEB_S_ANTENNA|PARSEB_S_LEAP;
+ clock_time->flags = PARSEB_S_CALLBIT|PARSEB_S_LEAP;
clock_time->utctime= 0;
clock_time->usecond= 0;
clock_time->second = 0;
@@ -310,7 +313,7 @@ convert_rawdcf(
if (ext_bf(buffer, DCF_R, dcfprm->zerobits))
clock_time->flags |= PARSEB_CALLBIT;
- parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n",
+ parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %02d:%02d, %02d.%02d.%02d, flags 0x%lx\n",
(int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year,
(u_long)clock_time->flags));
return CVT_OK;
@@ -321,7 +324,7 @@ convert_rawdcf(
* bad format - not for us
*/
#ifndef PARSEKERNEL
- msyslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"", buffer);
+ msyslog(LOG_ERR, "parse: convert_rawdcf: start bit / parity check FAILED for \"%.*s\"", size, buffer);
#endif
return CVT_FAIL|CVT_BADFMT;
}
@@ -484,6 +487,8 @@ cvt_rawdcf(
if (*c) c++;
}
+ *s = '\0';
+
if (rtc == CVT_NONE)
{
rtc = convert_rawdcf(buffer, size, &dcfparameter, clock_time);
@@ -494,13 +499,15 @@ cvt_rawdcf(
newtime = parse_to_unixtime(clock_time, &rtc);
if ((rtc == CVT_OK) && t)
{
- if ((newtime - t->tcode) == 60) /* guard against multi bit errors */
+ if ((newtime - t->tcode) <= 600) /* require a successful telegram within last 10 minutes */
{
+ parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: recent timestamp check OK\n"));
clock_time->utctime = newtime;
}
else
{
- rtc = CVT_FAIL|CVT_BADTIME;
+ parseprintf(DD_RAWDCF,("parse: cvt_rawdcf: recent timestamp check FAIL - ignore timestamp\n"));
+ rtc = CVT_SKIP;
}
t->tcode = newtime;
}
@@ -533,13 +540,63 @@ pps_rawdcf(
return CVT_NONE;
}
+static long
+calc_usecdiff(
+ timestamp_t *ref,
+ timestamp_t *base,
+ long offset
+ )
+{
+ struct timeval delta;
+ long delta_usec = 0;
+
+#ifdef PARSEKERNEL
+ delta.tv_sec = ref->tv.tv_sec - offset - base->tv.tv_sec;
+ delta.tv_usec = ref->tv.tv_usec - base->tv.tv_usec;
+ if (delta.tv_usec < 0)
+ {
+ delta.tv_sec -= 1;
+ delta.tv_usec += 1000000;
+ }
+#else
+ l_fp delt;
+
+ delt = ref->fp;
+ delt.l_i -= offset;
+ L_SUB(&delt, &base->fp);
+ TSTOTV(&delt, &delta);
+#endif
+
+ delta_usec = 1000000 * (int32_t)delta.tv_sec + delta.tv_usec;
+ return delta_usec;
+}
+
static u_long
snt_rawdcf(
parse_t *parseio,
timestamp_t *ptime
)
{
- if ((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK)
+ /*
+ * only synthesize if all of following conditions are met:
+ * - CVT_OK parse_status (we have a time stamp base)
+ * - ABS(ptime - tminute - (parse_index - 1) sec) < 500ms (spaced by 1 sec +- 500ms)
+ * - minute marker is available (confirms minute raster as base)
+ */
+ last_tcode_t *t = (last_tcode_t *)parseio->parse_pdata;
+ long delta_usec = -1;
+
+ if (t != NULL && t->tminute.tv.tv_sec != 0) {
+ delta_usec = calc_usecdiff(ptime, &t->tminute, parseio->parse_index - 1);
+ if (delta_usec < 0)
+ delta_usec = -delta_usec;
+ }
+
+ parseprintf(DD_RAWDCF,("parse: snt_rawdcf: synth for offset %d seconds - absolute usec error %ld\n",
+ parseio->parse_index - 1, delta_usec));
+
+ if (((parseio->parse_dtime.parse_status & CVT_MASK) == CVT_OK) &&
+ (delta_usec < 500000 && delta_usec >= 0)) /* only if minute marker is available */
{
parseio->parse_dtime.parse_stime = *ptime;
@@ -576,10 +633,43 @@ inp_rawdcf(
if (parse_timedout(parseio, tstamp, &timeout))
{
- parseprintf(DD_PARSE, ("inp_rawdcf: time out seen\n"));
-
+ last_tcode_t *t = (last_tcode_t *)parseio->parse_pdata;
+ long delta_usec;
+
+ parseprintf(DD_RAWDCF, ("inp_rawdcf: time out seen\n"));
+ /* finish collection */
(void) parse_end(parseio);
+
+ if (t != NULL)
+ {
+ /* remember minute start sample time if timeouts occur in minute raster */
+ if (t->timeout.tv.tv_sec != 0)
+ {
+ delta_usec = calc_usecdiff(tstamp, &t->timeout, 60);
+ if (delta_usec < 0)
+ delta_usec = -delta_usec;
+ }
+ else
+ {
+ delta_usec = -1;
+ }
+
+ if (delta_usec < 500000 && delta_usec >= 0)
+ {
+ parseprintf(DD_RAWDCF, ("inp_rawdcf: timeout time difference %ld usec - minute marker set\n", delta_usec));
+ /* collect minute markers only if spaced by 60 seconds */
+ t->tminute = *tstamp;
+ }
+ else
+ {
+ parseprintf(DD_RAWDCF, ("inp_rawdcf: timeout time difference %ld usec - minute marker cleared\n", delta_usec));
+ memset((char *)&t->tminute, 0, sizeof(t->tminute));
+ }
+ t->timeout = *tstamp;
+ }
(void) parse_addchar(parseio, ch);
+
+ /* pass up to higher layers */
return PARSE_INP_TIME;
}
else
OpenPOWER on IntegriCloud