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