📄 dcfd.c
字号:
* 64 bit machines.... this may cause some of the * existing ntp logic to fail for years beyond * 2036 (the current 32-bit limit). If all checks * fail ONLY beyond year 2036 you may ignore such * errors, at least for a decade or so. */ yearend = year0 + year; year = 1900+YEAR_PIVOT; printf( " starting year %04d\n", (int) year ); printf( " ending year %04d\n", (int) yearend ); for ( ; year < yearend; year++ ) { clocktime_t ct; time_t Observed; time_t Expected; unsigned Flag; unsigned long t; ct.day = 1; ct.month = 1; ct.year = year; ct.hour = ct.minute = ct.second = ct.usecond = 0; ct.utcoffset = 0; ct.flags = 0; Flag = 0; Observed = dcf_to_unixtime( &ct, &Flag ); /* seems to be a clone of parse_to_unixtime() with * *a minor difference to arg2 type */ if ( ct.year != year ) { fprintf( stdout, "%04d: dcf_to_unixtime(,%d) CORRUPTED ct.year: was %d\n", (int)year, (int)Flag, (int)ct.year ); Error(year); break; } t = julian0(year) - julian0(1970); /* Julian day from 1970 */ Expected = t * 24 * 60 * 60; if ( Observed != Expected || Flag ) { /* time difference */ fprintf( stdout, "%04d: dcf_to_unixtime(,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", year, (int)Flag, (unsigned long)Observed, (unsigned long)Expected, ((long)Observed - (long)Expected) ); Error(year); break; } if ( year >= YEAR_PIVOT+1900 ) { /* check year % 100 code we put into dcf_to_unixtime() */ ct.year = year % 100; Flag = 0; Observed = dcf_to_unixtime( &ct, &Flag ); if ( Observed != Expected || Flag ) { /* time difference */ fprintf( stdout, "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", year, (int)ct.year, (int)Flag, (unsigned long)Observed, (unsigned long)Expected, ((long)Observed - (long)Expected) ); Error(year); break; } /* check year - 1900 code we put into dcf_to_unixtime() */ ct.year = year - 1900; Flag = 0; Observed = dcf_to_unixtime( &ct, &Flag ); if ( Observed != Expected || Flag ) { /* time difference */ fprintf( stdout, "%04d: dcf_to_unixtime(%d,%d) FAILURE: was=%lu s/b=%lu (%ld)\n", year, (int)ct.year, (int)Flag, (unsigned long)Observed, (unsigned long)Expected, ((long)Observed - (long)Expected) ); Error(year); break; } } } return ( Fatals );}/*-------------------------------------------------- * rawdcf_init - set up modem lines for RAWDCF receivers */#if defined(TIOCMSET) && (defined(TIOCM_DTR) || defined(CIOCM_DTR))static voidrawdcf_init( int fd ){ /* * You can use the RS232 to supply the power for a DCF77 receiver. * Here a voltage between the DTR and the RTS line is used. Unfortunately * the name has changed from CIOCM_DTR to TIOCM_DTR recently. */ #ifdef TIOCM_DTR int sl232 = TIOCM_DTR; /* turn on DTR for power supply */#else int sl232 = CIOCM_DTR; /* turn on DTR for power supply */#endif if (ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1) { syslog(LOG_NOTICE, "rawdcf_init: WARNING: ioctl(fd, TIOCMSET, [C|T]IOCM_DTR): %m"); }}#elsestatic voidrawdcf_init( int fd ){ syslog(LOG_NOTICE, "rawdcf_init: WARNING: OS interface incapable of setting DTR to power DCF modules");}#endif /* DTR initialisation type *//*----------------------------------------------------------------------- * main loop - argument interpreter / setup / main loop */intmain( int argc, char **argv ){ unsigned char c; char **a = argv; int ac = argc; char *file = NULL; const char *drift_file = "/etc/dcfd.drift"; int fd; int offset = 15; int offsets = 0; int delay = DEFAULT_DELAY; /* average delay from input edge to time stamping */ int trace = 0; int errs = 0; /* * process arguments */ while (--ac) { char *arg = *++a; if (*arg == '-') while ((c = *++arg)) switch (c) { case 't': trace = 1; interactive = 1; break; case 'f': offset = 0; interactive = 1; break; case 'l': loop_filter_debug = 1; offsets = 1; interactive = 1; break; case 'n': no_set = 1; break; case 'o': offsets = 1; interactive = 1; break; case 'i': interactive = 1; break; case 'D': if (ac > 1) { delay = atoi(*++a); ac--; } else { fprintf(stderr, "%s: -D requires integer argument\n", argv[0]); errs=1; } break; case 'd': if (ac > 1) { drift_file = *++a; ac--; } else { fprintf(stderr, "%s: -d requires file name argument\n", argv[0]); errs=1; } break; case 'Y': errs=check_y2k(); exit( errs ? 1 : 0 ); default: fprintf(stderr, "%s: unknown option -%c\n", argv[0], c); errs=1; break; } else if (file == NULL) file = arg; else { fprintf(stderr, "%s: device specified twice\n", argv[0]); errs=1; } } if (errs) { usage(argv[0]); exit(1); } else if (file == NULL) { fprintf(stderr, "%s: device not specified\n", argv[0]); usage(argv[0]); exit(1); } errs = LINES+1; /* * get access to DCF77 tty port */ fd = open(file, O_RDONLY); if (fd == -1) { perror(file); exit(1); } else { int i, rrc; struct timeval t, tt, tlast; struct timeval timeout; struct timeval phase; struct timeval time_offset; char pbuf[61]; /* printable version */ char buf[61]; /* raw data */ clocktime_t clock_time; /* wall clock time */ time_t utc_time = 0; time_t last_utc_time = 0; long usecerror = 0; long lasterror = 0;#if defined(HAVE_TERMIOS_H) || defined(STREAM) struct termios term;#else /* not HAVE_TERMIOS_H || STREAM */# if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS) struct termio term;# endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */#endif /* not HAVE_TERMIOS_H || STREAM */ unsigned int rtc = CVT_NONE; rawdcf_init(fd); timeout.tv_sec = 1; timeout.tv_usec = 500000; phase.tv_sec = 0; phase.tv_usec = delay; /* * setup TTY (50 Baud, Read, 8Bit, No Hangup, 1 character IO) */ if (TTY_GETATTR(fd, &term) == -1) { perror("tcgetattr"); exit(1); } memset(term.c_cc, 0, sizeof(term.c_cc)); term.c_cc[VMIN] = 1;#ifdef NO_PARENB_IGNPAR term.c_cflag = CS8|CREAD|CLOCAL;#else term.c_cflag = CS8|CREAD|CLOCAL|PARENB;#endif term.c_iflag = IGNPAR; term.c_oflag = 0; term.c_lflag = 0; cfsetispeed(&term, B50); cfsetospeed(&term, B50); if (TTY_SETATTR(fd, &term) == -1) { perror("tcsetattr"); exit(1); } /* * lose terminal if in daemon operation */ if (!interactive) detach(); /* * get syslog() initialized */#ifdef LOG_DAEMON openlog("dcfd", LOG_PID, LOG_DAEMON);#else openlog("dcfd", LOG_PID);#endif /* * setup periodic operations (state control / frequency control) */#ifdef HAVE_SIGACTION { struct sigaction act; act.sa_handler = tick;# ifdef HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION act.sa_sigaction = (void (*) P((int, siginfo_t *, void *)))0;# endif /* HAVE_SA_SIGACTION_IN_STRUCT_SIGACTION */ sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGALRM, &act, (struct sigaction *)0) == -1) { syslog(LOG_ERR, "sigaction(SIGALRM): %m"); exit(1); } }#else#ifdef HAVE_SIGVEC { struct sigvec vec; vec.sv_handler = tick; vec.sv_mask = 0; vec.sv_flags = 0; if (sigvec(SIGALRM, &vec, (struct sigvec *)0) == -1) { syslog(LOG_ERR, "sigvec(SIGALRM): %m"); exit(1); } }#else (void) signal(SIGALRM, tick);#endif#endif#ifdef ITIMER_REAL { struct itimerval it; it.it_interval.tv_sec = 1<<ADJINTERVAL; it.it_interval.tv_usec = 0; it.it_value.tv_sec = 1<<ADJINTERVAL; it.it_value.tv_usec = 0; if (setitimer(ITIMER_REAL, &it, (struct itimerval *)0) == -1) { syslog(LOG_ERR, "setitimer: %m"); exit(1); } }#else (void) alarm(1<<ADJINTERVAL);#endif PRINTF(" DCF77 monitor %s - Copyright (C) 1993-2005 by Frank Kardel\n\n", revision); pbuf[60] = '\0'; for ( i = 0; i < 60; i++) pbuf[i] = '.'; read_drift(drift_file); /* * what time is it now (for interval measurement) */ gettimeofday(&tlast, 0L); i = 0; /* * loop until input trouble ... */ do { /* * get an impulse */ while ((rrc = read(fd, &c, 1)) == 1) { gettimeofday(&t, 0L); tt = t; timersub(&t, &tlast); if (errs > LINES) { PRINTF(" %s", &"PTB private....RADMLSMin....PHour..PMDay..DayMonthYear....P\n"[offset]); PRINTF(" %s", &"---------------RADMLS1248124P124812P1248121241248112481248P\n"[offset]); errs = 0; } /* * timeout -> possible minute mark -> interpretation */ if (timercmp(&t, &timeout, >)) { PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]); if ((rtc = cvt_rawdcf((unsigned char *)buf, i, &clock_time)) != CVT_OK) { /* * this data was bad - well - forget synchronisation for now */ PRINTF("\n"); if (sync_state == SYNC) { sync_state = NO_SYNC; syslog(LOG_INFO, "DCF77 reception lost (bad data)"); } errs++; } else if (trace) { PRINTF("\r %.*s ", 59 - offset, &buf[offset]); } buf[0] = c; /* * collect first character */ if (((c^0xFF)+1) & (c^0xFF)) pbuf[0] = '?'; else pbuf[0] = type(c) ? '#' : '-'; for ( i = 1; i < 60; i++) pbuf[i] = '.'; i = 0; } else { /* * collect character */ buf[i] = c; /* * initial guess (usually correct) */ if (((c^0xFF)+1) & (c^0xFF)) pbuf[i] = '?'; else pbuf[i] = type(c) ? '#' : '-'; PRINTF("%c %.*s ", pat[i % (sizeof(pat)-1)], 59 - offset, &pbuf[offset]); } if (i == 0 && rtc == CVT_OK) { /* * we got a good time code here - try to convert it to * UTC */ if ((utc_time = dcf_to_unixtime(&clock_time, &rtc)) == -1) { PRINTF("*** BAD CONVERSION\n"); } if (utc_time != (last_utc_time + 60)) { /* * well, two successive sucessful telegrams are not 60 seconds * apart */ PRINTF("*** NO MINUTE INC\n"); if (sync_state == SYNC) { sync_state = NO_SYNC; syslog(LOG_INFO, "DCF77 reception lost (data mismatch)"); } errs++; rtc = CVT_FAIL|CVT_BADTIME|CVT_BADDATE; } else usecerror = 0; last_utc_time = utc_time; } if (rtc == CVT_OK) { if (i == 0) { /* * valid time code - determine offset and * note regained reception */ last_sync = ticks; if (sync_state == NO_SYNC) { syslog(LOG_INFO, "receiving DCF77"); } else { /* * we had at least one minute SYNC - thus * last error is valid */ time_offset.tv_sec = lasterror / 1000000; time_offset.tv_usec = lasterror % 1000000; adjust_clock(&time_offset, drift_file, utc_time); } sync_state = SYNC; } time_offset.tv_sec = utc_time + i; time_offset.tv_usec = 0; timeradd(&time_offset, &phase); usecerror += (time_offset.tv_sec - tt.tv_sec) * 1000000 + time_offset.tv_usec -tt.tv_usec; /* * output interpreted DCF77 data */ PRINTF(offsets ? "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s> (%c%ld.%06lds)" : "%s, %2ld:%02ld:%02d, %ld.%02ld.%02ld, <%s%s%s%s>", wday[clock_time.wday], clock_time.hour, clock_time.minute, i, clock_time.day, clock_time.month, clock_time.year, (clock_time.flags & DCFB_ALTERNATE) ? "R" : "_", (clock_time.flags & DCFB_ANNOUNCE) ? "A" : "_", (clock_time.flags & DCFB_DST) ? "D" : "_", (clock_time.flags & DCFB_LEAP) ? "L" : "_", (lasterror < 0) ? '-' : '+', l_abs(lasterror) / 1000000, l_abs(lasterror) % 1000000 ); if (trace && (i == 0)) { PRINTF("\n"); errs++; } lasterror = usecerror / (i+1); } else { lasterror = 0; /* we cannot calculate phase errors on bad reception */ } PRINTF("\r"); if (i < 60) { i++; } tlast = tt; if (interactive) fflush(stdout); } } while ((rrc == -1) && (errno == EINTR)); /* * lost IO - sorry guys */ syslog(LOG_ERR, "TERMINATING - cannot read from device %s (%m)", file); (void)close(fd); } closelog(); return 0;}/* * History: * * dcfd.c,v * Revision 4.18 2005/10/07 22:08:18 kardel * make dcfd.c compile on NetBSD 3.99.9 again (configure/sigvec compatibility fix) * * Revision 4.17.2.1 2005/10/03 19:15:16 kardel * work around configure not detecting a missing sigvec compatibility * interface on NetBSD 3.99.9 and above * * Revision 4.17 2005/08/10 10:09:44 kardel * output revision information * * Revision 4.16 2005/08/10 06:33:25 kardel * cleanup warnings * * Revision 4.15 2005/08/10 06:28:45 kardel * fix setting of baud rate * * Revision 4.14 2005/04/16 17:32:10 kardel * update copyright * * Revision 4.13 2004/11/14 15:29:41 kardel * support PPSAPI, upgrade Copyright to Berkeley style * */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -