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