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