diff options
Diffstat (limited to 'contrib/ntp/libparse/clk_rawdcf.c')
-rw-r--r-- | contrib/ntp/libparse/clk_rawdcf.c | 116 |
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 |