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