154359Sroberto/* 2182007Sroberto * /src/NTP/REPOSITORY/ntp4-dev/parseutil/dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A 3282408Scy * 4182007Sroberto * dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A 554359Sroberto * 654359Sroberto * DCF77 100/200ms pulse synchronisation daemon program (via 50Baud serial line) 754359Sroberto * 854359Sroberto * Features: 954359Sroberto * DCF77 decoding 1054359Sroberto * simple NTP loopfilter logic for local clock 1154359Sroberto * interactive display for debugging 1254359Sroberto * 1354359Sroberto * Lacks: 1454359Sroberto * Leap second handling (at that level you should switch to NTP Version 4 - really!) 1554359Sroberto * 16285169Scy * Copyright (c) 1995-2015 by Frank Kardel <kardel <AT> ntp.org> 17282408Scy * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universitaet Erlangen-Nuernberg, Germany 1854359Sroberto * 19182007Sroberto * Redistribution and use in source and binary forms, with or without 20182007Sroberto * modification, are permitted provided that the following conditions 21182007Sroberto * are met: 22182007Sroberto * 1. Redistributions of source code must retain the above copyright 23182007Sroberto * notice, this list of conditions and the following disclaimer. 24182007Sroberto * 2. Redistributions in binary form must reproduce the above copyright 25182007Sroberto * notice, this list of conditions and the following disclaimer in the 26182007Sroberto * documentation and/or other materials provided with the distribution. 27182007Sroberto * 3. Neither the name of the author nor the names of its contributors 28182007Sroberto * may be used to endorse or promote products derived from this software 29182007Sroberto * without specific prior written permission. 30182007Sroberto * 31182007Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 32182007Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 33182007Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34182007Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 35182007Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36182007Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37182007Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38182007Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 39182007Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 40182007Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 41182007Sroberto * SUCH DAMAGE. 42182007Sroberto * 4354359Sroberto */ 4454359Sroberto 4554359Sroberto#ifdef HAVE_CONFIG_H 4654359Sroberto# include <config.h> 4754359Sroberto#endif 4854359Sroberto 49182007Sroberto#include <sys/ioctl.h> 5054359Sroberto#include <unistd.h> 5154359Sroberto#include <stdio.h> 5254359Sroberto#include <fcntl.h> 5354359Sroberto#include <sys/types.h> 5454359Sroberto#include <sys/time.h> 5554359Sroberto#include <signal.h> 5654359Sroberto#include <syslog.h> 5754359Sroberto#include <time.h> 5854359Sroberto 5954359Sroberto/* 6054359Sroberto * NTP compilation environment 6154359Sroberto */ 6254359Sroberto#include "ntp_stdlib.h" 6354359Sroberto#include "ntpd.h" /* indirectly include ntp.h to get YEAR_PIVOT Y2KFixes */ 6454359Sroberto 6554359Sroberto/* 6654359Sroberto * select which terminal handling to use (currently only SysV variants) 6754359Sroberto */ 6854359Sroberto#if defined(HAVE_TERMIOS_H) || defined(STREAM) 6954359Sroberto#include <termios.h> 7054359Sroberto#define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_)) 7154359Sroberto#define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_)) 7254359Sroberto#else /* not HAVE_TERMIOS_H || STREAM */ 7354359Sroberto# if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS) 7454359Sroberto# include <termio.h> 7554359Sroberto# define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_)) 7654359Sroberto# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_)) 7754359Sroberto# endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */ 7854359Sroberto#endif /* not HAVE_TERMIOS_H || STREAM */ 7954359Sroberto 8054359Sroberto 8154359Sroberto#ifndef TTY_GETATTR 8254359Sroberto#include "Bletch: MUST DEFINE ONE OF 'HAVE_TERMIOS_H' or 'HAVE_TERMIO_H'" 8354359Sroberto#endif 8454359Sroberto 8554359Sroberto#ifndef days_per_year 8654359Sroberto#define days_per_year(_x_) (((_x_) % 4) ? 365 : (((_x_) % 400) ? 365 : 366)) 8754359Sroberto#endif 8854359Sroberto 8954359Sroberto#define timernormalize(_a_) \ 9054359Sroberto if ((_a_)->tv_usec >= 1000000) \ 9154359Sroberto { \ 9254359Sroberto (_a_)->tv_sec += (_a_)->tv_usec / 1000000; \ 9354359Sroberto (_a_)->tv_usec = (_a_)->tv_usec % 1000000; \ 9454359Sroberto } \ 9554359Sroberto if ((_a_)->tv_usec < 0) \ 9654359Sroberto { \ 9754359Sroberto (_a_)->tv_sec -= 1 + (-(_a_)->tv_usec / 1000000); \ 9854359Sroberto (_a_)->tv_usec = 999999 - (-(_a_)->tv_usec - 1); \ 9954359Sroberto } 10054359Sroberto 10154359Sroberto#ifdef timeradd 10254359Sroberto#undef timeradd 10354359Sroberto#endif 10454359Sroberto#define timeradd(_a_, _b_) \ 10554359Sroberto (_a_)->tv_sec += (_b_)->tv_sec; \ 10654359Sroberto (_a_)->tv_usec += (_b_)->tv_usec; \ 10754359Sroberto timernormalize((_a_)) 10854359Sroberto 10954359Sroberto#ifdef timersub 11054359Sroberto#undef timersub 11154359Sroberto#endif 11254359Sroberto#define timersub(_a_, _b_) \ 11354359Sroberto (_a_)->tv_sec -= (_b_)->tv_sec; \ 11454359Sroberto (_a_)->tv_usec -= (_b_)->tv_usec; \ 11554359Sroberto timernormalize((_a_)) 11654359Sroberto 11754359Sroberto/* 11854359Sroberto * debug macros 11954359Sroberto */ 12054359Sroberto#define PRINTF if (interactive) printf 12154359Sroberto#define LPRINTF if (interactive && loop_filter_debug) printf 12254359Sroberto 12354359Sroberto#ifdef DEBUG 124358659Scy#define DPRINTF(_x_) LPRINTF _x_ 12554359Sroberto#else 126358659Scy#define DPRINTF(_x_) 12754359Sroberto#endif 12854359Sroberto 129106424Sroberto#ifdef DECL_ERRNO 13054359Sroberto extern int errno; 131106424Sroberto#endif 13254359Sroberto 133182007Srobertostatic char *revision = "4.18"; 134182007Sroberto 13554359Sroberto/* 13654359Sroberto * display received data (avoids also detaching from tty) 13754359Sroberto */ 13854359Srobertostatic int interactive = 0; 13954359Sroberto 14054359Sroberto/* 14154359Sroberto * display loopfilter (clock control) variables 14254359Sroberto */ 14354359Srobertostatic int loop_filter_debug = 0; 14454359Sroberto 14554359Sroberto/* 14654359Sroberto * do not set/adjust system time 14754359Sroberto */ 14854359Srobertostatic int no_set = 0; 14954359Sroberto 15054359Sroberto/* 15154359Sroberto * time that passes between start of DCF impulse and time stamping (fine 15254359Sroberto * adjustment) in microseconds (receiver/OS dependent) 15354359Sroberto */ 15454359Sroberto#define DEFAULT_DELAY 230000 /* rough estimate */ 15554359Sroberto 15654359Sroberto/* 15754359Sroberto * The two states we can be in - eithe we receive nothing 15854359Sroberto * usable or we have the correct time 15954359Sroberto */ 16054359Sroberto#define NO_SYNC 0x01 16154359Sroberto#define SYNC 0x02 16254359Sroberto 16354359Srobertostatic int sync_state = NO_SYNC; 16454359Srobertostatic time_t last_sync; 16554359Sroberto 16654359Srobertostatic unsigned long ticks = 0; 16754359Sroberto 16854359Srobertostatic char pat[] = "-\\|/"; 16954359Sroberto 17054359Sroberto#define LINES (24-2) /* error lines after which the two headlines are repeated */ 17154359Sroberto 17254359Sroberto#define MAX_UNSYNC (10*60) /* allow synchronisation loss for 10 minutes */ 17354359Sroberto#define NOTICE_INTERVAL (20*60) /* mention missing synchronisation every 20 minutes */ 17454359Sroberto 17554359Sroberto/* 17654359Sroberto * clock adjustment PLL - see NTP protocol spec (RFC1305) for details 17754359Sroberto */ 17854359Sroberto 17954359Sroberto#define USECSCALE 10 18054359Sroberto#define TIMECONSTANT 2 18154359Sroberto#define ADJINTERVAL 0 18254359Sroberto#define FREQ_WEIGHT 18 18354359Sroberto#define PHASE_WEIGHT 7 18454359Sroberto#define MAX_DRIFT 0x3FFFFFFF 18554359Sroberto 18654359Sroberto#define R_SHIFT(_X_, _Y_) (((_X_) < 0) ? -(-(_X_) >> (_Y_)) : ((_X_) >> (_Y_))) 18754359Sroberto 188280849Scystatic long max_adj_offset_usec = 128000; 18954359Sroberto 19054359Srobertostatic long clock_adjust = 0; /* current adjustment value (usec * 2^USECSCALE) */ 19154359Srobertostatic long accum_drift = 0; /* accumulated drift value (usec / ADJINTERVAL) */ 19254359Srobertostatic long adjustments = 0; 19354359Srobertostatic char skip_adjust = 1; /* discard first adjustment (bad samples) */ 19454359Sroberto 19554359Sroberto/* 19654359Sroberto * DCF77 state flags 19754359Sroberto */ 198280849Scy#define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */ 199280849Scy#define DCFB_DST 0x0002 /* DST in effect */ 200132451Sroberto#define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurrence) */ 201282408Scy#define DCFB_CALLBIT 0x0008 /* "call bit" used to signalize irregularities in the control facilities */ 20254359Sroberto 20354359Srobertostruct clocktime /* clock time broken up from time code */ 20454359Sroberto{ 20554359Sroberto long wday; /* Day of week: 1: Monday - 7: Sunday */ 20654359Sroberto long day; 20754359Sroberto long month; 20854359Sroberto long year; 20954359Sroberto long hour; 21054359Sroberto long minute; 21154359Sroberto long second; 21254359Sroberto long usecond; 21354359Sroberto long utcoffset; /* in minutes */ 21454359Sroberto long flags; /* current clock status (DCF77 state flags) */ 21554359Sroberto}; 21654359Sroberto 21754359Srobertotypedef struct clocktime clocktime_t; 21854359Sroberto 21954359Sroberto/* 22054359Sroberto * (usually) quick constant multiplications 22154359Sroberto */ 222282408Scy#ifndef TIMES10 22354359Sroberto#define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) /* *8 + *2 */ 224282408Scy#endif 225282408Scy#ifndef TIMES24 22654359Sroberto#define TIMES24(_X_) (((_X_) << 4) + ((_X_) << 3)) /* *16 + *8 */ 227282408Scy#endif 228282408Scy#ifndef TIMES60 22954359Sroberto#define TIMES60(_X_) ((((_X_) << 4) - (_X_)) << 2) /* *(16 - 1) *4 */ 230282408Scy#endif 231282408Scy 23254359Sroberto/* 23354359Sroberto * generic l_abs() function 23454359Sroberto */ 23554359Sroberto#define l_abs(_x_) (((_x_) < 0) ? -(_x_) : (_x_)) 23654359Sroberto 23754359Sroberto/* 23854359Sroberto * conversion related return/error codes 23954359Sroberto */ 24054359Sroberto#define CVT_MASK 0x0000000F /* conversion exit code */ 24154359Sroberto#define CVT_NONE 0x00000001 /* format not applicable */ 24254359Sroberto#define CVT_FAIL 0x00000002 /* conversion failed - error code returned */ 24354359Sroberto#define CVT_OK 0x00000004 /* conversion succeeded */ 24454359Sroberto#define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */ 24554359Sroberto#define CVT_BADDATE 0x00000020 /* invalid date */ 24654359Sroberto#define CVT_BADTIME 0x00000040 /* invalid time */ 24754359Sroberto 24854359Sroberto/* 24954359Sroberto * DCF77 raw time code 25054359Sroberto * 25154359Sroberto * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig 25254359Sroberto * und Berlin, Maerz 1989 25354359Sroberto * 25454359Sroberto * Timecode transmission: 25554359Sroberto * AM: 25654359Sroberto * time marks are send every second except for the second before the 25754359Sroberto * next minute mark 25854359Sroberto * time marks consist of a reduction of transmitter power to 25% 25954359Sroberto * of the nominal level 26054359Sroberto * the falling edge is the time indication (on time) 26154359Sroberto * time marks of a 100ms duration constitute a logical 0 26254359Sroberto * time marks of a 200ms duration constitute a logical 1 26354359Sroberto * FM: 26454359Sroberto * see the spec. (basically a (non-)inverted psuedo random phase shift) 26554359Sroberto * 26654359Sroberto * Encoding: 26754359Sroberto * Second Contents 26854359Sroberto * 0 - 10 AM: free, FM: 0 26954359Sroberto * 11 - 14 free 270282408Scy * 15 R - "call bit" used to signalize irregularities in the control facilities 271282408Scy * (until 2003 indicated transmission via alternate antenna) 27254359Sroberto * 16 A1 - expect zone change (1 hour before) 27354359Sroberto * 17 - 18 Z1,Z2 - time zone 27454359Sroberto * 0 0 illegal 27554359Sroberto * 0 1 MEZ (MET) 27654359Sroberto * 1 0 MESZ (MED, MET DST) 27754359Sroberto * 1 1 illegal 27854359Sroberto * 19 A2 - expect leap insertion/deletion (1 hour before) 27954359Sroberto * 20 S - start of time code (1) 28054359Sroberto * 21 - 24 M1 - BCD (lsb first) Minutes 28154359Sroberto * 25 - 27 M10 - BCD (lsb first) 10 Minutes 28254359Sroberto * 28 P1 - Minute Parity (even) 28354359Sroberto * 29 - 32 H1 - BCD (lsb first) Hours 28454359Sroberto * 33 - 34 H10 - BCD (lsb first) 10 Hours 28554359Sroberto * 35 P2 - Hour Parity (even) 28654359Sroberto * 36 - 39 D1 - BCD (lsb first) Days 28754359Sroberto * 40 - 41 D10 - BCD (lsb first) 10 Days 28854359Sroberto * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday) 28954359Sroberto * 45 - 49 MO - BCD (lsb first) Month 29054359Sroberto * 50 MO0 - 10 Months 29154359Sroberto * 51 - 53 Y1 - BCD (lsb first) Years 29254359Sroberto * 54 - 57 Y10 - BCD (lsb first) 10 Years 29354359Sroberto * 58 P3 - Date Parity (even) 29454359Sroberto * 59 - usually missing (minute indication), except for leap insertion 29554359Sroberto */ 29654359Sroberto 29754359Sroberto/*----------------------------------------------------------------------- 29854359Sroberto * conversion table to map DCF77 bit stream into data fields. 29954359Sroberto * Encoding: 30054359Sroberto * Each field of the DCF77 code is described with two adjacent entries in 30154359Sroberto * this table. The first entry specifies the offset into the DCF77 data stream 30254359Sroberto * while the length is given as the difference between the start index and 30354359Sroberto * the start index of the following field. 30454359Sroberto */ 305282408Scystatic struct rawdcfcode 30654359Sroberto{ 30754359Sroberto char offset; /* start bit */ 30854359Sroberto} rawdcfcode[] = 30954359Sroberto{ 31054359Sroberto { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 }, 31154359Sroberto { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 } 31254359Sroberto}; 31354359Sroberto 31454359Sroberto/*----------------------------------------------------------------------- 31554359Sroberto * symbolic names for the fields of DCF77 describes in "rawdcfcode". 31654359Sroberto * see comment above for the structure of the DCF77 data 31754359Sroberto */ 31854359Sroberto#define DCF_M 0 31954359Sroberto#define DCF_R 1 32054359Sroberto#define DCF_A1 2 32154359Sroberto#define DCF_Z 3 32254359Sroberto#define DCF_A2 4 32354359Sroberto#define DCF_S 5 32454359Sroberto#define DCF_M1 6 32554359Sroberto#define DCF_M10 7 32654359Sroberto#define DCF_P1 8 32754359Sroberto#define DCF_H1 9 32854359Sroberto#define DCF_H10 10 32954359Sroberto#define DCF_P2 11 33054359Sroberto#define DCF_D1 12 33154359Sroberto#define DCF_D10 13 33254359Sroberto#define DCF_DW 14 33354359Sroberto#define DCF_MO 15 33454359Sroberto#define DCF_MO0 16 33554359Sroberto#define DCF_Y1 17 33654359Sroberto#define DCF_Y10 18 33754359Sroberto#define DCF_P3 19 33854359Sroberto 33954359Sroberto/*----------------------------------------------------------------------- 34054359Sroberto * parity field table (same encoding as rawdcfcode) 34154359Sroberto * This table describes the sections of the DCF77 code that are 34254359Sroberto * parity protected 34354359Sroberto */ 34454359Srobertostatic struct partab 34554359Sroberto{ 34654359Sroberto char offset; /* start bit of parity field */ 34754359Sroberto} partab[] = 34854359Sroberto{ 34954359Sroberto { 21 }, { 29 }, { 36 }, { 59 } 35054359Sroberto}; 35154359Sroberto 35254359Sroberto/*----------------------------------------------------------------------- 35354359Sroberto * offsets for parity field descriptions 35454359Sroberto */ 35554359Sroberto#define DCF_P_P1 0 35654359Sroberto#define DCF_P_P2 1 35754359Sroberto#define DCF_P_P3 2 35854359Sroberto 35954359Sroberto/*----------------------------------------------------------------------- 36054359Sroberto * legal values for time zone information 36154359Sroberto */ 36254359Sroberto#define DCF_Z_MET 0x2 36354359Sroberto#define DCF_Z_MED 0x1 36454359Sroberto 36554359Sroberto/*----------------------------------------------------------------------- 36654359Sroberto * symbolic representation if the DCF77 data stream 36754359Sroberto */ 36854359Srobertostatic struct dcfparam 36954359Sroberto{ 37054359Sroberto unsigned char onebits[60]; 37154359Sroberto unsigned char zerobits[60]; 372282408Scy} dcfparam = 37354359Sroberto{ 37454359Sroberto "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */ 37554359Sroberto "--------------------s-------p------p----------------------p" /* 'ZERO' representation */ 37654359Sroberto}; 37754359Sroberto 37854359Sroberto/*----------------------------------------------------------------------- 37954359Sroberto * extract a bitfield from DCF77 datastream 38054359Sroberto * All numeric fields are LSB first. 38154359Sroberto * buf holds a pointer to a DCF77 data buffer in symbolic 38254359Sroberto * representation 38354359Sroberto * idx holds the index to the field description in rawdcfcode 38454359Sroberto */ 38554359Srobertostatic unsigned long 38654359Srobertoext_bf( 38754359Sroberto register unsigned char *buf, 38854359Sroberto register int idx 38954359Sroberto ) 39054359Sroberto{ 39154359Sroberto register unsigned long sum = 0; 39254359Sroberto register int i, first; 39354359Sroberto 39454359Sroberto first = rawdcfcode[idx].offset; 395282408Scy 39654359Sroberto for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--) 39754359Sroberto { 39854359Sroberto sum <<= 1; 39954359Sroberto sum |= (buf[i] != dcfparam.zerobits[i]); 40054359Sroberto } 40154359Sroberto return sum; 40254359Sroberto} 40354359Sroberto 40454359Sroberto/*----------------------------------------------------------------------- 40554359Sroberto * check even parity integrity for a bitfield 40654359Sroberto * 40754359Sroberto * buf holds a pointer to a DCF77 data buffer in symbolic 40854359Sroberto * representation 40954359Sroberto * idx holds the index to the field description in partab 41054359Sroberto */ 41154359Srobertostatic unsigned 41254359Srobertopcheck( 41354359Sroberto register unsigned char *buf, 41454359Sroberto register int idx 41554359Sroberto ) 41654359Sroberto{ 41754359Sroberto register int i,last; 41854359Sroberto register unsigned psum = 1; 41954359Sroberto 42054359Sroberto last = partab[idx+1].offset; 42154359Sroberto 42254359Sroberto for (i = partab[idx].offset; i < last; i++) 42354359Sroberto psum ^= (buf[i] != dcfparam.zerobits[i]); 42454359Sroberto 42554359Sroberto return psum; 42654359Sroberto} 42754359Sroberto 42854359Sroberto/*----------------------------------------------------------------------- 42954359Sroberto * convert a DCF77 data buffer into wall clock time + flags 43054359Sroberto * 43154359Sroberto * buffer holds a pointer to a DCF77 data buffer in symbolic 43254359Sroberto * representation 43354359Sroberto * size describes the length of DCF77 information in bits (represented 43454359Sroberto * as chars in symbolic notation 43554359Sroberto * clock points to a wall clock time description of the DCF77 data (result) 43654359Sroberto */ 43754359Srobertostatic unsigned long 43854359Srobertoconvert_rawdcf( 43954359Sroberto unsigned char *buffer, 44054359Sroberto int size, 44154359Sroberto clocktime_t *clock_time 44254359Sroberto ) 44354359Sroberto{ 44454359Sroberto if (size < 57) 44554359Sroberto { 44654359Sroberto PRINTF("%-30s", "*** INCOMPLETE"); 44754359Sroberto return CVT_NONE; 44854359Sroberto } 449282408Scy 45054359Sroberto /* 45154359Sroberto * check Start and Parity bits 45254359Sroberto */ 45354359Sroberto if ((ext_bf(buffer, DCF_S) == 1) && 45454359Sroberto pcheck(buffer, DCF_P_P1) && 45554359Sroberto pcheck(buffer, DCF_P_P2) && 45654359Sroberto pcheck(buffer, DCF_P_P3)) 45754359Sroberto { 45854359Sroberto /* 45954359Sroberto * buffer OK - extract all fields and build wall clock time from them 46054359Sroberto */ 46154359Sroberto 46254359Sroberto clock_time->flags = 0; 46354359Sroberto clock_time->usecond= 0; 46454359Sroberto clock_time->second = 0; 46554359Sroberto clock_time->minute = ext_bf(buffer, DCF_M10); 46654359Sroberto clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1); 46754359Sroberto clock_time->hour = ext_bf(buffer, DCF_H10); 46854359Sroberto clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1); 46954359Sroberto clock_time->day = ext_bf(buffer, DCF_D10); 47054359Sroberto clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1); 47154359Sroberto clock_time->month = ext_bf(buffer, DCF_MO0); 47254359Sroberto clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO); 47354359Sroberto clock_time->year = ext_bf(buffer, DCF_Y10); 47454359Sroberto clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1); 47554359Sroberto clock_time->wday = ext_bf(buffer, DCF_DW); 47654359Sroberto 47754359Sroberto /* 47854359Sroberto * determine offset to UTC by examining the time zone 47954359Sroberto */ 48054359Sroberto switch (ext_bf(buffer, DCF_Z)) 48154359Sroberto { 48254359Sroberto case DCF_Z_MET: 48354359Sroberto clock_time->utcoffset = -60; 48454359Sroberto break; 48554359Sroberto 48654359Sroberto case DCF_Z_MED: 48754359Sroberto clock_time->flags |= DCFB_DST; 48854359Sroberto clock_time->utcoffset = -120; 48954359Sroberto break; 49054359Sroberto 49154359Sroberto default: 49254359Sroberto PRINTF("%-30s", "*** BAD TIME ZONE"); 49354359Sroberto return CVT_FAIL|CVT_BADFMT; 49454359Sroberto } 49554359Sroberto 49654359Sroberto /* 49754359Sroberto * extract various warnings from DCF77 49854359Sroberto */ 49954359Sroberto if (ext_bf(buffer, DCF_A1)) 50054359Sroberto clock_time->flags |= DCFB_ANNOUNCE; 50154359Sroberto 50254359Sroberto if (ext_bf(buffer, DCF_A2)) 50354359Sroberto clock_time->flags |= DCFB_LEAP; 50454359Sroberto 50554359Sroberto if (ext_bf(buffer, DCF_R)) 506282408Scy clock_time->flags |= DCFB_CALLBIT; 50754359Sroberto 50854359Sroberto return CVT_OK; 50954359Sroberto } 51054359Sroberto else 51154359Sroberto { 51254359Sroberto /* 51354359Sroberto * bad format - not for us 51454359Sroberto */ 51554359Sroberto PRINTF("%-30s", "*** BAD FORMAT (invalid/parity)"); 51654359Sroberto return CVT_FAIL|CVT_BADFMT; 51754359Sroberto } 51854359Sroberto} 51954359Sroberto 52054359Sroberto/*----------------------------------------------------------------------- 52154359Sroberto * raw dcf input routine - fix up 50 baud 52254359Sroberto * characters for 1/0 decision 52354359Sroberto */ 52454359Srobertostatic unsigned long 52554359Srobertocvt_rawdcf( 52654359Sroberto unsigned char *buffer, 52754359Sroberto int size, 52854359Sroberto clocktime_t *clock_time 52954359Sroberto ) 53054359Sroberto{ 53154359Sroberto register unsigned char *s = buffer; 53254359Sroberto register unsigned char *e = buffer + size; 53354359Sroberto register unsigned char *b = dcfparam.onebits; 53454359Sroberto register unsigned char *c = dcfparam.zerobits; 53554359Sroberto register unsigned rtc = CVT_NONE; 53654359Sroberto register unsigned int i, lowmax, highmax, cutoff, span; 53754359Sroberto#define BITS 9 53854359Sroberto unsigned char histbuf[BITS]; 53954359Sroberto /* 54054359Sroberto * the input buffer contains characters with runs of consecutive 54154359Sroberto * bits set. These set bits are an indication of the DCF77 pulse 54254359Sroberto * length. We assume that we receive the pulse at 50 Baud. Thus 54354359Sroberto * a 100ms pulse would generate a 4 bit train (20ms per bit and 54454359Sroberto * start bit) 54554359Sroberto * a 200ms pulse would create all zeroes (and probably a frame error) 54654359Sroberto * 54754359Sroberto * The basic idea is that on corret reception we must have two 54854359Sroberto * maxima in the pulse length distribution histogram. (one for 54954359Sroberto * the zero representing pulses and one for the one representing 55054359Sroberto * pulses) 55154359Sroberto * There will always be ones in the datastream, thus we have to see 55254359Sroberto * two maxima. 55354359Sroberto * The best point to cut for a 1/0 decision is the minimum between those 55454359Sroberto * between the maxima. The following code tries to find this cutoff point. 55554359Sroberto */ 55654359Sroberto 55754359Sroberto /* 55854359Sroberto * clear histogram buffer 55954359Sroberto */ 56054359Sroberto for (i = 0; i < BITS; i++) 56154359Sroberto { 56254359Sroberto histbuf[i] = 0; 56354359Sroberto } 56454359Sroberto 56554359Sroberto cutoff = 0; 56654359Sroberto lowmax = 0; 56754359Sroberto 56854359Sroberto /* 56954359Sroberto * convert sequences of set bits into bits counts updating 57054359Sroberto * the histogram alongway 57154359Sroberto */ 57254359Sroberto while (s < e) 57354359Sroberto { 57454359Sroberto register unsigned int ch = *s ^ 0xFF; 57554359Sroberto /* 57654359Sroberto * check integrity and update histogramm 57754359Sroberto */ 57854359Sroberto if (!((ch+1) & ch) || !*s) 57954359Sroberto { 58054359Sroberto /* 58154359Sroberto * character ok 58254359Sroberto */ 58354359Sroberto for (i = 0; ch; i++) 58454359Sroberto { 58554359Sroberto ch >>= 1; 58654359Sroberto } 58754359Sroberto 58854359Sroberto *s = i; 58954359Sroberto histbuf[i]++; 59054359Sroberto cutoff += i; 59154359Sroberto lowmax++; 59254359Sroberto } 59354359Sroberto else 59454359Sroberto { 59554359Sroberto /* 59654359Sroberto * invalid character (no consecutive bit sequence) 59754359Sroberto */ 598358659Scy DPRINTF(("parse: cvt_rawdcf: character check for 0x%x@%ld FAILED\n", 599280849Scy (u_int)*s, (long)(s - buffer))); 60054359Sroberto *s = (unsigned char)~0; 60154359Sroberto rtc = CVT_FAIL|CVT_BADFMT; 60254359Sroberto } 60354359Sroberto s++; 60454359Sroberto } 60554359Sroberto 60654359Sroberto /* 60754359Sroberto * first cutoff estimate (average bit count - must be between both 60854359Sroberto * maxima) 60954359Sroberto */ 61054359Sroberto if (lowmax) 61154359Sroberto { 61254359Sroberto cutoff /= lowmax; 61354359Sroberto } 61454359Sroberto else 61554359Sroberto { 61654359Sroberto cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */ 61754359Sroberto } 61854359Sroberto 619358659Scy DPRINTF(("parse: cvt_rawdcf: average bit count: %d\n", cutoff)); 62054359Sroberto 62154359Sroberto lowmax = 0; /* weighted sum */ 62254359Sroberto highmax = 0; /* bitcount */ 62354359Sroberto 62454359Sroberto /* 62554359Sroberto * collect weighted sum of lower bits (left of initial guess) 62654359Sroberto */ 627358659Scy DPRINTF(("parse: cvt_rawdcf: histogram:")); 62854359Sroberto for (i = 0; i <= cutoff; i++) 62954359Sroberto { 63054359Sroberto lowmax += histbuf[i] * i; 63154359Sroberto highmax += histbuf[i]; 632358659Scy DPRINTF((" %d", histbuf[i])); 63354359Sroberto } 634358659Scy DPRINTF((" <M>")); 63554359Sroberto 63654359Sroberto /* 63754359Sroberto * round up 63854359Sroberto */ 63954359Sroberto lowmax += highmax / 2; 64054359Sroberto 64154359Sroberto /* 64254359Sroberto * calculate lower bit maximum (weighted sum / bit count) 64354359Sroberto * 64454359Sroberto * avoid divide by zero 64554359Sroberto */ 64654359Sroberto if (highmax) 64754359Sroberto { 64854359Sroberto lowmax /= highmax; 64954359Sroberto } 65054359Sroberto else 65154359Sroberto { 65254359Sroberto lowmax = 0; 65354359Sroberto } 65454359Sroberto 65554359Sroberto highmax = 0; /* weighted sum of upper bits counts */ 65654359Sroberto cutoff = 0; /* bitcount */ 65754359Sroberto 65854359Sroberto /* 65954359Sroberto * collect weighted sum of lower bits (right of initial guess) 66054359Sroberto */ 66154359Sroberto for (; i < BITS; i++) 66254359Sroberto { 66354359Sroberto highmax+=histbuf[i] * i; 66454359Sroberto cutoff +=histbuf[i]; 665358659Scy DPRINTF((" %d", histbuf[i])); 66654359Sroberto } 667358659Scy DPRINTF(("\n")); 66854359Sroberto 66954359Sroberto /* 67054359Sroberto * determine upper maximum (weighted sum / bit count) 67154359Sroberto */ 67254359Sroberto if (cutoff) 67354359Sroberto { 67454359Sroberto highmax /= cutoff; 67554359Sroberto } 67654359Sroberto else 67754359Sroberto { 67854359Sroberto highmax = BITS-1; 67954359Sroberto } 68054359Sroberto 68154359Sroberto /* 68254359Sroberto * following now holds: 68354359Sroberto * lowmax <= cutoff(initial guess) <= highmax 68454359Sroberto * best cutoff is the minimum nearest to higher bits 68554359Sroberto */ 68654359Sroberto 68754359Sroberto /* 68854359Sroberto * find the minimum between lowmax and highmax (detecting 68954359Sroberto * possibly a minimum span) 69054359Sroberto */ 69154359Sroberto span = cutoff = lowmax; 69254359Sroberto for (i = lowmax; i <= highmax; i++) 69354359Sroberto { 69454359Sroberto if (histbuf[cutoff] > histbuf[i]) 69554359Sroberto { 69654359Sroberto /* 69754359Sroberto * got a new minimum move beginning of minimum (cutoff) and 69854359Sroberto * end of minimum (span) there 69954359Sroberto */ 70054359Sroberto cutoff = span = i; 70154359Sroberto } 70254359Sroberto else 70354359Sroberto if (histbuf[cutoff] == histbuf[i]) 70454359Sroberto { 70554359Sroberto /* 70654359Sroberto * minimum not better yet - but it spans more than 70754359Sroberto * one bit value - follow it 70854359Sroberto */ 70954359Sroberto span = i; 71054359Sroberto } 71154359Sroberto } 71254359Sroberto 71354359Sroberto /* 71454359Sroberto * cutoff point for 1/0 decision is the middle of the minimum section 71554359Sroberto * in the histogram 71654359Sroberto */ 71754359Sroberto cutoff = (cutoff + span) / 2; 71854359Sroberto 719358659Scy DPRINTF(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff)); 72054359Sroberto 72154359Sroberto /* 72254359Sroberto * convert the bit counts to symbolic 1/0 information for data conversion 72354359Sroberto */ 72454359Sroberto s = buffer; 72554359Sroberto while ((s < e) && *c && *b) 72654359Sroberto { 72754359Sroberto if (*s == (unsigned char)~0) 72854359Sroberto { 72954359Sroberto /* 73054359Sroberto * invalid character 73154359Sroberto */ 73254359Sroberto *s = '?'; 73354359Sroberto } 73454359Sroberto else 73554359Sroberto { 73654359Sroberto /* 73754359Sroberto * symbolic 1/0 representation 73854359Sroberto */ 73954359Sroberto *s = (*s >= cutoff) ? *b : *c; 74054359Sroberto } 74154359Sroberto s++; 74254359Sroberto b++; 74354359Sroberto c++; 74454359Sroberto } 74554359Sroberto 74654359Sroberto /* 74754359Sroberto * if everything went well so far return the result of the symbolic 74854359Sroberto * conversion routine else just the accumulated errors 74954359Sroberto */ 750282408Scy if (rtc != CVT_NONE) 75154359Sroberto { 75254359Sroberto PRINTF("%-30s", "*** BAD DATA"); 75354359Sroberto } 75454359Sroberto 75554359Sroberto return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock_time) : rtc; 75654359Sroberto} 75754359Sroberto 75854359Sroberto/*----------------------------------------------------------------------- 75954359Sroberto * convert a wall clock time description of DCF77 to a Unix time (seconds 76054359Sroberto * since 1.1. 1970 UTC) 76154359Sroberto */ 762106424Srobertostatic time_t 76354359Srobertodcf_to_unixtime( 76454359Sroberto clocktime_t *clock_time, 76554359Sroberto unsigned *cvtrtc 76654359Sroberto ) 76754359Sroberto{ 76854359Sroberto#define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); } 769282408Scy static int days_of_month[] = 77054359Sroberto { 77154359Sroberto 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 77254359Sroberto }; 77354359Sroberto register int i; 77454359Sroberto time_t t; 775282408Scy 77654359Sroberto /* 77754359Sroberto * map 2 digit years to 19xx (DCF77 is a 20th century item) 77854359Sroberto */ 77954359Sroberto if ( clock_time->year < YEAR_PIVOT ) /* in case of Y2KFixes [ */ 78054359Sroberto clock_time->year += 100; /* *year%100, make tm_year */ 78154359Sroberto /* *(do we need this?) */ 78254359Sroberto if ( clock_time->year < YEAR_BREAK ) /* (failsafe if) */ 78354359Sroberto clock_time->year += 1900; /* Y2KFixes ] */ 78454359Sroberto 78554359Sroberto /* 78654359Sroberto * must have been a really bad year code - drop it 78754359Sroberto */ 78854359Sroberto if (clock_time->year < (YEAR_PIVOT + 1900) ) /* Y2KFixes */ 78954359Sroberto { 79054359Sroberto SETRTC(CVT_FAIL|CVT_BADDATE); 79154359Sroberto return -1; 79254359Sroberto } 79354359Sroberto /* 79454359Sroberto * sorry, slow section here - but it's not time critical anyway 79554359Sroberto */ 79654359Sroberto 79754359Sroberto /* 79854359Sroberto * calculate days since 1970 (watching leap years) 79954359Sroberto */ 80054359Sroberto t = julian0( clock_time->year ) - julian0( 1970 ); 80154359Sroberto 80254359Sroberto /* month */ 80354359Sroberto if (clock_time->month <= 0 || clock_time->month > 12) 80454359Sroberto { 80554359Sroberto SETRTC(CVT_FAIL|CVT_BADDATE); 80654359Sroberto return -1; /* bad month */ 80754359Sroberto } 80854359Sroberto /* adjust current leap year */ 80954359Sroberto#if 0 81054359Sroberto if (clock_time->month < 3 && days_per_year(clock_time->year) == 366) 81154359Sroberto t--; 81254359Sroberto#endif 81354359Sroberto 81454359Sroberto /* 81554359Sroberto * collect days from months excluding the current one 81654359Sroberto */ 81754359Sroberto for (i = 1; i < clock_time->month; i++) 81854359Sroberto { 81954359Sroberto t += days_of_month[i]; 82054359Sroberto } 82154359Sroberto /* day */ 82254359Sroberto if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ? 82354359Sroberto clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month])) 82454359Sroberto { 82554359Sroberto SETRTC(CVT_FAIL|CVT_BADDATE); 82654359Sroberto return -1; /* bad day */ 82754359Sroberto } 82854359Sroberto 82954359Sroberto /* 83054359Sroberto * collect days from date excluding the current one 83154359Sroberto */ 83254359Sroberto t += clock_time->day - 1; 83354359Sroberto 83454359Sroberto /* hour */ 83554359Sroberto if (clock_time->hour < 0 || clock_time->hour >= 24) 83654359Sroberto { 83754359Sroberto SETRTC(CVT_FAIL|CVT_BADTIME); 83854359Sroberto return -1; /* bad hour */ 83954359Sroberto } 84054359Sroberto 84154359Sroberto /* 84254359Sroberto * calculate hours from 1. 1. 1970 84354359Sroberto */ 84454359Sroberto t = TIMES24(t) + clock_time->hour; 84554359Sroberto 84654359Sroberto /* min */ 84754359Sroberto if (clock_time->minute < 0 || clock_time->minute > 59) 84854359Sroberto { 84954359Sroberto SETRTC(CVT_FAIL|CVT_BADTIME); 85054359Sroberto return -1; /* bad min */ 85154359Sroberto } 85254359Sroberto 85354359Sroberto /* 85454359Sroberto * calculate minutes from 1. 1. 1970 85554359Sroberto */ 85654359Sroberto t = TIMES60(t) + clock_time->minute; 85754359Sroberto /* sec */ 858282408Scy 85954359Sroberto /* 86054359Sroberto * calculate UTC in minutes 86154359Sroberto */ 86254359Sroberto t += clock_time->utcoffset; 86354359Sroberto 86454359Sroberto if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */ 86554359Sroberto { 86654359Sroberto SETRTC(CVT_FAIL|CVT_BADTIME); 86754359Sroberto return -1; /* bad sec */ 86854359Sroberto } 86954359Sroberto 87054359Sroberto /* 87154359Sroberto * calculate UTC in seconds - phew ! 87254359Sroberto */ 87354359Sroberto t = TIMES60(t) + clock_time->second; 87454359Sroberto /* done */ 87554359Sroberto return t; 87654359Sroberto} 87754359Sroberto 87854359Sroberto/*----------------------------------------------------------------------- 87954359Sroberto * cheap half baked 1/0 decision - for interactive operation only 88054359Sroberto */ 88154359Srobertostatic char 88254359Srobertotype( 88354359Sroberto unsigned int c 88454359Sroberto ) 88554359Sroberto{ 88654359Sroberto c ^= 0xFF; 88754359Sroberto return (c > 0xF); 88854359Sroberto} 88954359Sroberto 89054359Sroberto/*----------------------------------------------------------------------- 89154359Sroberto * week day representation 89254359Sroberto */ 89354359Srobertostatic const char *wday[8] = 89454359Sroberto{ 89554359Sroberto "??", 89654359Sroberto "Mo", 89754359Sroberto "Tu", 89854359Sroberto "We", 89954359Sroberto "Th", 90054359Sroberto "Fr", 90154359Sroberto "Sa", 90254359Sroberto "Su" 90354359Sroberto}; 90454359Sroberto 90554359Sroberto/*----------------------------------------------------------------------- 90654359Sroberto * generate a string representation for a timeval 90754359Sroberto */ 90854359Srobertostatic char * 90954359Srobertopr_timeval( 910280849Scy struct timeval *val 911280849Scy ) 91254359Sroberto{ 91354359Sroberto static char buf[20]; 91454359Sroberto 91554359Sroberto if (val->tv_sec == 0) 916280849Scy snprintf(buf, sizeof(buf), "%c0.%06ld", 917280849Scy (val->tv_usec < 0) ? '-' : '+', 918280849Scy (long int)l_abs(val->tv_usec)); 91954359Sroberto else 920280849Scy snprintf(buf, sizeof(buf), "%ld.%06ld", 921280849Scy (long int)val->tv_sec, 922280849Scy (long int)l_abs(val->tv_usec)); 92354359Sroberto return buf; 92454359Sroberto} 92554359Sroberto 92654359Sroberto/*----------------------------------------------------------------------- 92754359Sroberto * correct the current time by an offset by setting the time rigorously 92854359Sroberto */ 92954359Srobertostatic void 93054359Srobertoset_time( 93154359Sroberto struct timeval *offset 93254359Sroberto ) 93354359Sroberto{ 93454359Sroberto struct timeval the_time; 93554359Sroberto 93654359Sroberto if (no_set) 93754359Sroberto return; 93854359Sroberto 93954359Sroberto LPRINTF("set_time: %s ", pr_timeval(offset)); 94054359Sroberto syslog(LOG_NOTICE, "setting time (offset %s)", pr_timeval(offset)); 94154359Sroberto 94254359Sroberto if (gettimeofday(&the_time, 0L) == -1) 94354359Sroberto { 94454359Sroberto perror("gettimeofday()"); 94554359Sroberto } 94654359Sroberto else 94754359Sroberto { 94854359Sroberto timeradd(&the_time, offset); 94954359Sroberto if (settimeofday(&the_time, 0L) == -1) 95054359Sroberto { 95154359Sroberto perror("settimeofday()"); 95254359Sroberto } 95354359Sroberto } 95454359Sroberto} 95554359Sroberto 95654359Sroberto/*----------------------------------------------------------------------- 95754359Sroberto * slew the time by a given offset 95854359Sroberto */ 95954359Srobertostatic void 96054359Srobertoadj_time( 96154359Sroberto long offset 96254359Sroberto ) 96354359Sroberto{ 96454359Sroberto struct timeval time_offset; 96554359Sroberto 96654359Sroberto if (no_set) 96754359Sroberto return; 96854359Sroberto 96954359Sroberto time_offset.tv_sec = offset / 1000000; 97054359Sroberto time_offset.tv_usec = offset % 1000000; 97154359Sroberto 97254359Sroberto LPRINTF("adj_time: %ld us ", (long int)offset); 97354359Sroberto if (adjtime(&time_offset, 0L) == -1) 97454359Sroberto perror("adjtime()"); 97554359Sroberto} 97654359Sroberto 97754359Sroberto/*----------------------------------------------------------------------- 97854359Sroberto * read in a possibly previously written drift value 97954359Sroberto */ 98054359Srobertostatic void 98154359Srobertoread_drift( 98254359Sroberto const char *drift_file 98354359Sroberto ) 98454359Sroberto{ 98554359Sroberto FILE *df; 98654359Sroberto 98754359Sroberto df = fopen(drift_file, "r"); 98854359Sroberto if (df != NULL) 98954359Sroberto { 99054359Sroberto int idrift = 0, fdrift = 0; 99154359Sroberto 99254359Sroberto fscanf(df, "%4d.%03d", &idrift, &fdrift); 99354359Sroberto fclose(df); 99454359Sroberto LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift); 99554359Sroberto 99654359Sroberto accum_drift = idrift << USECSCALE; 99754359Sroberto fdrift = (fdrift << USECSCALE) / 1000; 99854359Sroberto accum_drift += fdrift & (1<<USECSCALE); 99954359Sroberto LPRINTF("read_drift: drift_comp %ld ", (long int)accum_drift); 100054359Sroberto } 100154359Sroberto} 100254359Sroberto 100354359Sroberto/*----------------------------------------------------------------------- 100454359Sroberto * write out the current drift value 100554359Sroberto */ 100654359Srobertostatic void 100754359Srobertoupdate_drift( 100854359Sroberto const char *drift_file, 100954359Sroberto long offset, 101054359Sroberto time_t reftime 101154359Sroberto ) 101254359Sroberto{ 101354359Sroberto FILE *df; 101454359Sroberto 101554359Sroberto df = fopen(drift_file, "w"); 101654359Sroberto if (df != NULL) 101754359Sroberto { 101854359Sroberto int idrift = R_SHIFT(accum_drift, USECSCALE); 101954359Sroberto int fdrift = accum_drift & ((1<<USECSCALE)-1); 102054359Sroberto 102154359Sroberto LPRINTF("update_drift: drift_comp %ld ", (long int)accum_drift); 102254359Sroberto fdrift = (fdrift * 1000) / (1<<USECSCALE); 102354359Sroberto fprintf(df, "%4d.%03d %c%ld.%06ld %.24s\n", idrift, fdrift, 102454359Sroberto (offset < 0) ? '-' : '+', (long int)(l_abs(offset) / 1000000), 102554359Sroberto (long int)(l_abs(offset) % 1000000), asctime(localtime(&reftime))); 102654359Sroberto fclose(df); 102754359Sroberto LPRINTF("update_drift: %d.%03d ppm ", idrift, fdrift); 102854359Sroberto } 102954359Sroberto} 103054359Sroberto 103154359Sroberto/*----------------------------------------------------------------------- 103254359Sroberto * process adjustments derived from the DCF77 observation 103354359Sroberto * (controls clock PLL) 103454359Sroberto */ 103554359Srobertostatic void 103654359Srobertoadjust_clock( 103754359Sroberto struct timeval *offset, 103854359Sroberto const char *drift_file, 103954359Sroberto time_t reftime 104054359Sroberto ) 104154359Sroberto{ 104254359Sroberto struct timeval toffset; 104354359Sroberto register long usecoffset; 104454359Sroberto int tmp; 104554359Sroberto 104654359Sroberto if (no_set) 104754359Sroberto return; 104854359Sroberto 104954359Sroberto if (skip_adjust) 105054359Sroberto { 105154359Sroberto skip_adjust = 0; 105254359Sroberto return; 105354359Sroberto } 105454359Sroberto 105554359Sroberto toffset = *offset; 105654359Sroberto toffset.tv_sec = l_abs(toffset.tv_sec); 105754359Sroberto toffset.tv_usec = l_abs(toffset.tv_usec); 1058280849Scy if (toffset.tv_sec || 1059280849Scy (!toffset.tv_sec && toffset.tv_usec > max_adj_offset_usec)) 106054359Sroberto { 106154359Sroberto /* 106254359Sroberto * hopeless - set the clock - and clear the timing 106354359Sroberto */ 106454359Sroberto set_time(offset); 106554359Sroberto clock_adjust = 0; 106654359Sroberto skip_adjust = 1; 106754359Sroberto return; 106854359Sroberto } 106954359Sroberto 107054359Sroberto usecoffset = offset->tv_sec * 1000000 + offset->tv_usec; 107154359Sroberto 107254359Sroberto clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT); /* adjustment to make for next period */ 107354359Sroberto 107454359Sroberto tmp = 0; 107554359Sroberto while (adjustments > (1 << tmp)) 107654359Sroberto tmp++; 107754359Sroberto adjustments = 0; 107854359Sroberto if (tmp > FREQ_WEIGHT) 107954359Sroberto tmp = FREQ_WEIGHT; 108054359Sroberto 108154359Sroberto accum_drift += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp); 108254359Sroberto 108354359Sroberto if (accum_drift > MAX_DRIFT) /* clamp into interval */ 108454359Sroberto accum_drift = MAX_DRIFT; 108554359Sroberto else 108654359Sroberto if (accum_drift < -MAX_DRIFT) 108754359Sroberto accum_drift = -MAX_DRIFT; 108854359Sroberto 108954359Sroberto update_drift(drift_file, usecoffset, reftime); 109054359Sroberto LPRINTF("clock_adjust: %s, clock_adjust %ld, drift_comp %ld(%ld) ", 109154359Sroberto pr_timeval(offset),(long int) R_SHIFT(clock_adjust, USECSCALE), 109254359Sroberto (long int)R_SHIFT(accum_drift, USECSCALE), (long int)accum_drift); 109354359Sroberto} 109454359Sroberto 109554359Sroberto/*----------------------------------------------------------------------- 109654359Sroberto * adjust the clock by a small mount to simulate frequency correction 109754359Sroberto */ 109854359Srobertostatic void 109954359Srobertoperiodic_adjust( 110054359Sroberto void 110154359Sroberto ) 110254359Sroberto{ 110354359Sroberto register long adjustment; 110454359Sroberto 110554359Sroberto adjustments++; 110654359Sroberto 110754359Sroberto adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT); 110854359Sroberto 110954359Sroberto clock_adjust -= adjustment; 111054359Sroberto 111154359Sroberto adjustment += R_SHIFT(accum_drift, USECSCALE+ADJINTERVAL); 111254359Sroberto 111354359Sroberto adj_time(adjustment); 111454359Sroberto} 111554359Sroberto 111654359Sroberto/*----------------------------------------------------------------------- 111754359Sroberto * control synchronisation status (warnings) and do periodic adjusts 111854359Sroberto * (frequency control simulation) 111954359Sroberto */ 112054359Srobertostatic void 112154359Srobertotick( 1122106424Sroberto int signum 112354359Sroberto ) 112454359Sroberto{ 112554359Sroberto static unsigned long last_notice = 0; 112654359Sroberto 112754359Sroberto#if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC) 112854359Sroberto (void)signal(SIGALRM, tick); 112954359Sroberto#endif 113054359Sroberto 113154359Sroberto periodic_adjust(); 113254359Sroberto 113354359Sroberto ticks += 1<<ADJINTERVAL; 113454359Sroberto 113554359Sroberto if ((ticks - last_sync) > MAX_UNSYNC) 113654359Sroberto { 113754359Sroberto /* 113854359Sroberto * not getting time for a while 113954359Sroberto */ 114054359Sroberto if (sync_state == SYNC) 114154359Sroberto { 114254359Sroberto /* 114354359Sroberto * completely lost information 114454359Sroberto */ 114554359Sroberto sync_state = NO_SYNC; 114654359Sroberto syslog(LOG_INFO, "DCF77 reception lost (timeout)"); 114754359Sroberto last_notice = ticks; 114854359Sroberto } 114954359Sroberto else 115054359Sroberto /* 115154359Sroberto * in NO_SYNC state - look whether its time to speak up again 115254359Sroberto */ 115354359Sroberto if ((ticks - last_notice) > NOTICE_INTERVAL) 115454359Sroberto { 115554359Sroberto syslog(LOG_NOTICE, "still not synchronized to DCF77 - check receiver/signal"); 115654359Sroberto last_notice = ticks; 115754359Sroberto } 115854359Sroberto } 115954359Sroberto 116054359Sroberto#ifndef ITIMER_REAL 116154359Sroberto (void) alarm(1<<ADJINTERVAL); 116254359Sroberto#endif 116354359Sroberto} 116454359Sroberto 116554359Sroberto/*----------------------------------------------------------------------- 116654359Sroberto * break association from terminal to avoid catching terminal 116754359Sroberto * or process group related signals (-> daemon operation) 116854359Sroberto */ 116954359Srobertostatic void 117054359Srobertodetach( 117154359Sroberto void 117254359Sroberto ) 117354359Sroberto{ 117454359Sroberto# ifdef HAVE_DAEMON 117554359Sroberto daemon(0, 0); 117654359Sroberto# else /* not HAVE_DAEMON */ 117754359Sroberto if (fork()) 117854359Sroberto exit(0); 117954359Sroberto 118054359Sroberto { 118154359Sroberto u_long s; 118254359Sroberto int max_fd; 118354359Sroberto 118454359Sroberto#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) 118554359Sroberto max_fd = sysconf(_SC_OPEN_MAX); 118654359Sroberto#else /* HAVE_SYSCONF && _SC_OPEN_MAX */ 118754359Sroberto max_fd = getdtablesize(); 118854359Sroberto#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ 118954359Sroberto for (s = 0; s < max_fd; s++) 119054359Sroberto (void) close((int)s); 119154359Sroberto (void) open("/", 0); 119254359Sroberto (void) dup2(0, 1); 119354359Sroberto (void) dup2(0, 2); 119454359Sroberto#ifdef SYS_DOMAINOS 119554359Sroberto { 119654359Sroberto uid_$t puid; 119754359Sroberto status_$t st; 119854359Sroberto 119954359Sroberto proc2_$who_am_i(&puid); 120054359Sroberto proc2_$make_server(&puid, &st); 120154359Sroberto } 120254359Sroberto#endif /* SYS_DOMAINOS */ 120354359Sroberto#if defined(HAVE_SETPGID) || defined(HAVE_SETSID) 120454359Sroberto# ifdef HAVE_SETSID 120554359Sroberto if (setsid() == (pid_t)-1) 120654359Sroberto syslog(LOG_ERR, "dcfd: setsid(): %m"); 120754359Sroberto# else 120854359Sroberto if (setpgid(0, 0) == -1) 120954359Sroberto syslog(LOG_ERR, "dcfd: setpgid(): %m"); 121054359Sroberto# endif 121154359Sroberto#else /* HAVE_SETPGID || HAVE_SETSID */ 121254359Sroberto { 121354359Sroberto int fid; 121454359Sroberto 121554359Sroberto fid = open("/dev/tty", 2); 121654359Sroberto if (fid >= 0) 121754359Sroberto { 121854359Sroberto (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); 121954359Sroberto (void) close(fid); 122054359Sroberto } 122154359Sroberto# ifdef HAVE_SETPGRP_0 122254359Sroberto (void) setpgrp(); 122354359Sroberto# else /* HAVE_SETPGRP_0 */ 122454359Sroberto (void) setpgrp(0, getpid()); 122554359Sroberto# endif /* HAVE_SETPGRP_0 */ 122654359Sroberto } 122754359Sroberto#endif /* HAVE_SETPGID || HAVE_SETSID */ 122854359Sroberto } 122954359Sroberto#endif /* not HAVE_DAEMON */ 123054359Sroberto} 123154359Sroberto 123254359Sroberto/*----------------------------------------------------------------------- 123354359Sroberto * list possible arguments and options 123454359Sroberto */ 123554359Srobertostatic void 123654359Srobertousage( 123754359Sroberto char *program 123854359Sroberto ) 123954359Sroberto{ 124054359Sroberto fprintf(stderr, "usage: %s [-n] [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] [-D <input delay>] <device>\n", program); 124154359Sroberto fprintf(stderr, "\t-n do not change time\n"); 124254359Sroberto fprintf(stderr, "\t-i interactive\n"); 124354359Sroberto fprintf(stderr, "\t-t trace (print all datagrams)\n"); 124454359Sroberto fprintf(stderr, "\t-f print all databits (includes PTB private data)\n"); 124554359Sroberto fprintf(stderr, "\t-l print loop filter debug information\n"); 124654359Sroberto fprintf(stderr, "\t-o print offet average for current minute\n"); 124754359Sroberto fprintf(stderr, "\t-Y make internal Y2K checks then exit\n"); /* Y2KFixes */ 124854359Sroberto fprintf(stderr, "\t-d <drift_file> specify alternate drift file\n"); 124954359Sroberto fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n"); 125054359Sroberto} 125154359Sroberto 125254359Sroberto/*----------------------------------------------------------------------- 125354359Sroberto * check_y2k() - internal check of Y2K logic 125454359Sroberto * (a lot of this logic lifted from ../ntpd/check_y2k.c) 125554359Sroberto */ 1256106424Srobertostatic int 125754359Srobertocheck_y2k( void ) 1258282408Scy{ 125954359Sroberto int year; /* current working year */ 126054359Sroberto int year0 = 1900; /* sarting year for NTP time */ 126154359Sroberto int yearend; /* ending year we test for NTP time. 126254359Sroberto * 32-bit systems: through 2036, the 126354359Sroberto **year in which NTP time overflows. 126454359Sroberto * 64-bit systems: a reasonable upper 126554359Sroberto **limit (well, maybe somewhat beyond 126654359Sroberto **reasonable, but well before the 126754359Sroberto **max time, by which time the earth 126854359Sroberto **will be dead.) */ 126954359Sroberto time_t Time; 127054359Sroberto struct tm LocalTime; 127154359Sroberto 127254359Sroberto int Fatals, Warnings; 127354359Sroberto#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \ 127454359Sroberto Warnings++; else Fatals++ 127554359Sroberto 127654359Sroberto Fatals = Warnings = 0; 127754359Sroberto 127854359Sroberto Time = time( (time_t *)NULL ); 127954359Sroberto LocalTime = *localtime( &Time ); 128054359Sroberto 128154359Sroberto year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */ 128254359Sroberto ? ( 400 * 3 ) /* three greater gregorian cycles */ 128354359Sroberto : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/ 128454359Sroberto /* NOTE: will automacially expand test years on 128554359Sroberto * 64 bit machines.... this may cause some of the 128654359Sroberto * existing ntp logic to fail for years beyond 128754359Sroberto * 2036 (the current 32-bit limit). If all checks 128854359Sroberto * fail ONLY beyond year 2036 you may ignore such 128954359Sroberto * errors, at least for a decade or so. */ 129054359Sroberto yearend = year0 + year; 129154359Sroberto 129254359Sroberto year = 1900+YEAR_PIVOT; 129354359Sroberto printf( " starting year %04d\n", (int) year ); 129454359Sroberto printf( " ending year %04d\n", (int) yearend ); 129554359Sroberto 129654359Sroberto for ( ; year < yearend; year++ ) 129754359Sroberto { 129854359Sroberto clocktime_t ct; 129954359Sroberto time_t Observed; 130054359Sroberto time_t Expected; 130154359Sroberto unsigned Flag; 130254359Sroberto unsigned long t; 130354359Sroberto 130454359Sroberto ct.day = 1; 130554359Sroberto ct.month = 1; 130654359Sroberto ct.year = year; 130754359Sroberto ct.hour = ct.minute = ct.second = ct.usecond = 0; 130854359Sroberto ct.utcoffset = 0; 130954359Sroberto ct.flags = 0; 131054359Sroberto 131154359Sroberto Flag = 0; 131254359Sroberto Observed = dcf_to_unixtime( &ct, &Flag ); 131354359Sroberto /* seems to be a clone of parse_to_unixtime() with 131454359Sroberto * *a minor difference to arg2 type */ 131554359Sroberto if ( ct.year != year ) 131654359Sroberto { 1317282408Scy fprintf( stdout, 131854359Sroberto "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n", 131954359Sroberto (int)year, (int)Flag, (int)ct.year ); 132054359Sroberto Error(year); 132154359Sroberto break; 132254359Sroberto } 132354359Sroberto t = julian0(year) - julian0(1970); /* Julian day from 1970 */ 132454359Sroberto Expected = t * 24 * 60 * 60; 132554359Sroberto if ( Observed != Expected || Flag ) 132654359Sroberto { /* time difference */ 1327282408Scy fprintf( stdout, 132854359Sroberto "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", 1329282408Scy year, (int)Flag, 133054359Sroberto (unsigned long)Observed, (unsigned long)Expected, 133154359Sroberto ((long)Observed - (long)Expected) ); 133254359Sroberto Error(year); 133354359Sroberto break; 133454359Sroberto } 133554359Sroberto 133654359Sroberto } 133754359Sroberto 133854359Sroberto return ( Fatals ); 133954359Sroberto} 134054359Sroberto 134154359Sroberto/*-------------------------------------------------- 134254359Sroberto * rawdcf_init - set up modem lines for RAWDCF receivers 134354359Sroberto */ 134454359Sroberto#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR)) 134554359Srobertostatic void 134654359Srobertorawdcf_init( 134754359Sroberto int fd 134854359Sroberto ) 134954359Sroberto{ 135054359Sroberto /* 135154359Sroberto * You can use the RS232 to supply the power for a DCF77 receiver. 135254359Sroberto * Here a voltage between the DTR and the RTS line is used. Unfortunately 135354359Sroberto * the name has changed from CIOCM_DTR to TIOCM_DTR recently. 135454359Sroberto */ 1355282408Scy 135654359Sroberto#ifdef TIOCM_DTR 135754359Sroberto int sl232 = TIOCM_DTR; /* turn on DTR for power supply */ 135854359Sroberto#else 135954359Sroberto int sl232 = CIOCM_DTR; /* turn on DTR for power supply */ 136054359Sroberto#endif 136154359Sroberto 136254359Sroberto if (ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) 136354359Sroberto { 136454359Sroberto syslog(LOG_NOTICE, "rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m"); 136554359Sroberto } 136654359Sroberto} 136754359Sroberto#else 136854359Srobertostatic void 136954359Srobertorawdcf_init( 137054359Sroberto int fd 137154359Sroberto ) 137254359Sroberto{ 137354359Sroberto syslog(LOG_NOTICE, "rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules"); 137454359Sroberto} 137554359Sroberto#endif /* DTR initialisation type */ 137654359Sroberto 137754359Sroberto/*----------------------------------------------------------------------- 137854359Sroberto * main loop - argument interpreter / setup / main loop 137954359Sroberto */ 138054359Srobertoint 138154359Srobertomain( 138254359Sroberto int argc, 138354359Sroberto char **argv 138454359Sroberto ) 138554359Sroberto{ 138654359Sroberto unsigned char c; 138754359Sroberto char **a = argv; 138854359Sroberto int ac = argc; 138954359Sroberto char *file = NULL; 139054359Sroberto const char *drift_file = "/etc/dcfd.drift"; 139154359Sroberto int fd; 139254359Sroberto int offset = 15; 139354359Sroberto int offsets = 0; 139454359Sroberto int delay = DEFAULT_DELAY; /* average delay from input edge to time stamping */ 139554359Sroberto int trace = 0; 139654359Sroberto int errs = 0; 139754359Sroberto 139854359Sroberto /* 139954359Sroberto * process arguments 140054359Sroberto */ 140154359Sroberto while (--ac) 140254359Sroberto { 140354359Sroberto char *arg = *++a; 140454359Sroberto if (*arg == '-') 140554359Sroberto while ((c = *++arg)) 140654359Sroberto switch (c) 140754359Sroberto { 140854359Sroberto case 't': 140954359Sroberto trace = 1; 141054359Sroberto interactive = 1; 141154359Sroberto break; 141254359Sroberto 141354359Sroberto case 'f': 141454359Sroberto offset = 0; 141554359Sroberto interactive = 1; 141654359Sroberto break; 141754359Sroberto 141854359Sroberto case 'l': 141954359Sroberto loop_filter_debug = 1; 142054359Sroberto offsets = 1; 142154359Sroberto interactive = 1; 142254359Sroberto break; 142354359Sroberto 142454359Sroberto case 'n': 142554359Sroberto no_set = 1; 142654359Sroberto break; 142754359Sroberto 142854359Sroberto case 'o': 142954359Sroberto offsets = 1; 143054359Sroberto interactive = 1; 143154359Sroberto break; 143254359Sroberto 143354359Sroberto case 'i': 143454359Sroberto interactive = 1; 143554359Sroberto break; 143654359Sroberto 143754359Sroberto case 'D': 143854359Sroberto if (ac > 1) 143954359Sroberto { 144054359Sroberto delay = atoi(*++a); 144154359Sroberto ac--; 144254359Sroberto } 144354359Sroberto else 144454359Sroberto { 144554359Sroberto fprintf(stderr, "%s: -D requires integer argument\n", argv[0]); 144654359Sroberto errs=1; 144754359Sroberto } 144854359Sroberto break; 1449282408Scy 145054359Sroberto case 'd': 145154359Sroberto if (ac > 1) 145254359Sroberto { 145354359Sroberto drift_file = *++a; 145454359Sroberto ac--; 145554359Sroberto } 145654359Sroberto else 145754359Sroberto { 145854359Sroberto fprintf(stderr, "%s: -d requires file name argument\n", argv[0]); 145954359Sroberto errs=1; 146054359Sroberto } 146154359Sroberto break; 1462282408Scy 1463282408Scy case 'Y': 146454359Sroberto errs=check_y2k(); 146554359Sroberto exit( errs ? 1 : 0 ); 146654359Sroberto 146754359Sroberto default: 146854359Sroberto fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); 146954359Sroberto errs=1; 147054359Sroberto break; 147154359Sroberto } 147254359Sroberto else 147354359Sroberto if (file == NULL) 147454359Sroberto file = arg; 147554359Sroberto else 147654359Sroberto { 147754359Sroberto fprintf(stderr, "%s: device specified twice\n", argv[0]); 147854359Sroberto errs=1; 147954359Sroberto } 148054359Sroberto } 148154359Sroberto 148254359Sroberto if (errs) 148354359Sroberto { 148454359Sroberto usage(argv[0]); 148554359Sroberto exit(1); 148654359Sroberto } 148754359Sroberto else 148854359Sroberto if (file == NULL) 148954359Sroberto { 149054359Sroberto fprintf(stderr, "%s: device not specified\n", argv[0]); 149154359Sroberto usage(argv[0]); 149254359Sroberto exit(1); 149354359Sroberto } 149454359Sroberto 149554359Sroberto errs = LINES+1; 149654359Sroberto 149754359Sroberto /* 149854359Sroberto * get access to DCF77 tty port 149954359Sroberto */ 150054359Sroberto fd = open(file, O_RDONLY); 150154359Sroberto if (fd == -1) 150254359Sroberto { 150354359Sroberto perror(file); 150454359Sroberto exit(1); 150554359Sroberto } 150654359Sroberto else 150754359Sroberto { 150854359Sroberto int i, rrc; 150954359Sroberto struct timeval t, tt, tlast; 151054359Sroberto struct timeval timeout; 151154359Sroberto struct timeval phase; 151254359Sroberto struct timeval time_offset; 151354359Sroberto char pbuf[61]; /* printable version */ 151454359Sroberto char buf[61]; /* raw data */ 151554359Sroberto clocktime_t clock_time; /* wall clock time */ 151654359Sroberto time_t utc_time = 0; 151754359Sroberto time_t last_utc_time = 0; 151854359Sroberto long usecerror = 0; 151954359Sroberto long lasterror = 0; 152054359Sroberto#if defined(HAVE_TERMIOS_H) || defined(STREAM) 152154359Sroberto struct termios term; 152254359Sroberto#else /* not HAVE_TERMIOS_H || STREAM */ 152354359Sroberto# if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS) 152454359Sroberto struct termio term; 152554359Sroberto# endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */ 152654359Sroberto#endif /* not HAVE_TERMIOS_H || STREAM */ 152754359Sroberto unsigned int rtc = CVT_NONE; 152854359Sroberto 152954359Sroberto rawdcf_init(fd); 1530282408Scy 153154359Sroberto timeout.tv_sec = 1; 153254359Sroberto timeout.tv_usec = 500000; 153354359Sroberto 153454359Sroberto phase.tv_sec = 0; 153554359Sroberto phase.tv_usec = delay; 153654359Sroberto 153754359Sroberto /* 153854359Sroberto * setup TTY (50 Baud, Read, 8Bit, No Hangup, 1 character IO) 153954359Sroberto */ 154054359Sroberto if (TTY_GETATTR(fd, &term) == -1) 154154359Sroberto { 154254359Sroberto perror("tcgetattr"); 154354359Sroberto exit(1); 154454359Sroberto } 154554359Sroberto 154654359Sroberto memset(term.c_cc, 0, sizeof(term.c_cc)); 154754359Sroberto term.c_cc[VMIN] = 1; 154854359Sroberto#ifdef NO_PARENB_IGNPAR 1549182007Sroberto term.c_cflag = CS8|CREAD|CLOCAL; 155054359Sroberto#else 1551182007Sroberto term.c_cflag = CS8|CREAD|CLOCAL|PARENB; 155254359Sroberto#endif 155354359Sroberto term.c_iflag = IGNPAR; 155454359Sroberto term.c_oflag = 0; 155554359Sroberto term.c_lflag = 0; 155654359Sroberto 1557182007Sroberto cfsetispeed(&term, B50); 1558182007Sroberto cfsetospeed(&term, B50); 1559182007Sroberto 156054359Sroberto if (TTY_SETATTR(fd, &term) == -1) 156154359Sroberto { 156254359Sroberto perror("tcsetattr"); 156354359Sroberto exit(1); 156454359Sroberto } 156554359Sroberto 156654359Sroberto /* 1567132451Sroberto * lose terminal if in daemon operation 156854359Sroberto */ 156954359Sroberto if (!interactive) 157054359Sroberto detach(); 1571282408Scy 157254359Sroberto /* 157354359Sroberto * get syslog() initialized 157454359Sroberto */ 157554359Sroberto#ifdef LOG_DAEMON 157654359Sroberto openlog("dcfd", LOG_PID, LOG_DAEMON); 157754359Sroberto#else 157854359Sroberto openlog("dcfd", LOG_PID); 157954359Sroberto#endif 158054359Sroberto 158154359Sroberto /* 158254359Sroberto * setup periodic operations (state control / frequency control) 158354359Sroberto */ 158454359Sroberto#ifdef HAVE_SIGACTION 158554359Sroberto { 158654359Sroberto struct sigaction act; 158754359Sroberto 158854359Sroberto# ifdef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION 1589280849Scy act.sa_sigaction = (void (*) (int, siginfo_t *, void *))0; 159054359Sroberto# endif /* HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION */ 1591182007Sroberto act.sa_handler = tick; 159254359Sroberto sigemptyset(&act.sa_mask); 159354359Sroberto act.sa_flags = 0; 159454359Sroberto 159554359Sroberto if (sigaction(SIGALRM, &act, (struct sigaction *)0) == -1) 159654359Sroberto { 159754359Sroberto syslog(LOG_ERR, "sigaction(SIGALRM): %m"); 159854359Sroberto exit(1); 159954359Sroberto } 160054359Sroberto } 160154359Sroberto#else 1602182007Sroberto#ifdef HAVE_SIGVEC 1603182007Sroberto { 1604182007Sroberto struct sigvec vec; 1605182007Sroberto 1606182007Sroberto vec.sv_handler = tick; 1607182007Sroberto vec.sv_mask = 0; 1608182007Sroberto vec.sv_flags = 0; 1609182007Sroberto 1610182007Sroberto if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1) 1611182007Sroberto { 1612182007Sroberto syslog(LOG_ERR, "sigvec(SIGALRM): %m"); 1613182007Sroberto exit(1); 1614182007Sroberto } 1615182007Sroberto } 1616182007Sroberto#else 161754359Sroberto (void) signal(SIGALRM, tick); 161854359Sroberto#endif 161954359Sroberto#endif 162054359Sroberto 162154359Sroberto#ifdef ITIMER_REAL 162254359Sroberto { 162354359Sroberto struct itimerval it; 162454359Sroberto 162554359Sroberto it.it_interval.tv_sec = 1<<ADJINTERVAL; 162654359Sroberto it.it_interval.tv_usec = 0; 162754359Sroberto it.it_value.tv_sec = 1<<ADJINTERVAL; 162854359Sroberto it.it_value.tv_usec = 0; 1629282408Scy 163054359Sroberto if (setitimer(ITIMER_REAL, &it, (struct itimerval *)0) == -1) 163154359Sroberto { 163254359Sroberto syslog(LOG_ERR, "setitimer: %m"); 163354359Sroberto exit(1); 163454359Sroberto } 163554359Sroberto } 163654359Sroberto#else 163754359Sroberto (void) alarm(1<<ADJINTERVAL); 163854359Sroberto#endif 163954359Sroberto 1640182007Sroberto PRINTF(" DCF77 monitor %s - Copyright (C) 1993-2005 by Frank Kardel\n\n", revision); 164154359Sroberto 164254359Sroberto pbuf[60] = '\0'; 164354359Sroberto for ( i = 0; i < 60; i++) 164454359Sroberto pbuf[i] = '.'; 164554359Sroberto 164654359Sroberto read_drift(drift_file); 164754359Sroberto 164854359Sroberto /* 164954359Sroberto * what time is it now (for interval measurement) 165054359Sroberto */ 165154359Sroberto gettimeofday(&tlast, 0L); 165254359Sroberto i = 0; 165354359Sroberto /* 165454359Sroberto * loop until input trouble ... 165554359Sroberto */ 165654359Sroberto do 165754359Sroberto { 165854359Sroberto /* 165954359Sroberto * get an impulse 166054359Sroberto */ 166154359Sroberto while ((rrc = read(fd, &c, 1)) == 1) 166254359Sroberto { 166354359Sroberto gettimeofday(&t, 0L); 166454359Sroberto tt = t; 166554359Sroberto timersub(&t, &tlast); 166654359Sroberto 166754359Sroberto if (errs > LINES) 166854359Sroberto { 166954359Sroberto PRINTF(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]); 167054359Sroberto PRINTF(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]); 167154359Sroberto errs = 0; 167254359Sroberto } 167354359Sroberto 167454359Sroberto /* 167554359Sroberto * timeout -> possible minute mark -> interpretation 167654359Sroberto */ 167754359Sroberto if (timercmp(&t, &timeout, >)) 167854359Sroberto { 167954359Sroberto PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]); 168054359Sroberto 168154359Sroberto if ((rtc = cvt_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK) 168254359Sroberto { 168354359Sroberto /* 168454359Sroberto * this data was bad - well - forget synchronisation for now 168554359Sroberto */ 168654359Sroberto PRINTF("\n"); 168754359Sroberto if (sync_state == SYNC) 168854359Sroberto { 168954359Sroberto sync_state = NO_SYNC; 169054359Sroberto syslog(LOG_INFO, "DCF77 reception lost (bad data)"); 169154359Sroberto } 169254359Sroberto errs++; 169354359Sroberto } 169454359Sroberto else 169554359Sroberto if (trace) 169654359Sroberto { 169754359Sroberto PRINTF("\r %.*s ", 59 - offset, &buf[offset]); 169854359Sroberto } 169954359Sroberto 170054359Sroberto 170154359Sroberto buf[0] = c; 170254359Sroberto 170354359Sroberto /* 170454359Sroberto * collect first character 170554359Sroberto */ 170654359Sroberto if (((c^0xFF)+1) & (c^0xFF)) 170754359Sroberto pbuf[0] = '?'; 170854359Sroberto else 170954359Sroberto pbuf[0] = type(c) ? '#' : '-'; 171054359Sroberto 171154359Sroberto for ( i = 1; i < 60; i++) 171254359Sroberto pbuf[i] = '.'; 171354359Sroberto 171454359Sroberto i = 0; 171554359Sroberto } 171654359Sroberto else 171754359Sroberto { 171854359Sroberto /* 171954359Sroberto * collect character 172054359Sroberto */ 172154359Sroberto buf[i] = c; 172254359Sroberto 172354359Sroberto /* 172454359Sroberto * initial guess (usually correct) 172554359Sroberto */ 172654359Sroberto if (((c^0xFF)+1) & (c^0xFF)) 172754359Sroberto pbuf[i] = '?'; 172854359Sroberto else 172954359Sroberto pbuf[i] = type(c) ? '#' : '-'; 173054359Sroberto 173154359Sroberto PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]); 173254359Sroberto } 173354359Sroberto 173454359Sroberto if (i == 0 && rtc == CVT_OK) 173554359Sroberto { 173654359Sroberto /* 173754359Sroberto * we got a good time code here - try to convert it to 173854359Sroberto * UTC 173954359Sroberto */ 174054359Sroberto if ((utc_time = dcf_to_unixtime(&clock_time, &rtc)) == -1) 174154359Sroberto { 174254359Sroberto PRINTF("*** BAD CONVERSION\n"); 174354359Sroberto } 174454359Sroberto 174554359Sroberto if (utc_time != (last_utc_time + 60)) 174654359Sroberto { 174754359Sroberto /* 174854359Sroberto * well, two successive sucessful telegrams are not 60 seconds 174954359Sroberto * apart 175054359Sroberto */ 175154359Sroberto PRINTF("*** NO MINUTE INC\n"); 175254359Sroberto if (sync_state == SYNC) 175354359Sroberto { 175454359Sroberto sync_state = NO_SYNC; 175554359Sroberto syslog(LOG_INFO, "DCF77 reception lost (data mismatch)"); 175654359Sroberto } 175754359Sroberto errs++; 175854359Sroberto rtc = CVT_FAIL|CVT_BADTIME|CVT_BADDATE; 175954359Sroberto } 176054359Sroberto else 176154359Sroberto usecerror = 0; 176254359Sroberto 176354359Sroberto last_utc_time = utc_time; 176454359Sroberto } 176554359Sroberto 176654359Sroberto if (rtc == CVT_OK) 176754359Sroberto { 176854359Sroberto if (i == 0) 176954359Sroberto { 177054359Sroberto /* 177154359Sroberto * valid time code - determine offset and 177254359Sroberto * note regained reception 177354359Sroberto */ 177454359Sroberto last_sync = ticks; 177554359Sroberto if (sync_state == NO_SYNC) 177654359Sroberto { 177754359Sroberto syslog(LOG_INFO, "receiving DCF77"); 177854359Sroberto } 177954359Sroberto else 178054359Sroberto { 178154359Sroberto /* 178254359Sroberto * we had at least one minute SYNC - thus 178354359Sroberto * last error is valid 178454359Sroberto */ 178554359Sroberto time_offset.tv_sec = lasterror / 1000000; 178654359Sroberto time_offset.tv_usec = lasterror % 1000000; 178754359Sroberto adjust_clock(&time_offset, drift_file, utc_time); 178854359Sroberto } 178954359Sroberto sync_state = SYNC; 179054359Sroberto } 179154359Sroberto 179254359Sroberto time_offset.tv_sec = utc_time + i; 179354359Sroberto time_offset.tv_usec = 0; 179454359Sroberto 179554359Sroberto timeradd(&time_offset, &phase); 179654359Sroberto 179754359Sroberto usecerror += (time_offset.tv_sec - tt.tv_sec) * 1000000 + time_offset.tv_usec 179854359Sroberto -tt.tv_usec; 179954359Sroberto 180054359Sroberto /* 180154359Sroberto * output interpreted DCF77 data 180254359Sroberto */ 1803132451Sroberto PRINTF(offsets ? "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s> (%c%ld.%06lds)" : 1804132451Sroberto "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s>", 180554359Sroberto wday[clock_time.wday], 180654359Sroberto clock_time.hour, clock_time.minute, i, clock_time.day, clock_time.month, 180754359Sroberto clock_time.year, 1808282408Scy (clock_time.flags & DCFB_CALLBIT) ? "R" : "_", 180954359Sroberto (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_", 181054359Sroberto (clock_time.flags & DCFB_DST) ? "D" : "_", 181154359Sroberto (clock_time.flags & DCFB_LEAP) ? "L" : "_", 181254359Sroberto (lasterror < 0) ? '-' : '+', l_abs(lasterror) / 1000000, l_abs(lasterror) % 1000000 181354359Sroberto ); 181454359Sroberto 181554359Sroberto if (trace && (i == 0)) 181654359Sroberto { 181754359Sroberto PRINTF("\n"); 181854359Sroberto errs++; 181954359Sroberto } 182054359Sroberto lasterror = usecerror / (i+1); 182154359Sroberto } 182254359Sroberto else 182354359Sroberto { 182454359Sroberto lasterror = 0; /* we cannot calculate phase errors on bad reception */ 182554359Sroberto } 182654359Sroberto 182754359Sroberto PRINTF("\r"); 182854359Sroberto 182954359Sroberto if (i < 60) 183054359Sroberto { 183154359Sroberto i++; 183254359Sroberto } 183354359Sroberto 183454359Sroberto tlast = tt; 183554359Sroberto 183654359Sroberto if (interactive) 183754359Sroberto fflush(stdout); 183854359Sroberto } 183954359Sroberto } while ((rrc == -1) && (errno == EINTR)); 1840282408Scy 184154359Sroberto /* 184254359Sroberto * lost IO - sorry guys 184354359Sroberto */ 184454359Sroberto syslog(LOG_ERR, "TERMINATING - cannot read from device %s (%m)", file); 184554359Sroberto 184654359Sroberto (void)close(fd); 184754359Sroberto } 184854359Sroberto 184954359Sroberto closelog(); 1850282408Scy 185154359Sroberto return 0; 185254359Sroberto} 1853182007Sroberto 1854182007Sroberto/* 1855182007Sroberto * History: 1856182007Sroberto * 1857182007Sroberto * dcfd.c,v 1858182007Sroberto * Revision 4.18 2005/10/07 22:08:18 kardel 1859182007Sroberto * make dcfd.c compile on NetBSD 3.99.9 again (configure/sigvec compatibility fix) 1860182007Sroberto * 1861182007Sroberto * Revision 4.17.2.1 2005/10/03 19:15:16 kardel 1862182007Sroberto * work around configure not detecting a missing sigvec compatibility 1863182007Sroberto * interface on NetBSD 3.99.9 and above 1864182007Sroberto * 1865182007Sroberto * Revision 4.17 2005/08/10 10:09:44 kardel 1866182007Sroberto * output revision information 1867182007Sroberto * 1868182007Sroberto * Revision 4.16 2005/08/10 06:33:25 kardel 1869182007Sroberto * cleanup warnings 1870182007Sroberto * 1871182007Sroberto * Revision 4.15 2005/08/10 06:28:45 kardel 1872182007Sroberto * fix setting of baud rate 1873182007Sroberto * 1874182007Sroberto * Revision 4.14 2005/04/16 17:32:10 kardel 1875182007Sroberto * update copyright 1876182007Sroberto * 1877182007Sroberto * Revision 4.13 2004/11/14 15:29:41 kardel 1878182007Sroberto * support PPSAPI, upgrade Copyright to Berkeley style 1879182007Sroberto * 1880182007Sroberto */ 1881