📄 dcfd.c
字号:
*/ if (highmax) { lowmax /= highmax; } else { lowmax = 0; } highmax = 0; /* weighted sum of upper bits counts */ cutoff = 0; /* bitcount */ /* * collect weighted sum of lower bits (right of initial guess) */ for (; i < BITS; i++) { highmax+=histbuf[i] * i; cutoff +=histbuf[i]; dprintf((" %d", histbuf[i])); } dprintf(("\n")); /* * determine upper maximum (weighted sum / bit count) */ if (cutoff) { highmax /= cutoff; } else { highmax = BITS-1; } /* * following now holds: * lowmax <= cutoff(initial guess) <= highmax * best cutoff is the minimum nearest to higher bits */ /* * find the minimum between lowmax and highmax (detecting * possibly a minimum span) */ span = cutoff = lowmax; for (i = lowmax; i <= highmax; i++) { if (histbuf[cutoff] > histbuf[i]) { /* * got a new minimum move beginning of minimum (cutoff) and * end of minimum (span) there */ cutoff = span = i; } else if (histbuf[cutoff] == histbuf[i]) { /* * minimum not better yet - but it spans more than * one bit value - follow it */ span = i; } } /* * cutoff point for 1/0 decision is the middle of the minimum section * in the histogram */ cutoff = (cutoff + span) / 2; dprintf(("parse: cvt_rawdcf: lower maximum %d, higher maximum %d, cutoff %d\n", lowmax, highmax, cutoff)); /* * convert the bit counts to symbolic 1/0 information for data conversion */ s = buffer; while ((s < e) && *c && *b) { if (*s == (unsigned char)~0) { /* * invalid character */ *s = '?'; } else { /* * symbolic 1/0 representation */ *s = (*s >= cutoff) ? *b : *c; } s++; b++; c++; } /* * if everything went well so far return the result of the symbolic * conversion routine else just the accumulated errors */ if (rtc != CVT_NONE) { PRINTF("%-30s", "*** BAD DATA"); } return (rtc == CVT_NONE) ? convert_rawdcf(buffer, size, clock_time) : rtc;}/*----------------------------------------------------------------------- * convert a wall clock time description of DCF77 to a Unix time (seconds * since 1.1. 1970 UTC) */static time_tdcf_to_unixtime( clocktime_t *clock_time, unsigned *cvtrtc ){#define SETRTC(_X_) { if (cvtrtc) *cvtrtc = (_X_); } static int days_of_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; register int i; time_t t; /* * map 2 digit years to 19xx (DCF77 is a 20th century item) */ if ( clock_time->year < YEAR_PIVOT ) /* in case of Y2KFixes [ */ clock_time->year += 100; /* *year%100, make tm_year */ /* *(do we need this?) */ if ( clock_time->year < YEAR_BREAK ) /* (failsafe if) */ clock_time->year += 1900; /* Y2KFixes ] */ /* * must have been a really bad year code - drop it */ if (clock_time->year < (YEAR_PIVOT + 1900) ) /* Y2KFixes */ { SETRTC(CVT_FAIL|CVT_BADDATE); return -1; } /* * sorry, slow section here - but it's not time critical anyway */ /* * calculate days since 1970 (watching leap years) */ t = julian0( clock_time->year ) - julian0( 1970 ); /* month */ if (clock_time->month <= 0 || clock_time->month > 12) { SETRTC(CVT_FAIL|CVT_BADDATE); return -1; /* bad month */ } /* adjust current leap year */#if 0 if (clock_time->month < 3 && days_per_year(clock_time->year) == 366) t--;#endif /* * collect days from months excluding the current one */ for (i = 1; i < clock_time->month; i++) { t += days_of_month[i]; } /* day */ if (clock_time->day < 1 || ((clock_time->month == 2 && days_per_year(clock_time->year) == 366) ? clock_time->day > 29 : clock_time->day > days_of_month[clock_time->month])) { SETRTC(CVT_FAIL|CVT_BADDATE); return -1; /* bad day */ } /* * collect days from date excluding the current one */ t += clock_time->day - 1; /* hour */ if (clock_time->hour < 0 || clock_time->hour >= 24) { SETRTC(CVT_FAIL|CVT_BADTIME); return -1; /* bad hour */ } /* * calculate hours from 1. 1. 1970 */ t = TIMES24(t) + clock_time->hour; /* min */ if (clock_time->minute < 0 || clock_time->minute > 59) { SETRTC(CVT_FAIL|CVT_BADTIME); return -1; /* bad min */ } /* * calculate minutes from 1. 1. 1970 */ t = TIMES60(t) + clock_time->minute; /* sec */ /* * calculate UTC in minutes */ t += clock_time->utcoffset; if (clock_time->second < 0 || clock_time->second > 60) /* allow for LEAPs */ { SETRTC(CVT_FAIL|CVT_BADTIME); return -1; /* bad sec */ } /* * calculate UTC in seconds - phew ! */ t = TIMES60(t) + clock_time->second; /* done */ return t;}/*----------------------------------------------------------------------- * cheap half baked 1/0 decision - for interactive operation only */static chartype( unsigned int c ){ c ^= 0xFF; return (c > 0xF);}/*----------------------------------------------------------------------- * week day representation */static const char *wday[8] ={ "??", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"};/*----------------------------------------------------------------------- * generate a string representation for a timeval */static char *pr_timeval( struct timeval *val ){ static char buf[20]; if (val->tv_sec == 0) sprintf(buf, "%c0.%06ld", (val->tv_usec < 0) ? '-' : '+', (long int)l_abs(val->tv_usec)); else sprintf(buf, "%ld.%06ld", (long int)val->tv_sec, (long int)l_abs(val->tv_usec)); return buf;}/*----------------------------------------------------------------------- * correct the current time by an offset by setting the time rigorously */static voidset_time( struct timeval *offset ){ struct timeval the_time; if (no_set) return; LPRINTF("set_time: %s ", pr_timeval(offset)); syslog(LOG_NOTICE, "setting time (offset %s)", pr_timeval(offset)); if (gettimeofday(&the_time, 0L) == -1) { perror("gettimeofday()"); } else { timeradd(&the_time, offset); if (settimeofday(&the_time, 0L) == -1) { perror("settimeofday()"); } }}/*----------------------------------------------------------------------- * slew the time by a given offset */static voidadj_time( long offset ){ struct timeval time_offset; if (no_set) return; time_offset.tv_sec = offset / 1000000; time_offset.tv_usec = offset % 1000000; LPRINTF("adj_time: %ld us ", (long int)offset); if (adjtime(&time_offset, 0L) == -1) perror("adjtime()");}/*----------------------------------------------------------------------- * read in a possibly previously written drift value */static voidread_drift( const char *drift_file ){ FILE *df; df = fopen(drift_file, "r"); if (df != NULL) { int idrift = 0, fdrift = 0; fscanf(df, "%4d.%03d", &idrift, &fdrift); fclose(df); LPRINTF("read_drift: %d.%03d ppm ", idrift, fdrift); accum_drift = idrift << USECSCALE; fdrift = (fdrift << USECSCALE) / 1000; accum_drift += fdrift & (1<<USECSCALE); LPRINTF("read_drift: drift_comp %ld ", (long int)accum_drift); }}/*----------------------------------------------------------------------- * write out the current drift value */static voidupdate_drift( const char *drift_file, long offset, time_t reftime ){ FILE *df; df = fopen(drift_file, "w"); if (df != NULL) { int idrift = R_SHIFT(accum_drift, USECSCALE); int fdrift = accum_drift & ((1<<USECSCALE)-1); LPRINTF("update_drift: drift_comp %ld ", (long int)accum_drift); fdrift = (fdrift * 1000) / (1<<USECSCALE); fprintf(df, "%4d.%03d %c%ld.%06ld %.24s\n", idrift, fdrift, (offset < 0) ? '-' : '+', (long int)(l_abs(offset) / 1000000), (long int)(l_abs(offset) % 1000000), asctime(localtime(&reftime))); fclose(df); LPRINTF("update_drift: %d.%03d ppm ", idrift, fdrift); }}/*----------------------------------------------------------------------- * process adjustments derived from the DCF77 observation * (controls clock PLL) */static voidadjust_clock( struct timeval *offset, const char *drift_file, time_t reftime ){ struct timeval toffset; register long usecoffset; int tmp; if (no_set) return; if (skip_adjust) { skip_adjust = 0; return; } toffset = *offset; toffset.tv_sec = l_abs(toffset.tv_sec); toffset.tv_usec = l_abs(toffset.tv_usec); if (timercmp(&toffset, &max_adj_offset, >)) { /* * hopeless - set the clock - and clear the timing */ set_time(offset); clock_adjust = 0; skip_adjust = 1; return; } usecoffset = offset->tv_sec * 1000000 + offset->tv_usec; clock_adjust = R_SHIFT(usecoffset, TIMECONSTANT); /* adjustment to make for next period */ tmp = 0; while (adjustments > (1 << tmp)) tmp++; adjustments = 0; if (tmp > FREQ_WEIGHT) tmp = FREQ_WEIGHT; accum_drift += R_SHIFT(usecoffset << USECSCALE, TIMECONSTANT+TIMECONSTANT+FREQ_WEIGHT-tmp); if (accum_drift > MAX_DRIFT) /* clamp into interval */ accum_drift = MAX_DRIFT; else if (accum_drift < -MAX_DRIFT) accum_drift = -MAX_DRIFT; update_drift(drift_file, usecoffset, reftime); LPRINTF("clock_adjust: %s, clock_adjust %ld, drift_comp %ld(%ld) ", pr_timeval(offset),(long int) R_SHIFT(clock_adjust, USECSCALE), (long int)R_SHIFT(accum_drift, USECSCALE), (long int)accum_drift);}/*----------------------------------------------------------------------- * adjust the clock by a small mount to simulate frequency correction */static voidperiodic_adjust( void ){ register long adjustment; adjustments++; adjustment = R_SHIFT(clock_adjust, PHASE_WEIGHT); clock_adjust -= adjustment; adjustment += R_SHIFT(accum_drift, USECSCALE+ADJINTERVAL); adj_time(adjustment);}/*----------------------------------------------------------------------- * control synchronisation status (warnings) and do periodic adjusts * (frequency control simulation) */static voidtick( int signum ){ static unsigned long last_notice = 0;#if !defined(HAVE_SIGACTION) && !defined(HAVE_SIGVEC) (void)signal(SIGALRM, tick);#endif periodic_adjust(); ticks += 1<<ADJINTERVAL; if ((ticks - last_sync) > MAX_UNSYNC) { /* * not getting time for a while */ if (sync_state == SYNC) { /* * completely lost information */ sync_state = NO_SYNC; syslog(LOG_INFO, "DCF77 reception lost (timeout)"); last_notice = ticks; } else /* * in NO_SYNC state - look whether its time to speak up again */ if ((ticks - last_notice) > NOTICE_INTERVAL) { syslog(LOG_NOTICE, "still not synchronized to DCF77 - check receiver/signal"); last_notice = ticks; } }#ifndef ITIMER_REAL (void) alarm(1<<ADJINTERVAL);#endif}/*----------------------------------------------------------------------- * break association from terminal to avoid catching terminal * or process group related signals (-> daemon operation) */static voiddetach( void ){# ifdef HAVE_DAEMON daemon(0, 0);# else /* not HAVE_DAEMON */ if (fork()) exit(0); { u_long s; int max_fd;#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX) max_fd = sysconf(_SC_OPEN_MAX);#else /* HAVE_SYSCONF && _SC_OPEN_MAX */ max_fd = getdtablesize();#endif /* HAVE_SYSCONF && _SC_OPEN_MAX */ for (s = 0; s < max_fd; s++) (void) close((int)s); (void) open("/", 0); (void) dup2(0, 1); (void) dup2(0, 2);#ifdef SYS_DOMAINOS { uid_$t puid; status_$t st; proc2_$who_am_i(&puid); proc2_$make_server(&puid, &st); }#endif /* SYS_DOMAINOS */#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)# ifdef HAVE_SETSID if (setsid() == (pid_t)-1) syslog(LOG_ERR, "dcfd: setsid(): %m");# else if (setpgid(0, 0) == -1) syslog(LOG_ERR, "dcfd: setpgid(): %m");# endif#else /* HAVE_SETPGID || HAVE_SETSID */ { int fid; fid = open("/dev/tty", 2); if (fid >= 0) { (void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0); (void) close(fid); }# ifdef HAVE_SETPGRP_0 (void) setpgrp();# else /* HAVE_SETPGRP_0 */ (void) setpgrp(0, getpid());# endif /* HAVE_SETPGRP_0 */ }#endif /* HAVE_SETPGID || HAVE_SETSID */ }#endif /* not HAVE_DAEMON */}/*----------------------------------------------------------------------- * list possible arguments and options */static voidusage( char *program ){ fprintf(stderr, "usage: %s [-n] [-f] [-l] [-t] [-i] [-o] [-d <drift_file>] [-D <input delay>] <device>\n", program); fprintf(stderr, "\t-n do not change time\n"); fprintf(stderr, "\t-i interactive\n"); fprintf(stderr, "\t-t trace (print all datagrams)\n"); fprintf(stderr, "\t-f print all databits (includes PTB private data)\n"); fprintf(stderr, "\t-l print loop filter debug information\n"); fprintf(stderr, "\t-o print offet average for current minute\n"); fprintf(stderr, "\t-Y make internal Y2K checks then exit\n"); /* Y2KFixes */ fprintf(stderr, "\t-d <drift_file> specify alternate drift file\n"); fprintf(stderr, "\t-D <input delay>specify delay from input edge to processing in micro seconds\n");}/*----------------------------------------------------------------------- * check_y2k() - internal check of Y2K logic * (a lot of this logic lifted from ../ntpd/check_y2k.c) */static intcheck_y2k( void ){ int year; /* current working year */ int year0 = 1900; /* sarting year for NTP time */ int yearend; /* ending year we test for NTP time. * 32-bit systems: through 2036, the **year in which NTP time overflows. * 64-bit systems: a reasonable upper **limit (well, maybe somewhat beyond **reasonable, but well before the **max time, by which time the earth **will be dead.) */ time_t Time; struct tm LocalTime; int Fatals, Warnings;#define Error(year) if ( (year)>=2036 && LocalTime.tm_year < 110 ) \ Warnings++; else Fatals++ Fatals = Warnings = 0; Time = time( (time_t *)NULL ); LocalTime = *localtime( &Time ); year = ( sizeof( u_long ) > 4 ) /* save max span using year as temp */ ? ( 400 * 3 ) /* three greater gregorian cycles */ : ((int)(0x7FFFFFFF / 365.242 / 24/60/60)* 2 ); /*32-bit limit*/ /* NOTE: will automacially expand test years on
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -