Home | History | Annotate | Line # | Download | only in parseutil
dcfd.c revision 1.1
      1  1.1  kardel /*	$NetBSD: dcfd.c,v 1.1 2009/12/13 16:56:35 kardel 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.1  kardel 			dprintf(("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer));
    593  1.1  kardel 			*s = (unsigned char)~0;
    594  1.1  kardel 			rtc = CVT_FAIL|CVT_BADFMT;
    595  1.1  kardel 		}
    596  1.1  kardel 		s++;
    597  1.1  kardel 	}
    598  1.1  kardel 
    599  1.1  kardel 	/*
    600  1.1  kardel 	 * first cutoff estimate (average bit count - must be between both
    601  1.1  kardel 	 * maxima)
    602  1.1  kardel 	 */
    603  1.1  kardel 	if (lowmax)
    604  1.1  kardel 	{
    605  1.1  kardel 		cutoff /= lowmax;
    606  1.1  kardel 	}
    607  1.1  kardel 	else
    608  1.1  kardel 	{
    609  1.1  kardel 		cutoff = 4;	/* doesn't really matter - it'll fail anyway, but gives error output */
    610  1.1  kardel 	}
    611  1.1  kardel 
    612  1.1  kardel 	dprintf(("parse: cvt_rawdcf: average bit count: %d\n", cutoff));
    613  1.1  kardel 
    614  1.1  kardel 	lowmax = 0;  /* weighted sum */
    615  1.1  kardel 	highmax = 0; /* bitcount */
    616  1.1  kardel 
    617  1.1  kardel 	/*
    618  1.1  kardel 	 * collect weighted sum of lower bits (left of initial guess)
    619  1.1  kardel 	 */
    620  1.1  kardel 	dprintf(("parse: cvt_rawdcf: histogram:"));
    621  1.1  kardel 	for (i = 0; i <= cutoff; i++)
    622  1.1  kardel 	{
    623  1.1  kardel 		lowmax  += histbuf[i] * i;
    624  1.1  kardel 		highmax += histbuf[i];
    625  1.1  kardel 		dprintf((" %d", histbuf[i]));
    626  1.1  kardel 	}
    627  1.1  kardel 	dprintf((" <M>"));
    628  1.1  kardel 
    629  1.1  kardel 	/*
    630  1.1  kardel 	 * round up
    631  1.1  kardel 	 */
    632  1.1  kardel 	lowmax += highmax / 2;
    633  1.1  kardel 
    634  1.1  kardel 	/*
    635  1.1  kardel 	 * calculate lower bit maximum (weighted sum / bit count)
    636  1.1  kardel 	 *
    637  1.1  kardel 	 * avoid divide by zero
    638  1.1  kardel 	 */
    639  1.1  kardel 	if (highmax)
    640  1.1  kardel 	{
    641  1.1  kardel 		lowmax /= highmax;
    642  1.1  kardel 	}
    643  1.1  kardel 	else
    644  1.1  kardel 	{
    645  1.1  kardel 		lowmax = 0;
    646  1.1  kardel 	}
    647  1.1  kardel 
    648  1.1  kardel 	highmax = 0; /* weighted sum of upper bits counts */
    649  1.1  kardel 	cutoff = 0;  /* bitcount */
    650  1.1  kardel 
    651  1.1  kardel 	/*
    652  1.1  kardel 	 * collect weighted sum of lower bits (right of initial guess)
    653  1.1  kardel 	 */
    654  1.1  kardel 	for (; i < BITS; i++)
    655  1.1  kardel 	{
    656  1.1  kardel 		highmax+=histbuf[i] * i;
    657  1.1  kardel 		cutoff +=histbuf[i];
    658  1.1  kardel 		dprintf((" %d", histbuf[i]));
    659  1.1  kardel 	}
    660  1.1  kardel 	dprintf(("\n"));
    661  1.1  kardel 
    662  1.1  kardel 	/*
    663  1.1  kardel 	 * determine upper maximum (weighted sum / bit count)
    664  1.1  kardel 	 */
    665  1.1  kardel 	if (cutoff)
    666  1.1  kardel 	{
    667  1.1  kardel 		highmax /= cutoff;
    668  1.1  kardel 	}
    669  1.1  kardel 	else
    670  1.1  kardel 	{
    671  1.1  kardel 		highmax = BITS-1;
    672  1.1  kardel 	}
    673  1.1  kardel 
    674  1.1  kardel 	/*
    675  1.1  kardel 	 * following now holds:
    676  1.1  kardel 	 * lowmax <= cutoff(initial guess) <= highmax
    677  1.1  kardel 	 * best cutoff is the minimum nearest to higher bits
    678  1.1  kardel 	 */
    679  1.1  kardel 
    680  1.1  kardel 	/*
    681  1.1  kardel 	 * find the minimum between lowmax and highmax (detecting
    682  1.1  kardel 	 * possibly a minimum span)
    683  1.1  kardel 	 */
    684  1.1  kardel 	span = cutoff = lowmax;
    685  1.1  kardel 	for (i = lowmax; i <= highmax; i++)
    686  1.1  kardel 	{
    687  1.1  kardel 		if (histbuf[cutoff] > histbuf[i])
    688  1.1  kardel 		{
    689  1.1  kardel 			/*
    690  1.1  kardel 			 * got a new minimum move beginning of minimum (cutoff) and
    691  1.1  kardel 			 * end of minimum (span) there
    692  1.1  kardel 			 */
    693  1.1  kardel 			cutoff = span = i;
    694  1.1  kardel 		}
    695  1.1  kardel 		else
    696  1.1  kardel 		    if (histbuf[cutoff] == histbuf[i])
    697  1.1  kardel 		    {
    698  1.1  kardel 			    /*
    699  1.1  kardel 			     * minimum not better yet - but it spans more than
    700  1.1  kardel 			     * one bit value - follow it
    701  1.1  kardel 			     */
    702  1.1  kardel 			    span = i;
    703  1.1  kardel 		    }
    704  1.1  kardel 	}
    705  1.1  kardel 
    706  1.1  kardel 	/*
    707  1.1  kardel 	 * cutoff point for 1/0 decision is the middle of the minimum section
    708  1.1  kardel 	 * in the histogram
    709  1.1  kardel 	 */
    710  1.1  kardel 	cutoff = (cutoff + span) / 2;
    711  1.1  kardel 
    712  1.1  kardel 	dprintf(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff));
    713  1.1  kardel 
    714  1.1  kardel 	/*
    715  1.1  kardel 	 * convert the bit counts to symbolic 1/0 information for data conversion
    716  1.1  kardel 	 */
    717  1.1  kardel 	s = buffer;
    718  1.1  kardel 	while ((s < e) && *c && *b)
    719  1.1  kardel 	{
    720  1.1  kardel 		if (*s == (unsigned char)~0)
    721  1.1  kardel 		{
    722  1.1  kardel 			/*
    723  1.1  kardel 			 * invalid character
    724  1.1  kardel 			 */
    725  1.1  kardel 			*s = '?';
    726  1.1  kardel 		}
    727  1.1  kardel 		else
    728  1.1  kardel 		{
    729  1.1  kardel 			/*
    730  1.1  kardel 			 * symbolic 1/0 representation
    731  1.1  kardel 			 */
    732  1.1  kardel 			*s = (*s >= cutoff) ? *b : *c;
    733  1.1  kardel 		}
    734  1.1  kardel 		s++;
    735  1.1  kardel 		b++;
    736  1.1  kardel 		c++;
    737  1.1  kardel 	}
    738  1.1  kardel 
    739  1.1  kardel 	/*
    740  1.1  kardel 	 * if everything went well so far return the result of the symbolic
    741  1.1  kardel 	 * conversion routine else just the accumulated errors
    742  1.1  kardel 	 */
    743  1.1  kardel 	if (rtc != CVT_NONE)
    744  1.1  kardel 	{
    745  1.1  kardel 		PRINTF("%-30s", "*** BAD DATA");
    746  1.1  kardel 	}
    747  1.1  kardel 
    748  1.1  kardel 	return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock_time) : rtc;
    749  1.1  kardel }
    750  1.1  kardel 
    751  1.1  kardel /*-----------------------------------------------------------------------
    752  1.1  kardel  * convert a wall clock time description of DCF77 to a Unix time (seconds
    753  1.1  kardel  * since 1.1. 1970 UTC)
    754  1.1  kardel  */
    755  1.1  kardel static time_t
    756  1.1  kardel dcf_to_unixtime(
    757  1.1  kardel 		clocktime_t   *clock_time,
    758  1.1  kardel 		unsigned *cvtrtc
    759  1.1  kardel 		)
    760  1.1  kardel {
    761  1.1  kardel #define SETRTC(_X_)	{ if (cvtrtc) *cvtrtc = (_X_); }
    762  1.1  kardel 	static int days_of_month[] =
    763  1.1  kardel 	{
    764  1.1  kardel 		0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    765  1.1  kardel 	};
    766  1.1  kardel 	register int i;
    767  1.1  kardel 	time_t t;
    768  1.1  kardel 
    769  1.1  kardel 	/*
    770  1.1  kardel 	 * map 2 digit years to 19xx (DCF77 is a 20th century item)
    771  1.1  kardel 	 */
    772  1.1  kardel 	if ( clock_time->year < YEAR_PIVOT ) 	/* in case of	   Y2KFixes [ */
    773  1.1  kardel 		clock_time->year += 100;	/* *year%100, make tm_year */
    774  1.1  kardel 						/* *(do we need this?) */
    775  1.1  kardel 	if ( clock_time->year < YEAR_BREAK )	/* (failsafe if) */
    776  1.1  kardel 	    clock_time->year += 1900;				/* Y2KFixes ] */
    777  1.1  kardel 
    778  1.1  kardel 	/*
    779  1.1  kardel 	 * must have been a really bad year code - drop it
    780  1.1  kardel 	 */
    781  1.1  kardel 	if (clock_time->year < (YEAR_PIVOT + 1900) )		/* Y2KFixes */
    782  1.1  kardel 	{
    783  1.1  kardel 		SETRTC(CVT_FAIL|CVT_BADDATE);
    784  1.1  kardel 		return -1;
    785  1.1  kardel 	}
    786  1.1  kardel 	/*
    787  1.1  kardel 	 * sorry, slow section here - but it's not time critical anyway
    788  1.1  kardel 	 */
    789  1.1  kardel 
    790  1.1  kardel 	/*
    791  1.1  kardel 	 * calculate days since 1970 (watching leap years)
    792  1.1  kardel 	 */
    793  1.1  kardel 	t = julian0( clock_time->year ) - julian0( 1970 );
    794  1.1  kardel 
    795  1.1  kardel   				/* month */
    796  1.1  kardel 	if (clock_time->month <= 0 || clock_time->month > 12)
    797  1.1  kardel 	{
    798  1.1  kardel 		SETRTC(CVT_FAIL|CVT_BADDATE);
    799  1.1  kardel 		return -1;		/* bad month */
    800  1.1  kardel 	}
    801  1.1  kardel 				/* adjust current leap year */
    802  1.1  kardel #if 0
    803  1.1  kardel 	if (clock_time->month < 3 && days_per_year(clock_time->year) == 366)
    804  1.1  kardel 	    t--;
    805  1.1  kardel #endif
    806  1.1  kardel 
    807  1.1  kardel 	/*
    808  1.1  kardel 	 * collect days from months excluding the current one
    809  1.1  kardel 	 */
    810  1.1  kardel 	for (i = 1; i < clock_time->month; i++)
    811  1.1  kardel 	{
    812  1.1  kardel 		t += days_of_month[i];
    813  1.1  kardel 	}
    814  1.1  kardel 				/* day */
    815  1.1  kardel 	if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ?
    816  1.1  kardel 			       clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month]))
    817  1.1  kardel 	{
    818  1.1  kardel 		SETRTC(CVT_FAIL|CVT_BADDATE);
    819  1.1  kardel 		return -1;		/* bad day */
    820  1.1  kardel 	}
    821  1.1  kardel 
    822  1.1  kardel 	/*
    823  1.1  kardel 	 * collect days from date excluding the current one
    824  1.1  kardel 	 */
    825  1.1  kardel 	t += clock_time->day - 1;
    826  1.1  kardel 
    827  1.1  kardel 				/* hour */
    828  1.1  kardel 	if (clock_time->hour < 0 || clock_time->hour >= 24)
    829  1.1  kardel 	{
    830  1.1  kardel 		SETRTC(CVT_FAIL|CVT_BADTIME);
    831  1.1  kardel 		return -1;		/* bad hour */
    832  1.1  kardel 	}
    833  1.1  kardel 
    834  1.1  kardel 	/*
    835  1.1  kardel 	 * calculate hours from 1. 1. 1970
    836  1.1  kardel 	 */
    837  1.1  kardel 	t = TIMES24(t) + clock_time->hour;
    838  1.1  kardel 
    839  1.1  kardel   				/* min */
    840  1.1  kardel 	if (clock_time->minute < 0 || clock_time->minute > 59)
    841  1.1  kardel 	{
    842  1.1  kardel 		SETRTC(CVT_FAIL|CVT_BADTIME);
    843  1.1  kardel 		return -1;		/* bad min */
    844  1.1  kardel 	}
    845  1.1  kardel 
    846  1.1  kardel 	/*
    847  1.1  kardel 	 * calculate minutes from 1. 1. 1970
    848  1.1  kardel 	 */
    849  1.1  kardel 	t = TIMES60(t) + clock_time->minute;
    850  1.1  kardel 				/* sec */
    851  1.1  kardel 
    852  1.1  kardel 	/*
    853  1.1  kardel 	 * calculate UTC in minutes
    854  1.1  kardel 	 */
    855  1.1  kardel 	t += clock_time->utcoffset;
    856  1.1  kardel 
    857  1.1  kardel 	if (clock_time->second < 0 || clock_time->second > 60)	/* allow for LEAPs */
    858  1.1  kardel 	{
    859  1.1  kardel 		SETRTC(CVT_FAIL|CVT_BADTIME);
    860  1.1  kardel 		return -1;		/* bad sec */
    861  1.1  kardel 	}
    862  1.1  kardel 
    863  1.1  kardel 	/*
    864  1.1  kardel 	 * calculate UTC in seconds - phew !
    865  1.1  kardel 	 */
    866  1.1  kardel 	t  = TIMES60(t) + clock_time->second;
    867  1.1  kardel 				/* done */
    868  1.1  kardel 	return t;
    869  1.1  kardel }
    870  1.1  kardel 
    871  1.1  kardel /*-----------------------------------------------------------------------
    872  1.1  kardel  * cheap half baked 1/0 decision - for interactive operation only
    873  1.1  kardel  */
    874  1.1  kardel static char
    875  1.1  kardel type(
    876  1.1  kardel      unsigned int c
    877  1.1  kardel      )
    878  1.1  kardel {
    879  1.1  kardel 	c ^= 0xFF;
    880  1.1  kardel 	return (c > 0xF);
    881  1.1  kardel }
    882  1.1  kardel 
    883  1.1  kardel /*-----------------------------------------------------------------------
    884  1.1  kardel  * week day representation
    885  1.1  kardel  */
    886  1.1  kardel static const char *wday[8] =
    887  1.1  kardel {
    888  1.1  kardel 	"??",
    889  1.1  kardel 	"Mo",
    890  1.1  kardel 	"Tu",
    891  1.1  kardel 	"We",
    892  1.1  kardel 	"Th",
    893  1.1  kardel 	"Fr",
    894  1.1  kardel 	"Sa",
    895  1.1  kardel 	"Su"
    896  1.1  kardel };
    897  1.1  kardel 
    898  1.1  kardel /*-----------------------------------------------------------------------
    899  1.1  kardel  * generate a string representation for a timeval
    900  1.1  kardel  */
    901  1.1  kardel static char *
    902  1.1  kardel pr_timeval(
    903  1.1  kardel 	   struct timeval *val
    904  1.1  kardel 	   )
    905  1.1  kardel {
    906  1.1  kardel 	static char buf[20];
    907  1.1  kardel 
    908  1.1  kardel 	if (val->tv_sec == 0)
    909  1.1  kardel 	    sprintf(buf, "%c0.%06ld", (val->tv_usec < 0) ? '-' : '+', (long int)l_abs(val->tv_usec));
    910  1.1  kardel 	else
    911  1.1  kardel 	    sprintf(buf, "%ld.%06ld", (long int)val->tv_sec, (long int)l_abs(val->tv_usec));
    912  1.1  kardel 	return buf;
    913  1.1  kardel }
    914  1.1  kardel 
    915  1.1  kardel /*-----------------------------------------------------------------------
    916  1.1  kardel  * correct the current time by an offset by setting the time rigorously
    917  1.1  kardel  */
    918  1.1  kardel static void
    919  1.1  kardel set_time(
    920  1.1  kardel 	 struct timeval *offset
    921  1.1  kardel 	 )
    922  1.1  kardel {
    923  1.1  kardel 	struct timeval the_time;
    924  1.1  kardel 
    925  1.1  kardel 	if (no_set)
    926  1.1  kardel 	    return;
    927  1.1  kardel 
    928  1.1  kardel 	LPRINTF("set_time: %s ", pr_timeval(offset));
    929  1.1  kardel 	syslog(LOG_NOTICE, "setting time (offset %s)", pr_timeval(offset));
    930  1.1  kardel 
    931  1.1  kardel 	if (gettimeofday(&the_time, 0L) == -1)
    932  1.1  kardel 	{
    933  1.1  kardel 		perror("gettimeofday()");
    934  1.1  kardel 	}
    935  1.1  kardel 	else
    936  1.1  kardel 	{
    937  1.1  kardel 		timeradd(&the_time, offset);
    938  1.1  kardel 		if (settimeofday(&the_time, 0L) == -1)
    939  1.1  kardel 		{
    940  1.1  kardel 			perror("settimeofday()");
    941  1.1  kardel 		}
    942  1.1  kardel 	}
    943  1.1  kardel }
    944  1.1  kardel 
    945  1.1  kardel /*-----------------------------------------------------------------------
    946  1.1  kardel  * slew the time by a given offset
    947  1.1  kardel  */
    948  1.1  kardel static void
    949  1.1  kardel adj_time(
    950  1.1  kardel 	 long offset
    951  1.1  kardel 	 )
    952  1.1  kardel {
    953  1.1  kardel 	struct timeval time_offset;
    954  1.1  kardel 
    955  1.1  kardel 	if (no_set)
    956  1.1  kardel 	    return;
    957  1.1  kardel 
    958  1.1  kardel 	time_offset.tv_sec  = offset / 1000000;
    959  1.1  kardel 	time_offset.tv_usec = offset % 1000000;
    960  1.1  kardel 
    961  1.1  kardel 	LPRINTF("adj_time: %ld us ", (long int)offset);
    962  1.1  kardel 	if (adjtime(&time_offset, 0L) == -1)
    963  1.1  kardel 	    perror("adjtime()");
    964  1.1  kardel }
    965  1.1  kardel 
    966  1.1  kardel /*-----------------------------------------------------------------------
    967  1.1  kardel  * read in a possibly previously written drift value
    968  1.1  kardel  */
    969  1.1  kardel static void
    970  1.1  kardel read_drift(
    971  1.1  kardel 	   const char *drift_file
    972  1.1  kardel 	   )
    973  1.1  kardel {
    974  1.1  kardel 	FILE *df;
    975  1.1  kardel 
    976  1.1  kardel 	df = fopen(drift_file, "r");
    977  1.1  kardel 	if (df != NULL)
    978  1.1  kardel 	{
    979  1.1  kardel 		int idrift = 0, fdrift = 0;
    980  1.1  kardel 
    981  1.1  kardel 		fscanf(df, "%4d.%03d", &idrift, &fdrift);
    982  1.1  kardel 		fclose(df);
    983  1.1  kardel 		LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift);
    984  1.1  kardel 
    985  1.1  kardel 		accum_drift = idrift << USECSCALE;
    986  1.1  kardel 		fdrift     = (fdrift << USECSCALE) / 1000;
    987  1.1  kardel 		accum_drift += fdrift & (1<<USECSCALE);
    988  1.1  kardel 		LPRINTF("read_drift: drift_comp %ld ", (long int)accum_drift);
    989  1.1  kardel 	}
    990  1.1  kardel }
    991  1.1  kardel 
    992  1.1  kardel /*-----------------------------------------------------------------------
    993  1.1  kardel  * write out the current drift value
    994  1.1  kardel  */
    995  1.1  kardel static void
    996  1.1  kardel update_drift(
    997  1.1  kardel 	     const char *drift_file,
    998  1.1  kardel 	     long offset,
    999  1.1  kardel 	     time_t reftime
   1000  1.1  kardel 	     )
   1001  1.1  kardel {
   1002  1.1  kardel 	FILE *df;
   1003  1.1  kardel 
   1004  1.1  kardel 	df = fopen(drift_file, "w");
   1005  1.1  kardel 	if (df != NULL)
   1006  1.1  kardel 	{
   1007  1.1  kardel 		int idrift = R_SHIFT(accum_drift, USECSCALE);
   1008  1.1  kardel 		int fdrift = accum_drift & ((1<<USECSCALE)-1);
   1009  1.1  kardel 
   1010  1.1  kardel 		LPRINTF("update_drift: drift_comp %ld ", (long int)accum_drift);
   1011  1.1  kardel 		fdrift = (fdrift * 1000) / (1<<USECSCALE);
   1012  1.1  kardel 		fprintf(df, "%4d.%03d %c%ld.%06ld %.24s\n", idrift, fdrift,
   1013  1.1  kardel 			(offset < 0) ? '-' : '+', (long int)(l_abs(offset) / 1000000),
   1014  1.1  kardel 			(long int)(l_abs(offset) % 1000000), asctime(localtime(&reftime)));
   1015  1.1  kardel 		fclose(df);
   1016  1.1  kardel 		LPRINTF("update_drift: %d.%03d ppm ", idrift, fdrift);
   1017  1.1  kardel 	}
   1018  1.1  kardel }
   1019  1.1  kardel 
   1020  1.1  kardel /*-----------------------------------------------------------------------
   1021  1.1  kardel  * process adjustments derived from the DCF77 observation
   1022  1.1  kardel  * (controls clock PLL)
   1023  1.1  kardel  */
   1024  1.1  kardel static void
   1025  1.1  kardel adjust_clock(
   1026  1.1  kardel 	     struct timeval *offset,
   1027  1.1  kardel 	     const char *drift_file,
   1028  1.1  kardel 	     time_t reftime
   1029  1.1  kardel 	     )
   1030  1.1  kardel {
   1031  1.1  kardel 	struct timeval toffset;
   1032  1.1  kardel 	register long usecoffset;
   1033  1.1  kardel 	int tmp;
   1034  1.1  kardel 
   1035  1.1  kardel 	if (no_set)
   1036  1.1  kardel 	    return;
   1037  1.1  kardel 
   1038  1.1  kardel 	if (skip_adjust)
   1039  1.1  kardel 	{
   1040  1.1  kardel 		skip_adjust = 0;
   1041  1.1  kardel 		return;
   1042  1.1  kardel 	}
   1043  1.1  kardel 
   1044  1.1  kardel 	toffset = *offset;
   1045  1.1  kardel 	toffset.tv_sec  = l_abs(toffset.tv_sec);
   1046  1.1  kardel 	toffset.tv_usec = l_abs(toffset.tv_usec);
   1047  1.1  kardel 	if (toffset.tv_sec ||
   1048  1.1  kardel 	    (!toffset.tv_sec && toffset.tv_usec > max_adj_offset_usec))
   1049  1.1  kardel 	{
   1050  1.1  kardel 		/*
   1051  1.1  kardel 		 * hopeless - set the clock - and clear the timing
   1052  1.1  kardel 		 */
   1053  1.1  kardel 		set_time(offset);
   1054  1.1  kardel 		clock_adjust = 0;
   1055  1.1  kardel 		skip_adjust  = 1;
   1056  1.1  kardel 		return;
   1057  1.1  kardel 	}
   1058  1.1  kardel 
   1059  1.1  kardel 	usecoffset   = offset->tv_sec * 1000000 + offset->tv_usec;
   1060  1.1  kardel 
   1061  1.1  kardel 	clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT);	/* adjustment to make for next period */
   1062  1.1  kardel 
   1063  1.1  kardel 	tmp = 0;
   1064  1.1  kardel 	while (adjustments > (1 << tmp))
   1065  1.1  kardel 	    tmp++;
   1066  1.1  kardel 	adjustments = 0;
   1067  1.1  kardel 	if (tmp > FREQ_WEIGHT)
   1068  1.1  kardel 	    tmp = FREQ_WEIGHT;
   1069  1.1  kardel 
   1070  1.1  kardel 	accum_drift  += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp);
   1071  1.1  kardel 
   1072  1.1  kardel 	if (accum_drift > MAX_DRIFT)		/* clamp into interval */
   1073  1.1  kardel 	    accum_drift = MAX_DRIFT;
   1074  1.1  kardel 	else
   1075  1.1  kardel 	    if (accum_drift < -MAX_DRIFT)
   1076  1.1  kardel 		accum_drift = -MAX_DRIFT;
   1077  1.1  kardel 
   1078  1.1  kardel 	update_drift(drift_file, usecoffset, reftime);
   1079  1.1  kardel 	LPRINTF("clock_adjust: %s, clock_adjust %ld, drift_comp %ld(%ld) ",
   1080  1.1  kardel 		pr_timeval(offset),(long int) R_SHIFT(clock_adjust, USECSCALE),
   1081  1.1  kardel 		(long int)R_SHIFT(accum_drift, USECSCALE), (long int)accum_drift);
   1082  1.1  kardel }
   1083  1.1  kardel 
   1084  1.1  kardel /*-----------------------------------------------------------------------
   1085  1.1  kardel  * adjust the clock by a small mount to simulate frequency correction
   1086  1.1  kardel  */
   1087  1.1  kardel static void
   1088  1.1  kardel periodic_adjust(
   1089  1.1  kardel 		void
   1090  1.1  kardel 		)
   1091  1.1  kardel {
   1092  1.1  kardel 	register long adjustment;
   1093  1.1  kardel 
   1094  1.1  kardel 	adjustments++;
   1095  1.1  kardel 
   1096  1.1  kardel 	adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT);
   1097  1.1  kardel 
   1098  1.1  kardel 	clock_adjust -= adjustment;
   1099  1.1  kardel 
   1100  1.1  kardel 	adjustment += R_SHIFT(accum_drift, USECSCALE+ADJINTERVAL);
   1101  1.1  kardel 
   1102  1.1  kardel 	adj_time(adjustment);
   1103  1.1  kardel }
   1104  1.1  kardel 
   1105  1.1  kardel /*-----------------------------------------------------------------------
   1106  1.1  kardel  * control synchronisation status (warnings) and do periodic adjusts
   1107  1.1  kardel  * (frequency control simulation)
   1108  1.1  kardel  */
   1109  1.1  kardel static void
   1110  1.1  kardel tick(
   1111  1.1  kardel      int signum
   1112  1.1  kardel      )
   1113  1.1  kardel {
   1114  1.1  kardel 	static unsigned long last_notice = 0;
   1115  1.1  kardel 
   1116  1.1  kardel #if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC)
   1117  1.1  kardel 	(void)signal(SIGALRM, tick);
   1118  1.1  kardel #endif
   1119  1.1  kardel 
   1120  1.1  kardel 	periodic_adjust();
   1121  1.1  kardel 
   1122  1.1  kardel 	ticks += 1<<ADJINTERVAL;
   1123  1.1  kardel 
   1124  1.1  kardel 	if ((ticks - last_sync) > MAX_UNSYNC)
   1125  1.1  kardel 	{
   1126  1.1  kardel 		/*
   1127  1.1  kardel 		 * not getting time for a while
   1128  1.1  kardel 		 */
   1129  1.1  kardel 		if (sync_state == SYNC)
   1130  1.1  kardel 		{
   1131  1.1  kardel 			/*
   1132  1.1  kardel 			 * completely lost information
   1133  1.1  kardel 			 */
   1134  1.1  kardel 			sync_state = NO_SYNC;
   1135  1.1  kardel 			syslog(LOG_INFO, "DCF77 reception lost (timeout)");
   1136  1.1  kardel 			last_notice = ticks;
   1137  1.1  kardel 		}
   1138  1.1  kardel 		else
   1139  1.1  kardel 		    /*
   1140  1.1  kardel 		     * in NO_SYNC state - look whether its time to speak up again
   1141  1.1  kardel 		     */
   1142  1.1  kardel 		    if ((ticks - last_notice) > NOTICE_INTERVAL)
   1143  1.1  kardel 		    {
   1144  1.1  kardel 			    syslog(LOG_NOTICE, "still not synchronized to DCF77 - check receiver/signal");
   1145  1.1  kardel 			    last_notice = ticks;
   1146  1.1  kardel 		    }
   1147  1.1  kardel 	}
   1148  1.1  kardel 
   1149  1.1  kardel #ifndef ITIMER_REAL
   1150  1.1  kardel 	(void) alarm(1<<ADJINTERVAL);
   1151  1.1  kardel #endif
   1152  1.1  kardel }
   1153  1.1  kardel 
   1154  1.1  kardel /*-----------------------------------------------------------------------
   1155  1.1  kardel  * break association from terminal to avoid catching terminal
   1156  1.1  kardel  * or process group related signals (-> daemon operation)
   1157  1.1  kardel  */
   1158  1.1  kardel static void
   1159  1.1  kardel detach(
   1160  1.1  kardel        void
   1161  1.1  kardel        )
   1162  1.1  kardel {
   1163  1.1  kardel #   ifdef HAVE_DAEMON
   1164  1.1  kardel 	daemon(0, 0);
   1165  1.1  kardel #   else /* not HAVE_DAEMON */
   1166  1.1  kardel 	if (fork())
   1167  1.1  kardel 	    exit(0);
   1168  1.1  kardel 
   1169  1.1  kardel 	{
   1170  1.1  kardel 		u_long s;
   1171  1.1  kardel 		int max_fd;
   1172  1.1  kardel 
   1173  1.1  kardel #if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
   1174  1.1  kardel 		max_fd = sysconf(_SC_OPEN_MAX);
   1175  1.1  kardel #else /* HAVE_SYSCONF && _SC_OPEN_MAX */
   1176  1.1  kardel 		max_fd = getdtablesize();
   1177  1.1  kardel #endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
   1178  1.1  kardel 		for (s = 0; s < max_fd; s++)
   1179  1.1  kardel 		    (void) close((int)s);
   1180  1.1  kardel 		(void) open("/", 0);
   1181  1.1  kardel 		(void) dup2(0, 1);
   1182  1.1  kardel 		(void) dup2(0, 2);
   1183  1.1  kardel #ifdef SYS_DOMAINOS
   1184  1.1  kardel 		{
   1185  1.1  kardel 			uid_$t puid;
   1186  1.1  kardel 			status_$t st;
   1187  1.1  kardel 
   1188  1.1  kardel 			proc2_$who_am_i(&puid);
   1189  1.1  kardel 			proc2_$make_server(&puid, &st);
   1190  1.1  kardel 		}
   1191  1.1  kardel #endif /* SYS_DOMAINOS */
   1192  1.1  kardel #if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
   1193  1.1  kardel # ifdef HAVE_SETSID
   1194  1.1  kardel 		if (setsid() == (pid_t)-1)
   1195  1.1  kardel 		    syslog(LOG_ERR, "dcfd: setsid(): %m");
   1196  1.1  kardel # else
   1197  1.1  kardel 		if (setpgid(0, 0) == -1)
   1198  1.1  kardel 		    syslog(LOG_ERR, "dcfd: setpgid(): %m");
   1199  1.1  kardel # endif
   1200  1.1  kardel #else /* HAVE_SETPGID || HAVE_SETSID */
   1201  1.1  kardel 		{
   1202  1.1  kardel 			int fid;
   1203  1.1  kardel 
   1204  1.1  kardel 			fid = open("/dev/tty", 2);
   1205  1.1  kardel 			if (fid >= 0)
   1206  1.1  kardel 			{
   1207  1.1  kardel 				(void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
   1208  1.1  kardel 				(void) close(fid);
   1209  1.1  kardel 			}
   1210  1.1  kardel # ifdef HAVE_SETPGRP_0
   1211  1.1  kardel 			(void) setpgrp();
   1212  1.1  kardel # else /* HAVE_SETPGRP_0 */
   1213  1.1  kardel 			(void) setpgrp(0, getpid());
   1214  1.1  kardel # endif /* HAVE_SETPGRP_0 */
   1215  1.1  kardel 		}
   1216  1.1  kardel #endif /* HAVE_SETPGID || HAVE_SETSID */
   1217  1.1  kardel 	}
   1218  1.1  kardel #endif /* not HAVE_DAEMON */
   1219  1.1  kardel }
   1220  1.1  kardel 
   1221  1.1  kardel /*-----------------------------------------------------------------------
   1222  1.1  kardel  * list possible arguments and options
   1223  1.1  kardel  */
   1224  1.1  kardel static void
   1225  1.1  kardel usage(
   1226  1.1  kardel       char *program
   1227  1.1  kardel       )
   1228  1.1  kardel {
   1229  1.1  kardel   fprintf(stderr, "usage: %s [-n] [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] [-D <input delay>] <device>\n", program);
   1230  1.1  kardel 	fprintf(stderr, "\t-n              do not change time\n");
   1231  1.1  kardel 	fprintf(stderr, "\t-i              interactive\n");
   1232  1.1  kardel 	fprintf(stderr, "\t-t              trace (print all datagrams)\n");
   1233  1.1  kardel 	fprintf(stderr, "\t-f              print all databits (includes PTB private data)\n");
   1234  1.1  kardel 	fprintf(stderr, "\t-l              print loop filter debug information\n");
   1235  1.1  kardel 	fprintf(stderr, "\t-o              print offet average for current minute\n");
   1236  1.1  kardel 	fprintf(stderr, "\t-Y              make internal Y2K checks then exit\n");	/* Y2KFixes */
   1237  1.1  kardel 	fprintf(stderr, "\t-d <drift_file> specify alternate drift file\n");
   1238  1.1  kardel 	fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n");
   1239  1.1  kardel }
   1240  1.1  kardel 
   1241  1.1  kardel /*-----------------------------------------------------------------------
   1242  1.1  kardel  * check_y2k() - internal check of Y2K logic
   1243  1.1  kardel  *	(a lot of this logic lifted from ../ntpd/check_y2k.c)
   1244  1.1  kardel  */
   1245  1.1  kardel static int
   1246  1.1  kardel check_y2k( void )
   1247  1.1  kardel {
   1248  1.1  kardel     int  year;			/* current working year */
   1249  1.1  kardel     int  year0 = 1900;		/* sarting year for NTP time */
   1250  1.1  kardel     int  yearend;		/* ending year we test for NTP time.
   1251  1.1  kardel 				    * 32-bit systems: through 2036, the
   1252  1.1  kardel 				      **year in which NTP time overflows.
   1253  1.1  kardel 				    * 64-bit systems: a reasonable upper
   1254  1.1  kardel 				      **limit (well, maybe somewhat beyond
   1255  1.1  kardel 				      **reasonable, but well before the
   1256  1.1  kardel 				      **max time, by which time the earth
   1257  1.1  kardel 				      **will be dead.) */
   1258  1.1  kardel     time_t Time;
   1259  1.1  kardel     struct tm LocalTime;
   1260  1.1  kardel 
   1261  1.1  kardel     int Fatals, Warnings;
   1262  1.1  kardel #define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \
   1263  1.1  kardel 	Warnings++; else Fatals++
   1264  1.1  kardel 
   1265  1.1  kardel     Fatals = Warnings = 0;
   1266  1.1  kardel 
   1267  1.1  kardel     Time = time( (time_t *)NULL );
   1268  1.1  kardel     LocalTime = *localtime( &Time );
   1269  1.1  kardel 
   1270  1.1  kardel     year = ( sizeof( u_long ) > 4 ) 	/* save max span using year as temp */
   1271  1.1  kardel 		? ( 400 * 3 ) 		/* three greater gregorian cycles */
   1272  1.1  kardel 		: ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/
   1273  1.1  kardel 			/* NOTE: will automacially expand test years on
   1274  1.1  kardel 			 * 64 bit machines.... this may cause some of the
   1275  1.1  kardel 			 * existing ntp logic to fail for years beyond
   1276  1.1  kardel 			 * 2036 (the current 32-bit limit). If all checks
   1277  1.1  kardel 			 * fail ONLY beyond year 2036 you may ignore such
   1278  1.1  kardel 			 * errors, at least for a decade or so. */
   1279  1.1  kardel     yearend = year0 + year;
   1280  1.1  kardel 
   1281  1.1  kardel     year = 1900+YEAR_PIVOT;
   1282  1.1  kardel     printf( "  starting year %04d\n", (int) year );
   1283  1.1  kardel     printf( "  ending year   %04d\n", (int) yearend );
   1284  1.1  kardel 
   1285  1.1  kardel     for ( ; year < yearend; year++ )
   1286  1.1  kardel     {
   1287  1.1  kardel 	clocktime_t  ct;
   1288  1.1  kardel 	time_t	     Observed;
   1289  1.1  kardel 	time_t	     Expected;
   1290  1.1  kardel 	unsigned     Flag;
   1291  1.1  kardel 	unsigned long t;
   1292  1.1  kardel 
   1293  1.1  kardel 	ct.day = 1;
   1294  1.1  kardel 	ct.month = 1;
   1295  1.1  kardel 	ct.year = year;
   1296  1.1  kardel 	ct.hour = ct.minute = ct.second = ct.usecond = 0;
   1297  1.1  kardel 	ct.utcoffset = 0;
   1298  1.1  kardel 	ct.flags = 0;
   1299  1.1  kardel 
   1300  1.1  kardel 	Flag = 0;
   1301  1.1  kardel  	Observed = dcf_to_unixtime( &ct, &Flag );
   1302  1.1  kardel 		/* seems to be a clone of parse_to_unixtime() with
   1303  1.1  kardel 		 * *a minor difference to arg2 type */
   1304  1.1  kardel 	if ( ct.year != year )
   1305  1.1  kardel 	{
   1306  1.1  kardel 	    fprintf( stdout,
   1307  1.1  kardel 	       "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n",
   1308  1.1  kardel 	       (int)year, (int)Flag, (int)ct.year );
   1309  1.1  kardel 	    Error(year);
   1310  1.1  kardel 	    break;
   1311  1.1  kardel 	}
   1312  1.1  kardel 	t = julian0(year) - julian0(1970);	/* Julian day from 1970 */
   1313  1.1  kardel 	Expected = t * 24 * 60 * 60;
   1314  1.1  kardel 	if ( Observed != Expected  ||  Flag )
   1315  1.1  kardel 	{   /* time difference */
   1316  1.1  kardel 	    fprintf( stdout,
   1317  1.1  kardel 	       "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
   1318  1.1  kardel 	       year, (int)Flag,
   1319  1.1  kardel 	       (unsigned long)Observed, (unsigned long)Expected,
   1320  1.1  kardel 	       ((long)Observed - (long)Expected) );
   1321  1.1  kardel 	    Error(year);
   1322  1.1  kardel 	    break;
   1323  1.1  kardel 	}
   1324  1.1  kardel 
   1325  1.1  kardel 	if ( year >= YEAR_PIVOT+1900 )
   1326  1.1  kardel 	{
   1327  1.1  kardel 	    /* check year % 100 code we put into dcf_to_unixtime() */
   1328  1.1  kardel 	    ct.year = year % 100;
   1329  1.1  kardel 	    Flag = 0;
   1330  1.1  kardel 
   1331  1.1  kardel 	    Observed = dcf_to_unixtime( &ct, &Flag );
   1332  1.1  kardel 
   1333  1.1  kardel 	    if ( Observed != Expected  ||  Flag )
   1334  1.1  kardel 	    {   /* time difference */
   1335  1.1  kardel 		fprintf( stdout,
   1336  1.1  kardel "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
   1337  1.1  kardel 		   year, (int)ct.year, (int)Flag,
   1338  1.1  kardel 		   (unsigned long)Observed, (unsigned long)Expected,
   1339  1.1  kardel 		   ((long)Observed - (long)Expected) );
   1340  1.1  kardel 		Error(year);
   1341  1.1  kardel 		break;
   1342  1.1  kardel 	    }
   1343  1.1  kardel 
   1344  1.1  kardel 	    /* check year - 1900 code we put into dcf_to_unixtime() */
   1345  1.1  kardel 	    ct.year = year - 1900;
   1346  1.1  kardel 	    Flag = 0;
   1347  1.1  kardel 
   1348  1.1  kardel 	    Observed = dcf_to_unixtime( &ct, &Flag );
   1349  1.1  kardel 
   1350  1.1  kardel 	    if ( Observed != Expected  ||  Flag ) {   /* time difference */
   1351  1.1  kardel 		    fprintf( stdout,
   1352  1.1  kardel 			     "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu  (%ld)\n",
   1353  1.1  kardel 			     year, (int)ct.year, (int)Flag,
   1354  1.1  kardel 			     (unsigned long)Observed, (unsigned long)Expected,
   1355  1.1  kardel 			     ((long)Observed - (long)Expected) );
   1356  1.1  kardel 		    Error(year);
   1357  1.1  kardel 		break;
   1358  1.1  kardel 	    }
   1359  1.1  kardel 
   1360  1.1  kardel 
   1361  1.1  kardel 	}
   1362  1.1  kardel     }
   1363  1.1  kardel 
   1364  1.1  kardel     return ( Fatals );
   1365  1.1  kardel }
   1366  1.1  kardel 
   1367  1.1  kardel /*--------------------------------------------------
   1368  1.1  kardel  * rawdcf_init - set up modem lines for RAWDCF receivers
   1369  1.1  kardel  */
   1370  1.1  kardel #if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))
   1371  1.1  kardel static void
   1372  1.1  kardel rawdcf_init(
   1373  1.1  kardel 	int fd
   1374  1.1  kardel 	)
   1375  1.1  kardel {
   1376  1.1  kardel 	/*
   1377  1.1  kardel 	 * You can use the RS232 to supply the power for a DCF77 receiver.
   1378  1.1  kardel 	 * Here a voltage between the DTR and the RTS line is used. Unfortunately
   1379  1.1  kardel 	 * the name has changed from CIOCM_DTR to TIOCM_DTR recently.
   1380  1.1  kardel 	 */
   1381  1.1  kardel 
   1382  1.1  kardel #ifdef TIOCM_DTR
   1383  1.1  kardel 	int sl232 = TIOCM_DTR;	/* turn on DTR for power supply */
   1384  1.1  kardel #else
   1385  1.1  kardel 	int sl232 = CIOCM_DTR;	/* turn on DTR for power supply */
   1386  1.1  kardel #endif
   1387  1.1  kardel 
   1388  1.1  kardel 	if (ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)
   1389  1.1  kardel 	{
   1390  1.1  kardel 		syslog(LOG_NOTICE, "rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m");
   1391  1.1  kardel 	}
   1392  1.1  kardel }
   1393  1.1  kardel #else
   1394  1.1  kardel static void
   1395  1.1  kardel rawdcf_init(
   1396  1.1  kardel 	    int fd
   1397  1.1  kardel 	)
   1398  1.1  kardel {
   1399  1.1  kardel 	syslog(LOG_NOTICE, "rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules");
   1400  1.1  kardel }
   1401  1.1  kardel #endif  /* DTR initialisation type */
   1402  1.1  kardel 
   1403  1.1  kardel /*-----------------------------------------------------------------------
   1404  1.1  kardel  * main loop - argument interpreter / setup / main loop
   1405  1.1  kardel  */
   1406  1.1  kardel int
   1407  1.1  kardel main(
   1408  1.1  kardel      int argc,
   1409  1.1  kardel      char **argv
   1410  1.1  kardel      )
   1411  1.1  kardel {
   1412  1.1  kardel 	unsigned char c;
   1413  1.1  kardel 	char **a = argv;
   1414  1.1  kardel 	int  ac = argc;
   1415  1.1  kardel 	char *file = NULL;
   1416  1.1  kardel 	const char *drift_file = "/etc/dcfd.drift";
   1417  1.1  kardel 	int fd;
   1418  1.1  kardel 	int offset = 15;
   1419  1.1  kardel 	int offsets = 0;
   1420  1.1  kardel 	int delay = DEFAULT_DELAY;	/* average delay from input edge to time stamping */
   1421  1.1  kardel 	int trace = 0;
   1422  1.1  kardel 	int errs = 0;
   1423  1.1  kardel 
   1424  1.1  kardel 	/*
   1425  1.1  kardel 	 * process arguments
   1426  1.1  kardel 	 */
   1427  1.1  kardel 	while (--ac)
   1428  1.1  kardel 	{
   1429  1.1  kardel 		char *arg = *++a;
   1430  1.1  kardel 		if (*arg == '-')
   1431  1.1  kardel 		    while ((c = *++arg))
   1432  1.1  kardel 			switch (c)
   1433  1.1  kardel 			{
   1434  1.1  kardel 			    case 't':
   1435  1.1  kardel 				trace = 1;
   1436  1.1  kardel 				interactive = 1;
   1437  1.1  kardel 				break;
   1438  1.1  kardel 
   1439  1.1  kardel 			    case 'f':
   1440  1.1  kardel 				offset = 0;
   1441  1.1  kardel 				interactive = 1;
   1442  1.1  kardel 				break;
   1443  1.1  kardel 
   1444  1.1  kardel 			    case 'l':
   1445  1.1  kardel 				loop_filter_debug = 1;
   1446  1.1  kardel 				offsets = 1;
   1447  1.1  kardel 				interactive = 1;
   1448  1.1  kardel 				break;
   1449  1.1  kardel 
   1450  1.1  kardel 			    case 'n':
   1451  1.1  kardel 				no_set = 1;
   1452  1.1  kardel 				break;
   1453  1.1  kardel 
   1454  1.1  kardel 			    case 'o':
   1455  1.1  kardel 				offsets = 1;
   1456  1.1  kardel 				interactive = 1;
   1457  1.1  kardel 				break;
   1458  1.1  kardel 
   1459  1.1  kardel 			    case 'i':
   1460  1.1  kardel 				interactive = 1;
   1461  1.1  kardel 				break;
   1462  1.1  kardel 
   1463  1.1  kardel 			    case 'D':
   1464  1.1  kardel 				if (ac > 1)
   1465  1.1  kardel 				{
   1466  1.1  kardel 					delay = atoi(*++a);
   1467  1.1  kardel 					ac--;
   1468  1.1  kardel 				}
   1469  1.1  kardel 				else
   1470  1.1  kardel 				{
   1471  1.1  kardel 					fprintf(stderr, "%s: -D requires integer argument\n", argv[0]);
   1472  1.1  kardel 					errs=1;
   1473  1.1  kardel 				}
   1474  1.1  kardel 				break;
   1475  1.1  kardel 
   1476  1.1  kardel 			    case 'd':
   1477  1.1  kardel 				if (ac > 1)
   1478  1.1  kardel 				{
   1479  1.1  kardel 					drift_file = *++a;
   1480  1.1  kardel 					ac--;
   1481  1.1  kardel 				}
   1482  1.1  kardel 				else
   1483  1.1  kardel 				{
   1484  1.1  kardel 					fprintf(stderr, "%s: -d requires file name argument\n", argv[0]);
   1485  1.1  kardel 					errs=1;
   1486  1.1  kardel 				}
   1487  1.1  kardel 				break;
   1488  1.1  kardel 
   1489  1.1  kardel 			    case 'Y':
   1490  1.1  kardel 				errs=check_y2k();
   1491  1.1  kardel 				exit( errs ? 1 : 0 );
   1492  1.1  kardel 
   1493  1.1  kardel 			    default:
   1494  1.1  kardel 				fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
   1495  1.1  kardel 				errs=1;
   1496  1.1  kardel 				break;
   1497  1.1  kardel 			}
   1498  1.1  kardel 		else
   1499  1.1  kardel 		    if (file == NULL)
   1500  1.1  kardel 			file = arg;
   1501  1.1  kardel 		    else
   1502  1.1  kardel 		    {
   1503  1.1  kardel 			    fprintf(stderr, "%s: device specified twice\n", argv[0]);
   1504  1.1  kardel 			    errs=1;
   1505  1.1  kardel 		    }
   1506  1.1  kardel 	}
   1507  1.1  kardel 
   1508  1.1  kardel 	if (errs)
   1509  1.1  kardel 	{
   1510  1.1  kardel 		usage(argv[0]);
   1511  1.1  kardel 		exit(1);
   1512  1.1  kardel 	}
   1513  1.1  kardel 	else
   1514  1.1  kardel 	    if (file == NULL)
   1515  1.1  kardel 	    {
   1516  1.1  kardel 		    fprintf(stderr, "%s: device not specified\n", argv[0]);
   1517  1.1  kardel 		    usage(argv[0]);
   1518  1.1  kardel 		    exit(1);
   1519  1.1  kardel 	    }
   1520  1.1  kardel 
   1521  1.1  kardel 	errs = LINES+1;
   1522  1.1  kardel 
   1523  1.1  kardel 	/*
   1524  1.1  kardel 	 * get access to DCF77 tty port
   1525  1.1  kardel 	 */
   1526  1.1  kardel 	fd = open(file, O_RDONLY);
   1527  1.1  kardel 	if (fd == -1)
   1528  1.1  kardel 	{
   1529  1.1  kardel 		perror(file);
   1530  1.1  kardel 		exit(1);
   1531  1.1  kardel 	}
   1532  1.1  kardel 	else
   1533  1.1  kardel 	{
   1534  1.1  kardel 		int i, rrc;
   1535  1.1  kardel 		struct timeval t, tt, tlast;
   1536  1.1  kardel 		struct timeval timeout;
   1537  1.1  kardel 		struct timeval phase;
   1538  1.1  kardel 		struct timeval time_offset;
   1539  1.1  kardel 		char pbuf[61];		/* printable version */
   1540  1.1  kardel 		char buf[61];		/* raw data */
   1541  1.1  kardel 		clocktime_t clock_time;	/* wall clock time */
   1542  1.1  kardel 		time_t utc_time = 0;
   1543  1.1  kardel 		time_t last_utc_time = 0;
   1544  1.1  kardel 		long usecerror = 0;
   1545  1.1  kardel 		long lasterror = 0;
   1546  1.1  kardel #if defined(HAVE_TERMIOS_H) || defined(STREAM)
   1547  1.1  kardel 		struct termios term;
   1548  1.1  kardel #else  /* not HAVE_TERMIOS_H || STREAM */
   1549  1.1  kardel # if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS)
   1550  1.1  kardel 		struct termio term;
   1551  1.1  kardel # endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */
   1552  1.1  kardel #endif /* not HAVE_TERMIOS_H || STREAM */
   1553  1.1  kardel 		unsigned int rtc = CVT_NONE;
   1554  1.1  kardel 
   1555  1.1  kardel 		rawdcf_init(fd);
   1556  1.1  kardel 
   1557  1.1  kardel 		timeout.tv_sec  = 1;
   1558  1.1  kardel 		timeout.tv_usec = 500000;
   1559  1.1  kardel 
   1560  1.1  kardel 		phase.tv_sec    = 0;
   1561  1.1  kardel 		phase.tv_usec   = delay;
   1562  1.1  kardel 
   1563  1.1  kardel 		/*
   1564  1.1  kardel 		 * setup TTY (50 Baud, Read, 8Bit, No Hangup, 1 character IO)
   1565  1.1  kardel 		 */
   1566  1.1  kardel 		if (TTY_GETATTR(fd,  &term) == -1)
   1567  1.1  kardel 		{
   1568  1.1  kardel 			perror("tcgetattr");
   1569  1.1  kardel 			exit(1);
   1570  1.1  kardel 		}
   1571  1.1  kardel 
   1572  1.1  kardel 		memset(term.c_cc, 0, sizeof(term.c_cc));
   1573  1.1  kardel 		term.c_cc[VMIN] = 1;
   1574  1.1  kardel #ifdef NO_PARENB_IGNPAR
   1575  1.1  kardel 		term.c_cflag = CS8|CREAD|CLOCAL;
   1576  1.1  kardel #else
   1577  1.1  kardel 		term.c_cflag = CS8|CREAD|CLOCAL|PARENB;
   1578  1.1  kardel #endif
   1579  1.1  kardel 		term.c_iflag = IGNPAR;
   1580  1.1  kardel 		term.c_oflag = 0;
   1581  1.1  kardel 		term.c_lflag = 0;
   1582  1.1  kardel 
   1583  1.1  kardel 		cfsetispeed(&term, B50);
   1584  1.1  kardel 		cfsetospeed(&term, B50);
   1585  1.1  kardel 
   1586  1.1  kardel 		if (TTY_SETATTR(fd, &term) == -1)
   1587  1.1  kardel 		{
   1588  1.1  kardel 			perror("tcsetattr");
   1589  1.1  kardel 			exit(1);
   1590  1.1  kardel 		}
   1591  1.1  kardel 
   1592  1.1  kardel 		/*
   1593  1.1  kardel 		 * lose terminal if in daemon operation
   1594  1.1  kardel 		 */
   1595  1.1  kardel 		if (!interactive)
   1596  1.1  kardel 		    detach();
   1597  1.1  kardel 
   1598  1.1  kardel 		/*
   1599  1.1  kardel 		 * get syslog() initialized
   1600  1.1  kardel 		 */
   1601  1.1  kardel #ifdef LOG_DAEMON
   1602  1.1  kardel 		openlog("dcfd", LOG_PID, LOG_DAEMON);
   1603  1.1  kardel #else
   1604  1.1  kardel 		openlog("dcfd", LOG_PID);
   1605  1.1  kardel #endif
   1606  1.1  kardel 
   1607  1.1  kardel 		/*
   1608  1.1  kardel 		 * setup periodic operations (state control / frequency control)
   1609  1.1  kardel 		 */
   1610  1.1  kardel #ifdef HAVE_SIGACTION
   1611  1.1  kardel 		{
   1612  1.1  kardel 			struct sigaction act;
   1613  1.1  kardel 
   1614  1.1  kardel # ifdef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION
   1615  1.1  kardel 			act.sa_sigaction = (void (*) (int, siginfo_t *, void *))0;
   1616  1.1  kardel # endif /* HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION */
   1617  1.1  kardel 			act.sa_handler   = tick;
   1618  1.1  kardel 			sigemptyset(&act.sa_mask);
   1619  1.1  kardel 			act.sa_flags     = 0;
   1620  1.1  kardel 
   1621  1.1  kardel 			if (sigaction(SIGALRM, &act, (struct sigaction *)0) == -1)
   1622  1.1  kardel 			{
   1623  1.1  kardel 				syslog(LOG_ERR, "sigaction(SIGALRM): %m");
   1624  1.1  kardel 				exit(1);
   1625  1.1  kardel 			}
   1626  1.1  kardel 		}
   1627  1.1  kardel #else
   1628  1.1  kardel #ifdef HAVE_SIGVEC
   1629  1.1  kardel 		{
   1630  1.1  kardel 			struct sigvec vec;
   1631  1.1  kardel 
   1632  1.1  kardel 			vec.sv_handler   = tick;
   1633  1.1  kardel 			vec.sv_mask      = 0;
   1634  1.1  kardel 			vec.sv_flags     = 0;
   1635  1.1  kardel 
   1636  1.1  kardel 			if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1)
   1637  1.1  kardel 			{
   1638  1.1  kardel 				syslog(LOG_ERR, "sigvec(SIGALRM): %m");
   1639  1.1  kardel 				exit(1);
   1640  1.1  kardel 			}
   1641  1.1  kardel 		}
   1642  1.1  kardel #else
   1643  1.1  kardel 		(void) signal(SIGALRM, tick);
   1644  1.1  kardel #endif
   1645  1.1  kardel #endif
   1646  1.1  kardel 
   1647  1.1  kardel #ifdef ITIMER_REAL
   1648  1.1  kardel 		{
   1649  1.1  kardel 			struct itimerval it;
   1650  1.1  kardel 
   1651  1.1  kardel 			it.it_interval.tv_sec  = 1<<ADJINTERVAL;
   1652  1.1  kardel 			it.it_interval.tv_usec = 0;
   1653  1.1  kardel 			it.it_value.tv_sec     = 1<<ADJINTERVAL;
   1654  1.1  kardel 			it.it_value.tv_usec    = 0;
   1655  1.1  kardel 
   1656  1.1  kardel 			if (setitimer(ITIMER_REAL, &it, (struct itimerval *)0) == -1)
   1657  1.1  kardel 			{
   1658  1.1  kardel 				syslog(LOG_ERR, "setitimer: %m");
   1659  1.1  kardel 				exit(1);
   1660  1.1  kardel 			}
   1661  1.1  kardel 		}
   1662  1.1  kardel #else
   1663  1.1  kardel 		(void) alarm(1<<ADJINTERVAL);
   1664  1.1  kardel #endif
   1665  1.1  kardel 
   1666  1.1  kardel 		PRINTF("  DCF77 monitor %s - Copyright (C) 1993-2005 by Frank Kardel\n\n", revision);
   1667  1.1  kardel 
   1668  1.1  kardel 		pbuf[60] = '\0';
   1669  1.1  kardel 		for ( i = 0; i < 60; i++)
   1670  1.1  kardel 		    pbuf[i] = '.';
   1671  1.1  kardel 
   1672  1.1  kardel 		read_drift(drift_file);
   1673  1.1  kardel 
   1674  1.1  kardel 		/*
   1675  1.1  kardel 		 * what time is it now (for interval measurement)
   1676  1.1  kardel 		 */
   1677  1.1  kardel 		gettimeofday(&tlast, 0L);
   1678  1.1  kardel 		i = 0;
   1679  1.1  kardel 		/*
   1680  1.1  kardel 		 * loop until input trouble ...
   1681  1.1  kardel 		 */
   1682  1.1  kardel 		do
   1683  1.1  kardel 		{
   1684  1.1  kardel 			/*
   1685  1.1  kardel 			 * get an impulse
   1686  1.1  kardel 			 */
   1687  1.1  kardel 			while ((rrc = read(fd, &c, 1)) == 1)
   1688  1.1  kardel 			{
   1689  1.1  kardel 				gettimeofday(&t, 0L);
   1690  1.1  kardel 				tt = t;
   1691  1.1  kardel 				timersub(&t, &tlast);
   1692  1.1  kardel 
   1693  1.1  kardel 				if (errs > LINES)
   1694  1.1  kardel 				{
   1695  1.1  kardel 					PRINTF("  %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]);
   1696  1.1  kardel 					PRINTF("  %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]);
   1697  1.1  kardel 					errs = 0;
   1698  1.1  kardel 				}
   1699  1.1  kardel 
   1700  1.1  kardel 				/*
   1701  1.1  kardel 				 * timeout -> possible minute mark -> interpretation
   1702  1.1  kardel 				 */
   1703  1.1  kardel 				if (timercmp(&t, &timeout, >))
   1704  1.1  kardel 				{
   1705  1.1  kardel 					PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]);
   1706  1.1  kardel 
   1707  1.1  kardel 					if ((rtc = cvt_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK)
   1708  1.1  kardel 					{
   1709  1.1  kardel 						/*
   1710  1.1  kardel 						 * this data was bad - well - forget synchronisation for now
   1711  1.1  kardel 						 */
   1712  1.1  kardel 						PRINTF("\n");
   1713  1.1  kardel 						if (sync_state == SYNC)
   1714  1.1  kardel 						{
   1715  1.1  kardel 							sync_state = NO_SYNC;
   1716  1.1  kardel 							syslog(LOG_INFO, "DCF77 reception lost (bad data)");
   1717  1.1  kardel 						}
   1718  1.1  kardel 						errs++;
   1719  1.1  kardel 					}
   1720  1.1  kardel 					else
   1721  1.1  kardel 					    if (trace)
   1722  1.1  kardel 					    {
   1723  1.1  kardel 						    PRINTF("\r  %.*s ", 59 - offset, &buf[offset]);
   1724  1.1  kardel 					    }
   1725  1.1  kardel 
   1726  1.1  kardel 
   1727  1.1  kardel 					buf[0] = c;
   1728  1.1  kardel 
   1729  1.1  kardel 					/*
   1730  1.1  kardel 					 * collect first character
   1731  1.1  kardel 					 */
   1732  1.1  kardel 					if (((c^0xFF)+1) & (c^0xFF))
   1733  1.1  kardel 					    pbuf[0] = '?';
   1734  1.1  kardel 					else
   1735  1.1  kardel 					    pbuf[0] = type(c) ? '#' : '-';
   1736  1.1  kardel 
   1737  1.1  kardel 					for ( i = 1; i < 60; i++)
   1738  1.1  kardel 					    pbuf[i] = '.';
   1739  1.1  kardel 
   1740  1.1  kardel 					i = 0;
   1741  1.1  kardel 				}
   1742  1.1  kardel 				else
   1743  1.1  kardel 				{
   1744  1.1  kardel 					/*
   1745  1.1  kardel 					 * collect character
   1746  1.1  kardel 					 */
   1747  1.1  kardel 					buf[i] = c;
   1748  1.1  kardel 
   1749  1.1  kardel 					/*
   1750  1.1  kardel 					 * initial guess (usually correct)
   1751  1.1  kardel 					 */
   1752  1.1  kardel 					if (((c^0xFF)+1) & (c^0xFF))
   1753  1.1  kardel 					    pbuf[i] = '?';
   1754  1.1  kardel 					else
   1755  1.1  kardel 					    pbuf[i] = type(c) ? '#' : '-';
   1756  1.1  kardel 
   1757  1.1  kardel 					PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]);
   1758  1.1  kardel 				}
   1759  1.1  kardel 
   1760  1.1  kardel 				if (i == 0 && rtc == CVT_OK)
   1761  1.1  kardel 				{
   1762  1.1  kardel 					/*
   1763  1.1  kardel 					 * we got a good time code here - try to convert it to
   1764  1.1  kardel 					 * UTC
   1765  1.1  kardel 					 */
   1766  1.1  kardel 					if ((utc_time = dcf_to_unixtime(&clock_time, &rtc)) == -1)
   1767  1.1  kardel 					{
   1768  1.1  kardel 						PRINTF("*** BAD CONVERSION\n");
   1769  1.1  kardel 					}
   1770  1.1  kardel 
   1771  1.1  kardel 					if (utc_time != (last_utc_time + 60))
   1772  1.1  kardel 					{
   1773  1.1  kardel 						/*
   1774  1.1  kardel 						 * well, two successive sucessful telegrams are not 60 seconds
   1775  1.1  kardel 						 * apart
   1776  1.1  kardel 						 */
   1777  1.1  kardel 						PRINTF("*** NO MINUTE INC\n");
   1778  1.1  kardel 						if (sync_state == SYNC)
   1779  1.1  kardel 						{
   1780  1.1  kardel 							sync_state = NO_SYNC;
   1781  1.1  kardel 							syslog(LOG_INFO, "DCF77 reception lost (data mismatch)");
   1782  1.1  kardel 						}
   1783  1.1  kardel 						errs++;
   1784  1.1  kardel 						rtc = CVT_FAIL|CVT_BADTIME|CVT_BADDATE;
   1785  1.1  kardel 					}
   1786  1.1  kardel 					else
   1787  1.1  kardel 					    usecerror = 0;
   1788  1.1  kardel 
   1789  1.1  kardel 					last_utc_time = utc_time;
   1790  1.1  kardel 				}
   1791  1.1  kardel 
   1792  1.1  kardel 				if (rtc == CVT_OK)
   1793  1.1  kardel 				{
   1794  1.1  kardel 					if (i == 0)
   1795  1.1  kardel 					{
   1796  1.1  kardel 						/*
   1797  1.1  kardel 						 * valid time code - determine offset and
   1798  1.1  kardel 						 * note regained reception
   1799  1.1  kardel 						 */
   1800  1.1  kardel 						last_sync = ticks;
   1801  1.1  kardel 						if (sync_state == NO_SYNC)
   1802  1.1  kardel 						{
   1803  1.1  kardel 							syslog(LOG_INFO, "receiving DCF77");
   1804  1.1  kardel 						}
   1805  1.1  kardel 						else
   1806  1.1  kardel 						{
   1807  1.1  kardel 							/*
   1808  1.1  kardel 							 * we had at least one minute SYNC - thus
   1809  1.1  kardel 							 * last error is valid
   1810  1.1  kardel 							 */
   1811  1.1  kardel 							time_offset.tv_sec  = lasterror / 1000000;
   1812  1.1  kardel 							time_offset.tv_usec = lasterror % 1000000;
   1813  1.1  kardel 							adjust_clock(&time_offset, drift_file, utc_time);
   1814  1.1  kardel 						}
   1815  1.1  kardel 						sync_state = SYNC;
   1816  1.1  kardel 					}
   1817  1.1  kardel 
   1818  1.1  kardel 					time_offset.tv_sec  = utc_time + i;
   1819  1.1  kardel 					time_offset.tv_usec = 0;
   1820  1.1  kardel 
   1821  1.1  kardel 					timeradd(&time_offset, &phase);
   1822  1.1  kardel 
   1823  1.1  kardel 					usecerror += (time_offset.tv_sec - tt.tv_sec) * 1000000 + time_offset.tv_usec
   1824  1.1  kardel 						-tt.tv_usec;
   1825  1.1  kardel 
   1826  1.1  kardel 					/*
   1827  1.1  kardel 					 * output interpreted DCF77 data
   1828  1.1  kardel 					 */
   1829  1.1  kardel 					PRINTF(offsets ? "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s> (%c%ld.%06lds)" :
   1830  1.1  kardel 					       "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s>",
   1831  1.1  kardel 					       wday[clock_time.wday],
   1832  1.1  kardel 					       clock_time.hour, clock_time.minute, i, clock_time.day, clock_time.month,
   1833  1.1  kardel 					       clock_time.year,
   1834  1.1  kardel 					       (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_",
   1835  1.1  kardel 					       (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_",
   1836  1.1  kardel 					       (clock_time.flags & DCFB_DST) ? "D" : "_",
   1837  1.1  kardel 					       (clock_time.flags & DCFB_LEAP) ? "L" : "_",
   1838  1.1  kardel 					       (lasterror < 0) ? '-' : '+', l_abs(lasterror) / 1000000, l_abs(lasterror) % 1000000
   1839  1.1  kardel 					       );
   1840  1.1  kardel 
   1841  1.1  kardel 					if (trace && (i == 0))
   1842  1.1  kardel 					{
   1843  1.1  kardel 						PRINTF("\n");
   1844  1.1  kardel 						errs++;
   1845  1.1  kardel 					}
   1846  1.1  kardel 					lasterror = usecerror / (i+1);
   1847  1.1  kardel 				}
   1848  1.1  kardel 				else
   1849  1.1  kardel 				{
   1850  1.1  kardel 					lasterror = 0; /* we cannot calculate phase errors on bad reception */
   1851  1.1  kardel 				}
   1852  1.1  kardel 
   1853  1.1  kardel 				PRINTF("\r");
   1854  1.1  kardel 
   1855  1.1  kardel 				if (i < 60)
   1856  1.1  kardel 				{
   1857  1.1  kardel 					i++;
   1858  1.1  kardel 				}
   1859  1.1  kardel 
   1860  1.1  kardel 				tlast = tt;
   1861  1.1  kardel 
   1862  1.1  kardel 				if (interactive)
   1863  1.1  kardel 				    fflush(stdout);
   1864  1.1  kardel 			}
   1865  1.1  kardel 		} while ((rrc == -1) && (errno == EINTR));
   1866  1.1  kardel 
   1867  1.1  kardel 		/*
   1868  1.1  kardel 		 * lost IO - sorry guys
   1869  1.1  kardel 		 */
   1870  1.1  kardel 		syslog(LOG_ERR, "TERMINATING - cannot read from device %s (%m)", file);
   1871  1.1  kardel 
   1872  1.1  kardel 		(void)close(fd);
   1873  1.1  kardel 	}
   1874  1.1  kardel 
   1875  1.1  kardel 	closelog();
   1876  1.1  kardel 
   1877  1.1  kardel 	return 0;
   1878  1.1  kardel }
   1879  1.1  kardel 
   1880  1.1  kardel /*
   1881  1.1  kardel  * History:
   1882  1.1  kardel  *
   1883  1.1  kardel  * dcfd.c,v
   1884  1.1  kardel  * Revision 4.18  2005/10/07 22:08:18  kardel
   1885  1.1  kardel  * make dcfd.c compile on NetBSD 3.99.9 again (configure/sigvec compatibility fix)
   1886  1.1  kardel  *
   1887  1.1  kardel  * Revision 4.17.2.1  2005/10/03 19:15:16  kardel
   1888  1.1  kardel  * work around configure not detecting a missing sigvec compatibility
   1889  1.1  kardel  * interface on NetBSD 3.99.9 and above
   1890  1.1  kardel  *
   1891  1.1  kardel  * Revision 4.17  2005/08/10 10:09:44  kardel
   1892  1.1  kardel  * output revision information
   1893  1.1  kardel  *
   1894  1.1  kardel  * Revision 4.16  2005/08/10 06:33:25  kardel
   1895  1.1  kardel  * cleanup warnings
   1896  1.1  kardel  *
   1897  1.1  kardel  * Revision 4.15  2005/08/10 06:28:45  kardel
   1898  1.1  kardel  * fix setting of baud rate
   1899  1.1  kardel  *
   1900  1.1  kardel  * Revision 4.14  2005/04/16 17:32:10  kardel
   1901  1.1  kardel  * update copyright
   1902  1.1  kardel  *
   1903  1.1  kardel  * Revision 4.13  2004/11/14 15:29:41  kardel
   1904  1.1  kardel  * support PPSAPI, upgrade Copyright to Berkeley style
   1905  1.1  kardel  *
   1906  1.1  kardel  */
   1907