Annotation of embedaddon/ntp/parseutil/dcfd.c, revision 1.1.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>