Annotation of embedaddon/ntp/parseutil/dcfd.c, revision 1.1
1.1 ! misho 1: /*
! 2: * /src/NTP/REPOSITORY/ntp4-dev/parseutil/dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A
! 3: *
! 4: * dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A
! 5: *
! 6: * DCF77 100/200ms pulse synchronisation daemon program (via 50Baud serial line)
! 7: *
! 8: * Features:
! 9: * DCF77 decoding
! 10: * simple NTP loopfilter logic for local clock
! 11: * interactive display for debugging
! 12: *
! 13: * Lacks:
! 14: * Leap second handling (at that level you should switch to NTP Version 4 - really!)
! 15: *
! 16: * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org>
! 17: * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universität Erlangen-Nürnberg, Germany
! 18: *
! 19: * Redistribution and use in source and binary forms, with or without
! 20: * modification, are permitted provided that the following conditions
! 21: * are met:
! 22: * 1. Redistributions of source code must retain the above copyright
! 23: * notice, this list of conditions and the following disclaimer.
! 24: * 2. Redistributions in binary form must reproduce the above copyright
! 25: * notice, this list of conditions and the following disclaimer in the
! 26: * documentation and/or other materials provided with the distribution.
! 27: * 3. Neither the name of the author nor the names of its contributors
! 28: * may be used to endorse or promote products derived from this software
! 29: * without specific prior written permission.
! 30: *
! 31: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 32: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 33: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 34: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 35: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 36: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 37: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 38: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 39: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 40: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 41: * SUCH DAMAGE.
! 42: *
! 43: */
! 44:
! 45: #ifdef HAVE_CONFIG_H
! 46: # include <config.h>
! 47: #endif
! 48:
! 49: #include <sys/ioctl.h>
! 50: #include <unistd.h>
! 51: #include <stdio.h>
! 52: #include <fcntl.h>
! 53: #include <sys/types.h>
! 54: #include <sys/time.h>
! 55: #include <signal.h>
! 56: #include <syslog.h>
! 57: #include <time.h>
! 58:
! 59: /*
! 60: * NTP compilation environment
! 61: */
! 62: #include "ntp_stdlib.h"
! 63: #include "ntpd.h" /* indirectly include ntp.h to get YEAR_PIVOT Y2KFixes */
! 64:
! 65: /*
! 66: * select which terminal handling to use (currently only SysV variants)
! 67: */
! 68: #if defined(HAVE_TERMIOS_H) || defined(STREAM)
! 69: #include <termios.h>
! 70: #define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))
! 71: #define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))
! 72: #else /* not HAVE_TERMIOS_H || STREAM */
! 73: # if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS)
! 74: # include <termio.h>
! 75: # define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))
! 76: # define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))
! 77: # endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */
! 78: #endif /* not HAVE_TERMIOS_H || STREAM */
! 79:
! 80:
! 81: #ifndef TTY_GETATTR
! 82: #include "Bletch: MUST DEFINE ONE OF 'HAVE_TERMIOS_H' or 'HAVE_TERMIO_H'"
! 83: #endif
! 84:
! 85: #ifndef days_per_year
! 86: #define days_per_year(_x_) (((_x_) % 4) ? 365 : (((_x_) % 400) ? 365 : 366))
! 87: #endif
! 88:
! 89: #define timernormalize(_a_) \
! 90: if ((_a_)->tv_usec >= 1000000) \
! 91: { \
! 92: (_a_)->tv_sec += (_a_)->tv_usec / 1000000; \
! 93: (_a_)->tv_usec = (_a_)->tv_usec % 1000000; \
! 94: } \
! 95: if ((_a_)->tv_usec < 0) \
! 96: { \
! 97: (_a_)->tv_sec -= 1 + (-(_a_)->tv_usec / 1000000); \
! 98: (_a_)->tv_usec = 999999 - (-(_a_)->tv_usec - 1); \
! 99: }
! 100:
! 101: #ifdef timeradd
! 102: #undef timeradd
! 103: #endif
! 104: #define timeradd(_a_, _b_) \
! 105: (_a_)->tv_sec += (_b_)->tv_sec; \
! 106: (_a_)->tv_usec += (_b_)->tv_usec; \
! 107: timernormalize((_a_))
! 108:
! 109: #ifdef timersub
! 110: #undef timersub
! 111: #endif
! 112: #define timersub(_a_, _b_) \
! 113: (_a_)->tv_sec -= (_b_)->tv_sec; \
! 114: (_a_)->tv_usec -= (_b_)->tv_usec; \
! 115: timernormalize((_a_))
! 116:
! 117: /*
! 118: * debug macros
! 119: */
! 120: #define PRINTF if (interactive) printf
! 121: #define LPRINTF if (interactive && loop_filter_debug) printf
! 122:
! 123: #ifdef DEBUG
! 124: #define dprintf(_x_) LPRINTF _x_
! 125: #else
! 126: #define dprintf(_x_)
! 127: #endif
! 128:
! 129: #ifdef DECL_ERRNO
! 130: extern int errno;
! 131: #endif
! 132:
! 133: static char *revision = "4.18";
! 134:
! 135: /*
! 136: * display received data (avoids also detaching from tty)
! 137: */
! 138: static int interactive = 0;
! 139:
! 140: /*
! 141: * display loopfilter (clock control) variables
! 142: */
! 143: static int loop_filter_debug = 0;
! 144:
! 145: /*
! 146: * do not set/adjust system time
! 147: */
! 148: static int no_set = 0;
! 149:
! 150: /*
! 151: * time that passes between start of DCF impulse and time stamping (fine
! 152: * adjustment) in microseconds (receiver/OS dependent)
! 153: */
! 154: #define DEFAULT_DELAY 230000 /* rough estimate */
! 155:
! 156: /*
! 157: * The two states we can be in - eithe we receive nothing
! 158: * usable or we have the correct time
! 159: */
! 160: #define NO_SYNC 0x01
! 161: #define SYNC 0x02
! 162:
! 163: static int sync_state = NO_SYNC;
! 164: static time_t last_sync;
! 165:
! 166: static unsigned long ticks = 0;
! 167:
! 168: static char pat[] = "-\\|/";
! 169:
! 170: #define LINES (24-2) /* error lines after which the two headlines are repeated */
! 171:
! 172: #define MAX_UNSYNC (10*60) /* allow synchronisation loss for 10 minutes */
! 173: #define NOTICE_INTERVAL (20*60) /* mention missing synchronisation every 20 minutes */
! 174:
! 175: /*
! 176: * clock adjustment PLL - see NTP protocol spec (RFC1305) for details
! 177: */
! 178:
! 179: #define USECSCALE 10
! 180: #define TIMECONSTANT 2
! 181: #define ADJINTERVAL 0
! 182: #define FREQ_WEIGHT 18
! 183: #define PHASE_WEIGHT 7
! 184: #define MAX_DRIFT 0x3FFFFFFF
! 185:
! 186: #define R_SHIFT(_X_, _Y_) (((_X_) < 0) ? -(-(_X_) >> (_Y_)) : ((_X_) >> (_Y_)))
! 187:
! 188: static long max_adj_offset_usec = 128000;
! 189:
! 190: static long clock_adjust = 0; /* current adjustment value (usec * 2^USECSCALE) */
! 191: static long accum_drift = 0; /* accumulated drift value (usec / ADJINTERVAL) */
! 192: static long adjustments = 0;
! 193: static char skip_adjust = 1; /* discard first adjustment (bad samples) */
! 194:
! 195: /*
! 196: * DCF77 state flags
! 197: */
! 198: #define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */
! 199: #define DCFB_DST 0x0002 /* DST in effect */
! 200: #define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurrence) */
! 201: #define DCFB_ALTERNATE 0x0008 /* alternate antenna used */
! 202:
! 203: struct clocktime /* clock time broken up from time code */
! 204: {
! 205: long wday; /* Day of week: 1: Monday - 7: Sunday */
! 206: long day;
! 207: long month;
! 208: long year;
! 209: long hour;
! 210: long minute;
! 211: long second;
! 212: long usecond;
! 213: long utcoffset; /* in minutes */
! 214: long flags; /* current clock status (DCF77 state flags) */
! 215: };
! 216:
! 217: typedef struct clocktime clocktime_t;
! 218:
! 219: /*
! 220: * (usually) quick constant multiplications
! 221: */
! 222: #define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) /* *8 + *2 */
! 223: #define TIMES24(_X_) (((_X_) << 4) + ((_X_) << 3)) /* *16 + *8 */
! 224: #define TIMES60(_X_) ((((_X_) << 4) - (_X_)) << 2) /* *(16 - 1) *4 */
! 225: /*
! 226: * generic l_abs() function
! 227: */
! 228: #define l_abs(_x_) (((_x_) < 0) ? -(_x_) : (_x_))
! 229:
! 230: /*
! 231: * conversion related return/error codes
! 232: */
! 233: #define CVT_MASK 0x0000000F /* conversion exit code */
! 234: #define CVT_NONE 0x00000001 /* format not applicable */
! 235: #define CVT_FAIL 0x00000002 /* conversion failed - error code returned */
! 236: #define CVT_OK 0x00000004 /* conversion succeeded */
! 237: #define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */
! 238: #define CVT_BADDATE 0x00000020 /* invalid date */
! 239: #define CVT_BADTIME 0x00000040 /* invalid time */
! 240:
! 241: /*
! 242: * DCF77 raw time code
! 243: *
! 244: * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig
! 245: * und Berlin, Maerz 1989
! 246: *
! 247: * Timecode transmission:
! 248: * AM:
! 249: * time marks are send every second except for the second before the
! 250: * next minute mark
! 251: * time marks consist of a reduction of transmitter power to 25%
! 252: * of the nominal level
! 253: * the falling edge is the time indication (on time)
! 254: * time marks of a 100ms duration constitute a logical 0
! 255: * time marks of a 200ms duration constitute a logical 1
! 256: * FM:
! 257: * see the spec. (basically a (non-)inverted psuedo random phase shift)
! 258: *
! 259: * Encoding:
! 260: * Second Contents
! 261: * 0 - 10 AM: free, FM: 0
! 262: * 11 - 14 free
! 263: * 15 R - alternate antenna
! 264: * 16 A1 - expect zone change (1 hour before)
! 265: * 17 - 18 Z1,Z2 - time zone
! 266: * 0 0 illegal
! 267: * 0 1 MEZ (MET)
! 268: * 1 0 MESZ (MED, MET DST)
! 269: * 1 1 illegal
! 270: * 19 A2 - expect leap insertion/deletion (1 hour before)
! 271: * 20 S - start of time code (1)
! 272: * 21 - 24 M1 - BCD (lsb first) Minutes
! 273: * 25 - 27 M10 - BCD (lsb first) 10 Minutes
! 274: * 28 P1 - Minute Parity (even)
! 275: * 29 - 32 H1 - BCD (lsb first) Hours
! 276: * 33 - 34 H10 - BCD (lsb first) 10 Hours
! 277: * 35 P2 - Hour Parity (even)
! 278: * 36 - 39 D1 - BCD (lsb first) Days
! 279: * 40 - 41 D10 - BCD (lsb first) 10 Days
! 280: * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday)
! 281: * 45 - 49 MO - BCD (lsb first) Month
! 282: * 50 MO0 - 10 Months
! 283: * 51 - 53 Y1 - BCD (lsb first) Years
! 284: * 54 - 57 Y10 - BCD (lsb first) 10 Years
! 285: * 58 P3 - Date Parity (even)
! 286: * 59 - usually missing (minute indication), except for leap insertion
! 287: */
! 288:
! 289: /*-----------------------------------------------------------------------
! 290: * conversion table to map DCF77 bit stream into data fields.
! 291: * Encoding:
! 292: * Each field of the DCF77 code is described with two adjacent entries in
! 293: * this table. The first entry specifies the offset into the DCF77 data stream
! 294: * while the length is given as the difference between the start index and
! 295: * the start index of the following field.
! 296: */
! 297: static struct rawdcfcode
! 298: {
! 299: char offset; /* start bit */
! 300: } rawdcfcode[] =
! 301: {
! 302: { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 },
! 303: { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 }
! 304: };
! 305:
! 306: /*-----------------------------------------------------------------------
! 307: * symbolic names for the fields of DCF77 describes in "rawdcfcode".
! 308: * see comment above for the structure of the DCF77 data
! 309: */
! 310: #define DCF_M 0
! 311: #define DCF_R 1
! 312: #define DCF_A1 2
! 313: #define DCF_Z 3
! 314: #define DCF_A2 4
! 315: #define DCF_S 5
! 316: #define DCF_M1 6
! 317: #define DCF_M10 7
! 318: #define DCF_P1 8
! 319: #define DCF_H1 9
! 320: #define DCF_H10 10
! 321: #define DCF_P2 11
! 322: #define DCF_D1 12
! 323: #define DCF_D10 13
! 324: #define DCF_DW 14
! 325: #define DCF_MO 15
! 326: #define DCF_MO0 16
! 327: #define DCF_Y1 17
! 328: #define DCF_Y10 18
! 329: #define DCF_P3 19
! 330:
! 331: /*-----------------------------------------------------------------------
! 332: * parity field table (same encoding as rawdcfcode)
! 333: * This table describes the sections of the DCF77 code that are
! 334: * parity protected
! 335: */
! 336: static struct partab
! 337: {
! 338: char offset; /* start bit of parity field */
! 339: } partab[] =
! 340: {
! 341: { 21 }, { 29 }, { 36 }, { 59 }
! 342: };
! 343:
! 344: /*-----------------------------------------------------------------------
! 345: * offsets for parity field descriptions
! 346: */
! 347: #define DCF_P_P1 0
! 348: #define DCF_P_P2 1
! 349: #define DCF_P_P3 2
! 350:
! 351: /*-----------------------------------------------------------------------
! 352: * legal values for time zone information
! 353: */
! 354: #define DCF_Z_MET 0x2
! 355: #define DCF_Z_MED 0x1
! 356:
! 357: /*-----------------------------------------------------------------------
! 358: * symbolic representation if the DCF77 data stream
! 359: */
! 360: static struct dcfparam
! 361: {
! 362: unsigned char onebits[60];
! 363: unsigned char zerobits[60];
! 364: } dcfparam =
! 365: {
! 366: "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */
! 367: "--------------------s-------p------p----------------------p" /* 'ZERO' representation */
! 368: };
! 369:
! 370: /*-----------------------------------------------------------------------
! 371: * extract a bitfield from DCF77 datastream
! 372: * All numeric fields are LSB first.
! 373: * buf holds a pointer to a DCF77 data buffer in symbolic
! 374: * representation
! 375: * idx holds the index to the field description in rawdcfcode
! 376: */
! 377: static unsigned long
! 378: ext_bf(
! 379: register unsigned char *buf,
! 380: register int idx
! 381: )
! 382: {
! 383: register unsigned long sum = 0;
! 384: register int i, first;
! 385:
! 386: first = rawdcfcode[idx].offset;
! 387:
! 388: for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--)
! 389: {
! 390: sum <<= 1;
! 391: sum |= (buf[i] != dcfparam.zerobits[i]);
! 392: }
! 393: return sum;
! 394: }
! 395:
! 396: /*-----------------------------------------------------------------------
! 397: * check even parity integrity for a bitfield
! 398: *
! 399: * buf holds a pointer to a DCF77 data buffer in symbolic
! 400: * representation
! 401: * idx holds the index to the field description in partab
! 402: */
! 403: static unsigned
! 404: pcheck(
! 405: register unsigned char *buf,
! 406: register int idx
! 407: )
! 408: {
! 409: register int i,last;
! 410: register unsigned psum = 1;
! 411:
! 412: last = partab[idx+1].offset;
! 413:
! 414: for (i = partab[idx].offset; i < last; i++)
! 415: psum ^= (buf[i] != dcfparam.zerobits[i]);
! 416:
! 417: return psum;
! 418: }
! 419:
! 420: /*-----------------------------------------------------------------------
! 421: * convert a DCF77 data buffer into wall clock time + flags
! 422: *
! 423: * buffer holds a pointer to a DCF77 data buffer in symbolic
! 424: * representation
! 425: * size describes the length of DCF77 information in bits (represented
! 426: * as chars in symbolic notation
! 427: * clock points to a wall clock time description of the DCF77 data (result)
! 428: */
! 429: static unsigned long
! 430: convert_rawdcf(
! 431: unsigned char *buffer,
! 432: int size,
! 433: clocktime_t *clock_time
! 434: )
! 435: {
! 436: if (size < 57)
! 437: {
! 438: PRINTF("%-30s", "*** INCOMPLETE");
! 439: return CVT_NONE;
! 440: }
! 441:
! 442: /*
! 443: * check Start and Parity bits
! 444: */
! 445: if ((ext_bf(buffer, DCF_S) == 1) &&
! 446: pcheck(buffer, DCF_P_P1) &&
! 447: pcheck(buffer, DCF_P_P2) &&
! 448: pcheck(buffer, DCF_P_P3))
! 449: {
! 450: /*
! 451: * buffer OK - extract all fields and build wall clock time from them
! 452: */
! 453:
! 454: clock_time->flags = 0;
! 455: clock_time->usecond= 0;
! 456: clock_time->second = 0;
! 457: clock_time->minute = ext_bf(buffer, DCF_M10);
! 458: clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1);
! 459: clock_time->hour = ext_bf(buffer, DCF_H10);
! 460: clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1);
! 461: clock_time->day = ext_bf(buffer, DCF_D10);
! 462: clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1);
! 463: clock_time->month = ext_bf(buffer, DCF_MO0);
! 464: clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO);
! 465: clock_time->year = ext_bf(buffer, DCF_Y10);
! 466: clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1);
! 467: clock_time->wday = ext_bf(buffer, DCF_DW);
! 468:
! 469: /*
! 470: * determine offset to UTC by examining the time zone
! 471: */
! 472: switch (ext_bf(buffer, DCF_Z))
! 473: {
! 474: case DCF_Z_MET:
! 475: clock_time->utcoffset = -60;
! 476: break;
! 477:
! 478: case DCF_Z_MED:
! 479: clock_time->flags |= DCFB_DST;
! 480: clock_time->utcoffset = -120;
! 481: break;
! 482:
! 483: default:
! 484: PRINTF("%-30s", "*** BAD TIME ZONE");
! 485: return CVT_FAIL|CVT_BADFMT;
! 486: }
! 487:
! 488: /*
! 489: * extract various warnings from DCF77
! 490: */
! 491: if (ext_bf(buffer, DCF_A1))
! 492: clock_time->flags |= DCFB_ANNOUNCE;
! 493:
! 494: if (ext_bf(buffer, DCF_A2))
! 495: clock_time->flags |= DCFB_LEAP;
! 496:
! 497: if (ext_bf(buffer, DCF_R))
! 498: clock_time->flags |= DCFB_ALTERNATE;
! 499:
! 500: return CVT_OK;
! 501: }
! 502: else
! 503: {
! 504: /*
! 505: * bad format - not for us
! 506: */
! 507: PRINTF("%-30s", "*** BAD FORMAT (invalid/parity)");
! 508: return CVT_FAIL|CVT_BADFMT;
! 509: }
! 510: }
! 511:
! 512: /*-----------------------------------------------------------------------
! 513: * raw dcf input routine - fix up 50 baud
! 514: * characters for 1/0 decision
! 515: */
! 516: static unsigned long
! 517: cvt_rawdcf(
! 518: unsigned char *buffer,
! 519: int size,
! 520: clocktime_t *clock_time
! 521: )
! 522: {
! 523: register unsigned char *s = buffer;
! 524: register unsigned char *e = buffer + size;
! 525: register unsigned char *b = dcfparam.onebits;
! 526: register unsigned char *c = dcfparam.zerobits;
! 527: register unsigned rtc = CVT_NONE;
! 528: register unsigned int i, lowmax, highmax, cutoff, span;
! 529: #define BITS 9
! 530: unsigned char histbuf[BITS];
! 531: /*
! 532: * the input buffer contains characters with runs of consecutive
! 533: * bits set. These set bits are an indication of the DCF77 pulse
! 534: * length. We assume that we receive the pulse at 50 Baud. Thus
! 535: * a 100ms pulse would generate a 4 bit train (20ms per bit and
! 536: * start bit)
! 537: * a 200ms pulse would create all zeroes (and probably a frame error)
! 538: *
! 539: * The basic idea is that on corret reception we must have two
! 540: * maxima in the pulse length distribution histogram. (one for
! 541: * the zero representing pulses and one for the one representing
! 542: * pulses)
! 543: * There will always be ones in the datastream, thus we have to see
! 544: * two maxima.
! 545: * The best point to cut for a 1/0 decision is the minimum between those
! 546: * between the maxima. The following code tries to find this cutoff point.
! 547: */
! 548:
! 549: /*
! 550: * clear histogram buffer
! 551: */
! 552: for (i = 0; i < BITS; i++)
! 553: {
! 554: histbuf[i] = 0;
! 555: }
! 556:
! 557: cutoff = 0;
! 558: lowmax = 0;
! 559:
! 560: /*
! 561: * convert sequences of set bits into bits counts updating
! 562: * the histogram alongway
! 563: */
! 564: while (s < e)
! 565: {
! 566: register unsigned int ch = *s ^ 0xFF;
! 567: /*
! 568: * check integrity and update histogramm
! 569: */
! 570: if (!((ch+1) & ch) || !*s)
! 571: {
! 572: /*
! 573: * character ok
! 574: */
! 575: for (i = 0; ch; i++)
! 576: {
! 577: ch >>= 1;
! 578: }
! 579:
! 580: *s = i;
! 581: histbuf[i]++;
! 582: cutoff += i;
! 583: lowmax++;
! 584: }
! 585: else
! 586: {
! 587: /*
! 588: * invalid character (no consecutive bit sequence)
! 589: */
! 590: dprintf(("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer));
! 591: *s = (unsigned char)~0;
! 592: rtc = CVT_FAIL|CVT_BADFMT;
! 593: }
! 594: s++;
! 595: }
! 596:
! 597: /*
! 598: * first cutoff estimate (average bit count - must be between both
! 599: * maxima)
! 600: */
! 601: if (lowmax)
! 602: {
! 603: cutoff /= lowmax;
! 604: }
! 605: else
! 606: {
! 607: cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */
! 608: }
! 609:
! 610: dprintf(("parse: cvt_rawdcf: average bit count: %d\n", cutoff));
! 611:
! 612: lowmax = 0; /* weighted sum */
! 613: highmax = 0; /* bitcount */
! 614:
! 615: /*
! 616: * collect weighted sum of lower bits (left of initial guess)
! 617: */
! 618: dprintf(("parse: cvt_rawdcf: histogram:"));
! 619: for (i = 0; i <= cutoff; i++)
! 620: {
! 621: lowmax += histbuf[i] * i;
! 622: highmax += histbuf[i];
! 623: dprintf((" %d", histbuf[i]));
! 624: }
! 625: dprintf((" <M>"));
! 626:
! 627: /*
! 628: * round up
! 629: */
! 630: lowmax += highmax / 2;
! 631:
! 632: /*
! 633: * calculate lower bit maximum (weighted sum / bit count)
! 634: *
! 635: * avoid divide by zero
! 636: */
! 637: if (highmax)
! 638: {
! 639: lowmax /= highmax;
! 640: }
! 641: else
! 642: {
! 643: lowmax = 0;
! 644: }
! 645:
! 646: highmax = 0; /* weighted sum of upper bits counts */
! 647: cutoff = 0; /* bitcount */
! 648:
! 649: /*
! 650: * collect weighted sum of lower bits (right of initial guess)
! 651: */
! 652: for (; i < BITS; i++)
! 653: {
! 654: highmax+=histbuf[i] * i;
! 655: cutoff +=histbuf[i];
! 656: dprintf((" %d", histbuf[i]));
! 657: }
! 658: dprintf(("\n"));
! 659:
! 660: /*
! 661: * determine upper maximum (weighted sum / bit count)
! 662: */
! 663: if (cutoff)
! 664: {
! 665: highmax /= cutoff;
! 666: }
! 667: else
! 668: {
! 669: highmax = BITS-1;
! 670: }
! 671:
! 672: /*
! 673: * following now holds:
! 674: * lowmax <= cutoff(initial guess) <= highmax
! 675: * best cutoff is the minimum nearest to higher bits
! 676: */
! 677:
! 678: /*
! 679: * find the minimum between lowmax and highmax (detecting
! 680: * possibly a minimum span)
! 681: */
! 682: span = cutoff = lowmax;
! 683: for (i = lowmax; i <= highmax; i++)
! 684: {
! 685: if (histbuf[cutoff] > histbuf[i])
! 686: {
! 687: /*
! 688: * got a new minimum move beginning of minimum (cutoff) and
! 689: * end of minimum (span) there
! 690: */
! 691: cutoff = span = i;
! 692: }
! 693: else
! 694: if (histbuf[cutoff] == histbuf[i])
! 695: {
! 696: /*
! 697: * minimum not better yet - but it spans more than
! 698: * one bit value - follow it
! 699: */
! 700: span = i;
! 701: }
! 702: }
! 703:
! 704: /*
! 705: * cutoff point for 1/0 decision is the middle of the minimum section
! 706: * in the histogram
! 707: */
! 708: cutoff = (cutoff + span) / 2;
! 709:
! 710: dprintf(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff));
! 711:
! 712: /*
! 713: * convert the bit counts to symbolic 1/0 information for data conversion
! 714: */
! 715: s = buffer;
! 716: while ((s < e) && *c && *b)
! 717: {
! 718: if (*s == (unsigned char)~0)
! 719: {
! 720: /*
! 721: * invalid character
! 722: */
! 723: *s = '?';
! 724: }
! 725: else
! 726: {
! 727: /*
! 728: * symbolic 1/0 representation
! 729: */
! 730: *s = (*s >= cutoff) ? *b : *c;
! 731: }
! 732: s++;
! 733: b++;
! 734: c++;
! 735: }
! 736:
! 737: /*
! 738: * if everything went well so far return the result of the symbolic
! 739: * conversion routine else just the accumulated errors
! 740: */
! 741: if (rtc != CVT_NONE)
! 742: {
! 743: PRINTF("%-30s", "*** BAD DATA");
! 744: }
! 745:
! 746: return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock_time) : rtc;
! 747: }
! 748:
! 749: /*-----------------------------------------------------------------------
! 750: * convert a wall clock time description of DCF77 to a Unix time (seconds
! 751: * since 1.1. 1970 UTC)
! 752: */
! 753: static time_t
! 754: dcf_to_unixtime(
! 755: clocktime_t *clock_time,
! 756: unsigned *cvtrtc
! 757: )
! 758: {
! 759: #define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); }
! 760: static int days_of_month[] =
! 761: {
! 762: 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
! 763: };
! 764: register int i;
! 765: time_t t;
! 766:
! 767: /*
! 768: * map 2 digit years to 19xx (DCF77 is a 20th century item)
! 769: */
! 770: if ( clock_time->year < YEAR_PIVOT ) /* in case of Y2KFixes [ */
! 771: clock_time->year += 100; /* *year%100, make tm_year */
! 772: /* *(do we need this?) */
! 773: if ( clock_time->year < YEAR_BREAK ) /* (failsafe if) */
! 774: clock_time->year += 1900; /* Y2KFixes ] */
! 775:
! 776: /*
! 777: * must have been a really bad year code - drop it
! 778: */
! 779: if (clock_time->year < (YEAR_PIVOT + 1900) ) /* Y2KFixes */
! 780: {
! 781: SETRTC(CVT_FAIL|CVT_BADDATE);
! 782: return -1;
! 783: }
! 784: /*
! 785: * sorry, slow section here - but it's not time critical anyway
! 786: */
! 787:
! 788: /*
! 789: * calculate days since 1970 (watching leap years)
! 790: */
! 791: t = julian0( clock_time->year ) - julian0( 1970 );
! 792:
! 793: /* month */
! 794: if (clock_time->month <= 0 || clock_time->month > 12)
! 795: {
! 796: SETRTC(CVT_FAIL|CVT_BADDATE);
! 797: return -1; /* bad month */
! 798: }
! 799: /* adjust current leap year */
! 800: #if 0
! 801: if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
! 802: t--;
! 803: #endif
! 804:
! 805: /*
! 806: * collect days from months excluding the current one
! 807: */
! 808: for (i = 1; i < clock_time->month; i++)
! 809: {
! 810: t += days_of_month[i];
! 811: }
! 812: /* day */
! 813: if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
! 814: clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
! 815: {
! 816: SETRTC(CVT_FAIL|CVT_BADDATE);
! 817: return -1; /* bad day */
! 818: }
! 819:
! 820: /*
! 821: * collect days from date excluding the current one
! 822: */
! 823: t += clock_time->day - 1;
! 824:
! 825: /* hour */
! 826: if (clock_time->hour < 0 || clock_time->hour >= 24)
! 827: {
! 828: SETRTC(CVT_FAIL|CVT_BADTIME);
! 829: return -1; /* bad hour */
! 830: }
! 831:
! 832: /*
! 833: * calculate hours from 1. 1. 1970
! 834: */
! 835: t = TIMES24(t) + clock_time->hour;
! 836:
! 837: /* min */
! 838: if (clock_time->minute < 0 || clock_time->minute > 59)
! 839: {
! 840: SETRTC(CVT_FAIL|CVT_BADTIME);
! 841: return -1; /* bad min */
! 842: }
! 843:
! 844: /*
! 845: * calculate minutes from 1. 1. 1970
! 846: */
! 847: t = TIMES60(t) + clock_time->minute;
! 848: /* sec */
! 849:
! 850: /*
! 851: * calculate UTC in minutes
! 852: */
! 853: t += clock_time->utcoffset;
! 854:
! 855: if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */
! 856: {
! 857: SETRTC(CVT_FAIL|CVT_BADTIME);
! 858: return -1; /* bad sec */
! 859: }
! 860:
! 861: /*
! 862: * calculate UTC in seconds - phew !
! 863: */
! 864: t = TIMES60(t) + clock_time->second;
! 865: /* done */
! 866: return t;
! 867: }
! 868:
! 869: /*-----------------------------------------------------------------------
! 870: * cheap half baked 1/0 decision - for interactive operation only
! 871: */
! 872: static char
! 873: type(
! 874: unsigned int c
! 875: )
! 876: {
! 877: c ^= 0xFF;
! 878: return (c > 0xF);
! 879: }
! 880:
! 881: /*-----------------------------------------------------------------------
! 882: * week day representation
! 883: */
! 884: static const char *wday[8] =
! 885: {
! 886: "??",
! 887: "Mo",
! 888: "Tu",
! 889: "We",
! 890: "Th",
! 891: "Fr",
! 892: "Sa",
! 893: "Su"
! 894: };
! 895:
! 896: /*-----------------------------------------------------------------------
! 897: * generate a string representation for a timeval
! 898: */
! 899: static char *
! 900: pr_timeval(
! 901: struct timeval *val
! 902: )
! 903: {
! 904: static char buf[20];
! 905:
! 906: if (val->tv_sec == 0)
! 907: sprintf(buf, "%c0.%06ld", (val->tv_usec < 0) ? '-' : '+', (long int)l_abs(val->tv_usec));
! 908: else
! 909: sprintf(buf, "%ld.%06ld", (long int)val->tv_sec, (long int)l_abs(val->tv_usec));
! 910: return buf;
! 911: }
! 912:
! 913: /*-----------------------------------------------------------------------
! 914: * correct the current time by an offset by setting the time rigorously
! 915: */
! 916: static void
! 917: set_time(
! 918: struct timeval *offset
! 919: )
! 920: {
! 921: struct timeval the_time;
! 922:
! 923: if (no_set)
! 924: return;
! 925:
! 926: LPRINTF("set_time: %s ", pr_timeval(offset));
! 927: syslog(LOG_NOTICE, "setting time (offset %s)", pr_timeval(offset));
! 928:
! 929: if (gettimeofday(&the_time, 0L) == -1)
! 930: {
! 931: perror("gettimeofday()");
! 932: }
! 933: else
! 934: {
! 935: timeradd(&the_time, offset);
! 936: if (settimeofday(&the_time, 0L) == -1)
! 937: {
! 938: perror("settimeofday()");
! 939: }
! 940: }
! 941: }
! 942:
! 943: /*-----------------------------------------------------------------------
! 944: * slew the time by a given offset
! 945: */
! 946: static void
! 947: adj_time(
! 948: long offset
! 949: )
! 950: {
! 951: struct timeval time_offset;
! 952:
! 953: if (no_set)
! 954: return;
! 955:
! 956: time_offset.tv_sec = offset / 1000000;
! 957: time_offset.tv_usec = offset % 1000000;
! 958:
! 959: LPRINTF("adj_time: %ld us ", (long int)offset);
! 960: if (adjtime(&time_offset, 0L) == -1)
! 961: perror("adjtime()");
! 962: }
! 963:
! 964: /*-----------------------------------------------------------------------
! 965: * read in a possibly previously written drift value
! 966: */
! 967: static void
! 968: read_drift(
! 969: const char *drift_file
! 970: )
! 971: {
! 972: FILE *df;
! 973:
! 974: df = fopen(drift_file, "r");
! 975: if (df != NULL)
! 976: {
! 977: int idrift = 0, fdrift = 0;
! 978:
! 979: fscanf(df, "%4d.%03d", &idrift, &fdrift);
! 980: fclose(df);
! 981: LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift);
! 982:
! 983: accum_drift = idrift << USECSCALE;
! 984: fdrift = (fdrift << USECSCALE) / 1000;
! 985: accum_drift += fdrift & (1<<USECSCALE);
! 986: LPRINTF("read_drift: drift_comp %ld ", (long int)accum_drift);
! 987: }
! 988: }
! 989:
! 990: /*-----------------------------------------------------------------------
! 991: * write out the current drift value
! 992: */
! 993: static void
! 994: update_drift(
! 995: const char *drift_file,
! 996: long offset,
! 997: time_t reftime
! 998: )
! 999: {
! 1000: FILE *df;
! 1001:
! 1002: df = fopen(drift_file, "w");
! 1003: if (df != NULL)
! 1004: {
! 1005: int idrift = R_SHIFT(accum_drift, USECSCALE);
! 1006: int fdrift = accum_drift & ((1<<USECSCALE)-1);
! 1007:
! 1008: LPRINTF("update_drift: drift_comp %ld ", (long int)accum_drift);
! 1009: fdrift = (fdrift * 1000) / (1<<USECSCALE);
! 1010: fprintf(df, "%4d.%03d %c%ld.%06ld %.24s\n", idrift, fdrift,
! 1011: (offset < 0) ? '-' : '+', (long int)(l_abs(offset) / 1000000),
! 1012: (long int)(l_abs(offset) % 1000000), asctime(localtime(&reftime)));
! 1013: fclose(df);
! 1014: LPRINTF("update_drift: %d.%03d ppm ", idrift, fdrift);
! 1015: }
! 1016: }
! 1017:
! 1018: /*-----------------------------------------------------------------------
! 1019: * process adjustments derived from the DCF77 observation
! 1020: * (controls clock PLL)
! 1021: */
! 1022: static void
! 1023: adjust_clock(
! 1024: struct timeval *offset,
! 1025: const char *drift_file,
! 1026: time_t reftime
! 1027: )
! 1028: {
! 1029: struct timeval toffset;
! 1030: register long usecoffset;
! 1031: int tmp;
! 1032:
! 1033: if (no_set)
! 1034: return;
! 1035:
! 1036: if (skip_adjust)
! 1037: {
! 1038: skip_adjust = 0;
! 1039: return;
! 1040: }
! 1041:
! 1042: toffset = *offset;
! 1043: toffset.tv_sec = l_abs(toffset.tv_sec);
! 1044: toffset.tv_usec = l_abs(toffset.tv_usec);
! 1045: if (toffset.tv_sec ||
! 1046: (!toffset.tv_sec && toffset.tv_usec > max_adj_offset_usec))
! 1047: {
! 1048: /*
! 1049: * hopeless - set the clock - and clear the timing
! 1050: */
! 1051: set_time(offset);
! 1052: clock_adjust = 0;
! 1053: skip_adjust = 1;
! 1054: return;
! 1055: }
! 1056:
! 1057: usecoffset = offset->tv_sec * 1000000 + offset->tv_usec;
! 1058:
! 1059: clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT); /* adjustment to make for next period */
! 1060:
! 1061: tmp = 0;
! 1062: while (adjustments > (1 << tmp))
! 1063: tmp++;
! 1064: adjustments = 0;
! 1065: if (tmp > FREQ_WEIGHT)
! 1066: tmp = FREQ_WEIGHT;
! 1067:
! 1068: accum_drift += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp);
! 1069:
! 1070: if (accum_drift > MAX_DRIFT) /* clamp into interval */
! 1071: accum_drift = MAX_DRIFT;
! 1072: else
! 1073: if (accum_drift < -MAX_DRIFT)
! 1074: accum_drift = -MAX_DRIFT;
! 1075:
! 1076: update_drift(drift_file, usecoffset, reftime);
! 1077: LPRINTF("clock_adjust: %s, clock_adjust %ld, drift_comp %ld(%ld) ",
! 1078: pr_timeval(offset),(long int) R_SHIFT(clock_adjust, USECSCALE),
! 1079: (long int)R_SHIFT(accum_drift, USECSCALE), (long int)accum_drift);
! 1080: }
! 1081:
! 1082: /*-----------------------------------------------------------------------
! 1083: * adjust the clock by a small mount to simulate frequency correction
! 1084: */
! 1085: static void
! 1086: periodic_adjust(
! 1087: void
! 1088: )
! 1089: {
! 1090: register long adjustment;
! 1091:
! 1092: adjustments++;
! 1093:
! 1094: adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT);
! 1095:
! 1096: clock_adjust -= adjustment;
! 1097:
! 1098: adjustment += R_SHIFT(accum_drift, USECSCALE+ADJINTERVAL);
! 1099:
! 1100: adj_time(adjustment);
! 1101: }
! 1102:
! 1103: /*-----------------------------------------------------------------------
! 1104: * control synchronisation status (warnings) and do periodic adjusts
! 1105: * (frequency control simulation)
! 1106: */
! 1107: static void
! 1108: tick(
! 1109: int signum
! 1110: )
! 1111: {
! 1112: static unsigned long last_notice = 0;
! 1113:
! 1114: #if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC)
! 1115: (void)signal(SIGALRM, tick);
! 1116: #endif
! 1117:
! 1118: periodic_adjust();
! 1119:
! 1120: ticks += 1<<ADJINTERVAL;
! 1121:
! 1122: if ((ticks - last_sync) > MAX_UNSYNC)
! 1123: {
! 1124: /*
! 1125: * not getting time for a while
! 1126: */
! 1127: if (sync_state == SYNC)
! 1128: {
! 1129: /*
! 1130: * completely lost information
! 1131: */
! 1132: sync_state = NO_SYNC;
! 1133: syslog(LOG_INFO, "DCF77 reception lost (timeout)");
! 1134: last_notice = ticks;
! 1135: }
! 1136: else
! 1137: /*
! 1138: * in NO_SYNC state - look whether its time to speak up again
! 1139: */
! 1140: if ((ticks - last_notice) > NOTICE_INTERVAL)
! 1141: {
! 1142: syslog(LOG_NOTICE, "still not synchronized to DCF77 - check receiver/signal");
! 1143: last_notice = ticks;
! 1144: }
! 1145: }
! 1146:
! 1147: #ifndef ITIMER_REAL
! 1148: (void) alarm(1<<ADJINTERVAL);
! 1149: #endif
! 1150: }
! 1151:
! 1152: /*-----------------------------------------------------------------------
! 1153: * break association from terminal to avoid catching terminal
! 1154: * or process group related signals (-> daemon operation)
! 1155: */
! 1156: static void
! 1157: detach(
! 1158: void
! 1159: )
! 1160: {
! 1161: # ifdef HAVE_DAEMON
! 1162: daemon(0, 0);
! 1163: # else /* not HAVE_DAEMON */
! 1164: if (fork())
! 1165: exit(0);
! 1166:
! 1167: {
! 1168: u_long s;
! 1169: int max_fd;
! 1170:
! 1171: #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
! 1172: max_fd = sysconf(_SC_OPEN_MAX);
! 1173: #else /* HAVE_SYSCONF && _SC_OPEN_MAX */
! 1174: max_fd = getdtablesize();
! 1175: #endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
! 1176: for (s = 0; s < max_fd; s++)
! 1177: (void) close((int)s);
! 1178: (void) open("/", 0);
! 1179: (void) dup2(0, 1);
! 1180: (void) dup2(0, 2);
! 1181: #ifdef SYS_DOMAINOS
! 1182: {
! 1183: uid_$t puid;
! 1184: status_$t st;
! 1185:
! 1186: proc2_$who_am_i(&puid);
! 1187: proc2_$make_server(&puid, &st);
! 1188: }
! 1189: #endif /* SYS_DOMAINOS */
! 1190: #if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
! 1191: # ifdef HAVE_SETSID
! 1192: if (setsid() == (pid_t)-1)
! 1193: syslog(LOG_ERR, "dcfd: setsid(): %m");
! 1194: # else
! 1195: if (setpgid(0, 0) == -1)
! 1196: syslog(LOG_ERR, "dcfd: setpgid(): %m");
! 1197: # endif
! 1198: #else /* HAVE_SETPGID || HAVE_SETSID */
! 1199: {
! 1200: int fid;
! 1201:
! 1202: fid = open("/dev/tty", 2);
! 1203: if (fid >= 0)
! 1204: {
! 1205: (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
! 1206: (void) close(fid);
! 1207: }
! 1208: # ifdef HAVE_SETPGRP_0
! 1209: (void) setpgrp();
! 1210: # else /* HAVE_SETPGRP_0 */
! 1211: (void) setpgrp(0, getpid());
! 1212: # endif /* HAVE_SETPGRP_0 */
! 1213: }
! 1214: #endif /* HAVE_SETPGID || HAVE_SETSID */
! 1215: }
! 1216: #endif /* not HAVE_DAEMON */
! 1217: }
! 1218:
! 1219: /*-----------------------------------------------------------------------
! 1220: * list possible arguments and options
! 1221: */
! 1222: static void
! 1223: usage(
! 1224: char *program
! 1225: )
! 1226: {
! 1227: fprintf(stderr, "usage: %s [-n] [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] [-D <input delay>] <device>\n", program);
! 1228: fprintf(stderr, "\t-n do not change time\n");
! 1229: fprintf(stderr, "\t-i interactive\n");
! 1230: fprintf(stderr, "\t-t trace (print all datagrams)\n");
! 1231: fprintf(stderr, "\t-f print all databits (includes PTB private data)\n");
! 1232: fprintf(stderr, "\t-l print loop filter debug information\n");
! 1233: fprintf(stderr, "\t-o print offet average for current minute\n");
! 1234: fprintf(stderr, "\t-Y make internal Y2K checks then exit\n"); /* Y2KFixes */
! 1235: fprintf(stderr, "\t-d <drift_file> specify alternate drift file\n");
! 1236: fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n");
! 1237: }
! 1238:
! 1239: /*-----------------------------------------------------------------------
! 1240: * check_y2k() - internal check of Y2K logic
! 1241: * (a lot of this logic lifted from ../ntpd/check_y2k.c)
! 1242: */
! 1243: static int
! 1244: check_y2k( void )
! 1245: {
! 1246: int year; /* current working year */
! 1247: int year0 = 1900; /* sarting year for NTP time */
! 1248: int yearend; /* ending year we test for NTP time.
! 1249: * 32-bit systems: through 2036, the
! 1250: **year in which NTP time overflows.
! 1251: * 64-bit systems: a reasonable upper
! 1252: **limit (well, maybe somewhat beyond
! 1253: **reasonable, but well before the
! 1254: **max time, by which time the earth
! 1255: **will be dead.) */
! 1256: time_t Time;
! 1257: struct tm LocalTime;
! 1258:
! 1259: int Fatals, Warnings;
! 1260: #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
! 1261: Warnings++; else Fatals++
! 1262:
! 1263: Fatals = Warnings = 0;
! 1264:
! 1265: Time = time( (time_t *)NULL );
! 1266: LocalTime = *localtime( &Time );
! 1267:
! 1268: year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */
! 1269: ? ( 400 * 3 ) /* three greater gregorian cycles */
! 1270: : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
! 1271: /* NOTE: will automacially expand test years on
! 1272: * 64 bit machines.... this may cause some of the
! 1273: * existing ntp logic to fail for years beyond
! 1274: * 2036 (the current 32-bit limit). If all checks
! 1275: * fail ONLY beyond year 2036 you may ignore such
! 1276: * errors, at least for a decade or so. */
! 1277: yearend = year0 + year;
! 1278:
! 1279: year = 1900+YEAR_PIVOT;
! 1280: printf( " starting year %04d\n", (int) year );
! 1281: printf( " ending year %04d\n", (int) yearend );
! 1282:
! 1283: for ( ; year < yearend; year++ )
! 1284: {
! 1285: clocktime_t ct;
! 1286: time_t Observed;
! 1287: time_t Expected;
! 1288: unsigned Flag;
! 1289: unsigned long t;
! 1290:
! 1291: ct.day = 1;
! 1292: ct.month = 1;
! 1293: ct.year = year;
! 1294: ct.hour = ct.minute = ct.second = ct.usecond = 0;
! 1295: ct.utcoffset = 0;
! 1296: ct.flags = 0;
! 1297:
! 1298: Flag = 0;
! 1299: Observed = dcf_to_unixtime( &ct, &Flag );
! 1300: /* seems to be a clone of parse_to_unixtime() with
! 1301: * *a minor difference to arg2 type */
! 1302: if ( ct.year != year )
! 1303: {
! 1304: fprintf( stdout,
! 1305: "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
! 1306: (int)year, (int)Flag, (int)ct.year );
! 1307: Error(year);
! 1308: break;
! 1309: }
! 1310: t = julian0(year) - julian0(1970); /* Julian day from 1970 */
! 1311: Expected = t * 24 * 60 * 60;
! 1312: if ( Observed != Expected || Flag )
! 1313: { /* time difference */
! 1314: fprintf( stdout,
! 1315: "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
! 1316: year, (int)Flag,
! 1317: (unsigned long)Observed, (unsigned long)Expected,
! 1318: ((long)Observed - (long)Expected) );
! 1319: Error(year);
! 1320: break;
! 1321: }
! 1322:
! 1323: if ( year >= YEAR_PIVOT+1900 )
! 1324: {
! 1325: /* check year % 100 code we put into dcf_to_unixtime() */
! 1326: ct.year = year % 100;
! 1327: Flag = 0;
! 1328:
! 1329: Observed = dcf_to_unixtime( &ct, &Flag );
! 1330:
! 1331: if ( Observed != Expected || Flag )
! 1332: { /* time difference */
! 1333: fprintf( stdout,
! 1334: "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
! 1335: year, (int)ct.year, (int)Flag,
! 1336: (unsigned long)Observed, (unsigned long)Expected,
! 1337: ((long)Observed - (long)Expected) );
! 1338: Error(year);
! 1339: break;
! 1340: }
! 1341:
! 1342: /* check year - 1900 code we put into dcf_to_unixtime() */
! 1343: ct.year = year - 1900;
! 1344: Flag = 0;
! 1345:
! 1346: Observed = dcf_to_unixtime( &ct, &Flag );
! 1347:
! 1348: if ( Observed != Expected || Flag ) { /* time difference */
! 1349: fprintf( stdout,
! 1350: "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n",
! 1351: year, (int)ct.year, (int)Flag,
! 1352: (unsigned long)Observed, (unsigned long)Expected,
! 1353: ((long)Observed - (long)Expected) );
! 1354: Error(year);
! 1355: break;
! 1356: }
! 1357:
! 1358:
! 1359: }
! 1360: }
! 1361:
! 1362: return ( Fatals );
! 1363: }
! 1364:
! 1365: /*--------------------------------------------------
! 1366: * rawdcf_init - set up modem lines for RAWDCF receivers
! 1367: */
! 1368: #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
! 1369: static void
! 1370: rawdcf_init(
! 1371: int fd
! 1372: )
! 1373: {
! 1374: /*
! 1375: * You can use the RS232 to supply the power for a DCF77 receiver.
! 1376: * Here a voltage between the DTR and the RTS line is used. Unfortunately
! 1377: * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
! 1378: */
! 1379:
! 1380: #ifdef TIOCM_DTR
! 1381: int sl232 = TIOCM_DTR; /* turn on DTR for power supply */
! 1382: #else
! 1383: int sl232 = CIOCM_DTR; /* turn on DTR for power supply */
! 1384: #endif
! 1385:
! 1386: if (ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)
! 1387: {
! 1388: syslog(LOG_NOTICE, "rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m");
! 1389: }
! 1390: }
! 1391: #else
! 1392: static void
! 1393: rawdcf_init(
! 1394: int fd
! 1395: )
! 1396: {
! 1397: syslog(LOG_NOTICE, "rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules");
! 1398: }
! 1399: #endif /* DTR initialisation type */
! 1400:
! 1401: /*-----------------------------------------------------------------------
! 1402: * main loop - argument interpreter / setup / main loop
! 1403: */
! 1404: int
! 1405: main(
! 1406: int argc,
! 1407: char **argv
! 1408: )
! 1409: {
! 1410: unsigned char c;
! 1411: char **a = argv;
! 1412: int ac = argc;
! 1413: char *file = NULL;
! 1414: const char *drift_file = "/etc/dcfd.drift";
! 1415: int fd;
! 1416: int offset = 15;
! 1417: int offsets = 0;
! 1418: int delay = DEFAULT_DELAY; /* average delay from input edge to time stamping */
! 1419: int trace = 0;
! 1420: int errs = 0;
! 1421:
! 1422: /*
! 1423: * process arguments
! 1424: */
! 1425: while (--ac)
! 1426: {
! 1427: char *arg = *++a;
! 1428: if (*arg == '-')
! 1429: while ((c = *++arg))
! 1430: switch (c)
! 1431: {
! 1432: case 't':
! 1433: trace = 1;
! 1434: interactive = 1;
! 1435: break;
! 1436:
! 1437: case 'f':
! 1438: offset = 0;
! 1439: interactive = 1;
! 1440: break;
! 1441:
! 1442: case 'l':
! 1443: loop_filter_debug = 1;
! 1444: offsets = 1;
! 1445: interactive = 1;
! 1446: break;
! 1447:
! 1448: case 'n':
! 1449: no_set = 1;
! 1450: break;
! 1451:
! 1452: case 'o':
! 1453: offsets = 1;
! 1454: interactive = 1;
! 1455: break;
! 1456:
! 1457: case 'i':
! 1458: interactive = 1;
! 1459: break;
! 1460:
! 1461: case 'D':
! 1462: if (ac > 1)
! 1463: {
! 1464: delay = atoi(*++a);
! 1465: ac--;
! 1466: }
! 1467: else
! 1468: {
! 1469: fprintf(stderr, "%s: -D requires integer argument\n", argv[0]);
! 1470: errs=1;
! 1471: }
! 1472: break;
! 1473:
! 1474: case 'd':
! 1475: if (ac > 1)
! 1476: {
! 1477: drift_file = *++a;
! 1478: ac--;
! 1479: }
! 1480: else
! 1481: {
! 1482: fprintf(stderr, "%s: -d requires file name argument\n", argv[0]);
! 1483: errs=1;
! 1484: }
! 1485: break;
! 1486:
! 1487: case 'Y':
! 1488: errs=check_y2k();
! 1489: exit( errs ? 1 : 0 );
! 1490:
! 1491: default:
! 1492: fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
! 1493: errs=1;
! 1494: break;
! 1495: }
! 1496: else
! 1497: if (file == NULL)
! 1498: file = arg;
! 1499: else
! 1500: {
! 1501: fprintf(stderr, "%s: device specified twice\n", argv[0]);
! 1502: errs=1;
! 1503: }
! 1504: }
! 1505:
! 1506: if (errs)
! 1507: {
! 1508: usage(argv[0]);
! 1509: exit(1);
! 1510: }
! 1511: else
! 1512: if (file == NULL)
! 1513: {
! 1514: fprintf(stderr, "%s: device not specified\n", argv[0]);
! 1515: usage(argv[0]);
! 1516: exit(1);
! 1517: }
! 1518:
! 1519: errs = LINES+1;
! 1520:
! 1521: /*
! 1522: * get access to DCF77 tty port
! 1523: */
! 1524: fd = open(file, O_RDONLY);
! 1525: if (fd == -1)
! 1526: {
! 1527: perror(file);
! 1528: exit(1);
! 1529: }
! 1530: else
! 1531: {
! 1532: int i, rrc;
! 1533: struct timeval t, tt, tlast;
! 1534: struct timeval timeout;
! 1535: struct timeval phase;
! 1536: struct timeval time_offset;
! 1537: char pbuf[61]; /* printable version */
! 1538: char buf[61]; /* raw data */
! 1539: clocktime_t clock_time; /* wall clock time */
! 1540: time_t utc_time = 0;
! 1541: time_t last_utc_time = 0;
! 1542: long usecerror = 0;
! 1543: long lasterror = 0;
! 1544: #if defined(HAVE_TERMIOS_H) || defined(STREAM)
! 1545: struct termios term;
! 1546: #else /* not HAVE_TERMIOS_H || STREAM */
! 1547: # if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS)
! 1548: struct termio term;
! 1549: # endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */
! 1550: #endif /* not HAVE_TERMIOS_H || STREAM */
! 1551: unsigned int rtc = CVT_NONE;
! 1552:
! 1553: rawdcf_init(fd);
! 1554:
! 1555: timeout.tv_sec = 1;
! 1556: timeout.tv_usec = 500000;
! 1557:
! 1558: phase.tv_sec = 0;
! 1559: phase.tv_usec = delay;
! 1560:
! 1561: /*
! 1562: * setup TTY (50 Baud, Read, 8Bit, No Hangup, 1 character IO)
! 1563: */
! 1564: if (TTY_GETATTR(fd, &term) == -1)
! 1565: {
! 1566: perror("tcgetattr");
! 1567: exit(1);
! 1568: }
! 1569:
! 1570: memset(term.c_cc, 0, sizeof(term.c_cc));
! 1571: term.c_cc[VMIN] = 1;
! 1572: #ifdef NO_PARENB_IGNPAR
! 1573: term.c_cflag = CS8|CREAD|CLOCAL;
! 1574: #else
! 1575: term.c_cflag = CS8|CREAD|CLOCAL|PARENB;
! 1576: #endif
! 1577: term.c_iflag = IGNPAR;
! 1578: term.c_oflag = 0;
! 1579: term.c_lflag = 0;
! 1580:
! 1581: cfsetispeed(&term, B50);
! 1582: cfsetospeed(&term, B50);
! 1583:
! 1584: if (TTY_SETATTR(fd, &term) == -1)
! 1585: {
! 1586: perror("tcsetattr");
! 1587: exit(1);
! 1588: }
! 1589:
! 1590: /*
! 1591: * lose terminal if in daemon operation
! 1592: */
! 1593: if (!interactive)
! 1594: detach();
! 1595:
! 1596: /*
! 1597: * get syslog() initialized
! 1598: */
! 1599: #ifdef LOG_DAEMON
! 1600: openlog("dcfd", LOG_PID, LOG_DAEMON);
! 1601: #else
! 1602: openlog("dcfd", LOG_PID);
! 1603: #endif
! 1604:
! 1605: /*
! 1606: * setup periodic operations (state control / frequency control)
! 1607: */
! 1608: #ifdef HAVE_SIGACTION
! 1609: {
! 1610: struct sigaction act;
! 1611:
! 1612: # ifdef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION
! 1613: act.sa_sigaction = (void (*) (int, siginfo_t *, void *))0;
! 1614: # endif /* HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION */
! 1615: act.sa_handler = tick;
! 1616: sigemptyset(&act.sa_mask);
! 1617: act.sa_flags = 0;
! 1618:
! 1619: if (sigaction(SIGALRM, &act, (struct sigaction *)0) == -1)
! 1620: {
! 1621: syslog(LOG_ERR, "sigaction(SIGALRM): %m");
! 1622: exit(1);
! 1623: }
! 1624: }
! 1625: #else
! 1626: #ifdef HAVE_SIGVEC
! 1627: {
! 1628: struct sigvec vec;
! 1629:
! 1630: vec.sv_handler = tick;
! 1631: vec.sv_mask = 0;
! 1632: vec.sv_flags = 0;
! 1633:
! 1634: if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1)
! 1635: {
! 1636: syslog(LOG_ERR, "sigvec(SIGALRM): %m");
! 1637: exit(1);
! 1638: }
! 1639: }
! 1640: #else
! 1641: (void) signal(SIGALRM, tick);
! 1642: #endif
! 1643: #endif
! 1644:
! 1645: #ifdef ITIMER_REAL
! 1646: {
! 1647: struct itimerval it;
! 1648:
! 1649: it.it_interval.tv_sec = 1<<ADJINTERVAL;
! 1650: it.it_interval.tv_usec = 0;
! 1651: it.it_value.tv_sec = 1<<ADJINTERVAL;
! 1652: it.it_value.tv_usec = 0;
! 1653:
! 1654: if (setitimer(ITIMER_REAL, &it, (struct itimerval *)0) == -1)
! 1655: {
! 1656: syslog(LOG_ERR, "setitimer: %m");
! 1657: exit(1);
! 1658: }
! 1659: }
! 1660: #else
! 1661: (void) alarm(1<<ADJINTERVAL);
! 1662: #endif
! 1663:
! 1664: PRINTF(" DCF77 monitor %s - Copyright (C) 1993-2005 by Frank Kardel\n\n", revision);
! 1665:
! 1666: pbuf[60] = '\0';
! 1667: for ( i = 0; i < 60; i++)
! 1668: pbuf[i] = '.';
! 1669:
! 1670: read_drift(drift_file);
! 1671:
! 1672: /*
! 1673: * what time is it now (for interval measurement)
! 1674: */
! 1675: gettimeofday(&tlast, 0L);
! 1676: i = 0;
! 1677: /*
! 1678: * loop until input trouble ...
! 1679: */
! 1680: do
! 1681: {
! 1682: /*
! 1683: * get an impulse
! 1684: */
! 1685: while ((rrc = read(fd, &c, 1)) == 1)
! 1686: {
! 1687: gettimeofday(&t, 0L);
! 1688: tt = t;
! 1689: timersub(&t, &tlast);
! 1690:
! 1691: if (errs > LINES)
! 1692: {
! 1693: PRINTF(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]);
! 1694: PRINTF(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]);
! 1695: errs = 0;
! 1696: }
! 1697:
! 1698: /*
! 1699: * timeout -> possible minute mark -> interpretation
! 1700: */
! 1701: if (timercmp(&t, &timeout, >))
! 1702: {
! 1703: PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]);
! 1704:
! 1705: if ((rtc = cvt_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK)
! 1706: {
! 1707: /*
! 1708: * this data was bad - well - forget synchronisation for now
! 1709: */
! 1710: PRINTF("\n");
! 1711: if (sync_state == SYNC)
! 1712: {
! 1713: sync_state = NO_SYNC;
! 1714: syslog(LOG_INFO, "DCF77 reception lost (bad data)");
! 1715: }
! 1716: errs++;
! 1717: }
! 1718: else
! 1719: if (trace)
! 1720: {
! 1721: PRINTF("\r %.*s ", 59 - offset, &buf[offset]);
! 1722: }
! 1723:
! 1724:
! 1725: buf[0] = c;
! 1726:
! 1727: /*
! 1728: * collect first character
! 1729: */
! 1730: if (((c^0xFF)+1) & (c^0xFF))
! 1731: pbuf[0] = '?';
! 1732: else
! 1733: pbuf[0] = type(c) ? '#' : '-';
! 1734:
! 1735: for ( i = 1; i < 60; i++)
! 1736: pbuf[i] = '.';
! 1737:
! 1738: i = 0;
! 1739: }
! 1740: else
! 1741: {
! 1742: /*
! 1743: * collect character
! 1744: */
! 1745: buf[i] = c;
! 1746:
! 1747: /*
! 1748: * initial guess (usually correct)
! 1749: */
! 1750: if (((c^0xFF)+1) & (c^0xFF))
! 1751: pbuf[i] = '?';
! 1752: else
! 1753: pbuf[i] = type(c) ? '#' : '-';
! 1754:
! 1755: PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]);
! 1756: }
! 1757:
! 1758: if (i == 0 && rtc == CVT_OK)
! 1759: {
! 1760: /*
! 1761: * we got a good time code here - try to convert it to
! 1762: * UTC
! 1763: */
! 1764: if ((utc_time = dcf_to_unixtime(&clock_time, &rtc)) == -1)
! 1765: {
! 1766: PRINTF("*** BAD CONVERSION\n");
! 1767: }
! 1768:
! 1769: if (utc_time != (last_utc_time + 60))
! 1770: {
! 1771: /*
! 1772: * well, two successive sucessful telegrams are not 60 seconds
! 1773: * apart
! 1774: */
! 1775: PRINTF("*** NO MINUTE INC\n");
! 1776: if (sync_state == SYNC)
! 1777: {
! 1778: sync_state = NO_SYNC;
! 1779: syslog(LOG_INFO, "DCF77 reception lost (data mismatch)");
! 1780: }
! 1781: errs++;
! 1782: rtc = CVT_FAIL|CVT_BADTIME|CVT_BADDATE;
! 1783: }
! 1784: else
! 1785: usecerror = 0;
! 1786:
! 1787: last_utc_time = utc_time;
! 1788: }
! 1789:
! 1790: if (rtc == CVT_OK)
! 1791: {
! 1792: if (i == 0)
! 1793: {
! 1794: /*
! 1795: * valid time code - determine offset and
! 1796: * note regained reception
! 1797: */
! 1798: last_sync = ticks;
! 1799: if (sync_state == NO_SYNC)
! 1800: {
! 1801: syslog(LOG_INFO, "receiving DCF77");
! 1802: }
! 1803: else
! 1804: {
! 1805: /*
! 1806: * we had at least one minute SYNC - thus
! 1807: * last error is valid
! 1808: */
! 1809: time_offset.tv_sec = lasterror / 1000000;
! 1810: time_offset.tv_usec = lasterror % 1000000;
! 1811: adjust_clock(&time_offset, drift_file, utc_time);
! 1812: }
! 1813: sync_state = SYNC;
! 1814: }
! 1815:
! 1816: time_offset.tv_sec = utc_time + i;
! 1817: time_offset.tv_usec = 0;
! 1818:
! 1819: timeradd(&time_offset, &phase);
! 1820:
! 1821: usecerror += (time_offset.tv_sec - tt.tv_sec) * 1000000 + time_offset.tv_usec
! 1822: -tt.tv_usec;
! 1823:
! 1824: /*
! 1825: * output interpreted DCF77 data
! 1826: */
! 1827: PRINTF(offsets ? "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s> (%c%ld.%06lds)" :
! 1828: "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s>",
! 1829: wday[clock_time.wday],
! 1830: clock_time.hour, clock_time.minute, i, clock_time.day, clock_time.month,
! 1831: clock_time.year,
! 1832: (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_",
! 1833: (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_",
! 1834: (clock_time.flags & DCFB_DST) ? "D" : "_",
! 1835: (clock_time.flags & DCFB_LEAP) ? "L" : "_",
! 1836: (lasterror < 0) ? '-' : '+', l_abs(lasterror) / 1000000, l_abs(lasterror) % 1000000
! 1837: );
! 1838:
! 1839: if (trace && (i == 0))
! 1840: {
! 1841: PRINTF("\n");
! 1842: errs++;
! 1843: }
! 1844: lasterror = usecerror / (i+1);
! 1845: }
! 1846: else
! 1847: {
! 1848: lasterror = 0; /* we cannot calculate phase errors on bad reception */
! 1849: }
! 1850:
! 1851: PRINTF("\r");
! 1852:
! 1853: if (i < 60)
! 1854: {
! 1855: i++;
! 1856: }
! 1857:
! 1858: tlast = tt;
! 1859:
! 1860: if (interactive)
! 1861: fflush(stdout);
! 1862: }
! 1863: } while ((rrc == -1) && (errno == EINTR));
! 1864:
! 1865: /*
! 1866: * lost IO - sorry guys
! 1867: */
! 1868: syslog(LOG_ERR, "TERMINATING - cannot read from device %s (%m)", file);
! 1869:
! 1870: (void)close(fd);
! 1871: }
! 1872:
! 1873: closelog();
! 1874:
! 1875: return 0;
! 1876: }
! 1877:
! 1878: /*
! 1879: * History:
! 1880: *
! 1881: * dcfd.c,v
! 1882: * Revision 4.18 2005/10/07 22:08:18 kardel
! 1883: * make dcfd.c compile on NetBSD 3.99.9 again (configure/sigvec compatibility fix)
! 1884: *
! 1885: * Revision 4.17.2.1 2005/10/03 19:15:16 kardel
! 1886: * work around configure not detecting a missing sigvec compatibility
! 1887: * interface on NetBSD 3.99.9 and above
! 1888: *
! 1889: * Revision 4.17 2005/08/10 10:09:44 kardel
! 1890: * output revision information
! 1891: *
! 1892: * Revision 4.16 2005/08/10 06:33:25 kardel
! 1893: * cleanup warnings
! 1894: *
! 1895: * Revision 4.15 2005/08/10 06:28:45 kardel
! 1896: * fix setting of baud rate
! 1897: *
! 1898: * Revision 4.14 2005/04/16 17:32:10 kardel
! 1899: * update copyright
! 1900: *
! 1901: * Revision 4.13 2004/11/14 15:29:41 kardel
! 1902: * support PPSAPI, upgrade Copyright to Berkeley style
! 1903: *
! 1904: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>