📄 dcfd.c
字号:
/* * /src/NTP/REPOSITORY/ntp4-dev/parseutil/dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A * * dcfd.c,v 4.18 2005/10/07 22:08:18 kardel RELEASE_20051008_A * * DCF77 100/200ms pulse synchronisation daemon program (via 50Baud serial line) * * Features: * DCF77 decoding * simple NTP loopfilter logic for local clock * interactive display for debugging * * Lacks: * Leap second handling (at that level you should switch to NTP Version 4 - really!) * * Copyright (c) 1995-2005 by Frank Kardel <kardel <AT> ntp.org> * Copyright (c) 1989-1994 by Frank Kardel, Friedrich-Alexander Universit鋞 Erlangen-N黵nberg, Germany * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <sys/ioctl.h>#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <sys/types.h>#include <sys/time.h>#include <signal.h>#include <syslog.h>#include <time.h>/* * NTP compilation environment */#include "ntp_stdlib.h"#include "ntpd.h" /* indirectly include ntp.h to get YEAR_PIVOT Y2KFixes *//* * select which terminal handling to use (currently only SysV variants) */#if defined(HAVE_TERMIOS_H) || defined(STREAM)#include <termios.h>#define TTY_GETATTR(_FD_, _ARG_) tcgetattr((_FD_), (_ARG_))#define TTY_SETATTR(_FD_, _ARG_) tcsetattr((_FD_), TCSANOW, (_ARG_))#else /* not HAVE_TERMIOS_H || STREAM */# if defined(HAVE_TERMIO_H) || defined(HAVE_SYSV_TTYS)# include <termio.h># define TTY_GETATTR(_FD_, _ARG_) ioctl((_FD_), TCGETA, (_ARG_))# define TTY_SETATTR(_FD_, _ARG_) ioctl((_FD_), TCSETAW, (_ARG_))# endif/* HAVE_TERMIO_H || HAVE_SYSV_TTYS */#endif /* not HAVE_TERMIOS_H || STREAM */#ifndef TTY_GETATTR#include "Bletch: MUST DEFINE ONE OF 'HAVE_TERMIOS_H' or 'HAVE_TERMIO_H'"#endif#ifndef days_per_year#define days_per_year(_x_) (((_x_) % 4) ? 365 : (((_x_) % 400) ? 365 : 366))#endif#define timernormalize(_a_) \ if ((_a_)->tv_usec >= 1000000) \ { \ (_a_)->tv_sec += (_a_)->tv_usec / 1000000; \ (_a_)->tv_usec = (_a_)->tv_usec % 1000000; \ } \ if ((_a_)->tv_usec < 0) \ { \ (_a_)->tv_sec -= 1 + (-(_a_)->tv_usec / 1000000); \ (_a_)->tv_usec = 999999 - (-(_a_)->tv_usec - 1); \ }#ifdef timeradd#undef timeradd#endif#define timeradd(_a_, _b_) \ (_a_)->tv_sec += (_b_)->tv_sec; \ (_a_)->tv_usec += (_b_)->tv_usec; \ timernormalize((_a_))#ifdef timersub#undef timersub#endif#define timersub(_a_, _b_) \ (_a_)->tv_sec -= (_b_)->tv_sec; \ (_a_)->tv_usec -= (_b_)->tv_usec; \ timernormalize((_a_))/* * debug macros */#define PRINTF if (interactive) printf#define LPRINTF if (interactive && loop_filter_debug) printf#ifdef DEBUG#define dprintf(_x_) LPRINTF _x_#else#define dprintf(_x_)#endif#ifdef DECL_ERRNO extern int errno;#endifstatic char *revision = "4.18";/* * display received data (avoids also detaching from tty) */static int interactive = 0;/* * display loopfilter (clock control) variables */static int loop_filter_debug = 0;/* * do not set/adjust system time */static int no_set = 0;/* * time that passes between start of DCF impulse and time stamping (fine * adjustment) in microseconds (receiver/OS dependent) */#define DEFAULT_DELAY 230000 /* rough estimate *//* * The two states we can be in - eithe we receive nothing * usable or we have the correct time */#define NO_SYNC 0x01#define SYNC 0x02static int sync_state = NO_SYNC;static time_t last_sync;static unsigned long ticks = 0;static char pat[] = "-\\|/";#define LINES (24-2) /* error lines after which the two headlines are repeated */#define MAX_UNSYNC (10*60) /* allow synchronisation loss for 10 minutes */#define NOTICE_INTERVAL (20*60) /* mention missing synchronisation every 20 minutes *//* * clock adjustment PLL - see NTP protocol spec (RFC1305) for details */#define USECSCALE 10#define TIMECONSTANT 2#define ADJINTERVAL 0#define FREQ_WEIGHT 18#define PHASE_WEIGHT 7#define MAX_DRIFT 0x3FFFFFFF#define R_SHIFT(_X_, _Y_) (((_X_) < 0) ? -(-(_X_) >> (_Y_)) : ((_X_) >> (_Y_)))static struct timeval max_adj_offset = { 0, 128000 };static long clock_adjust = 0; /* current adjustment value (usec * 2^USECSCALE) */static long accum_drift = 0; /* accumulated drift value (usec / ADJINTERVAL) */static long adjustments = 0;static char skip_adjust = 1; /* discard first adjustment (bad samples) *//* * DCF77 state flags */#define DCFB_ANNOUNCE 0x0001 /* switch time zone warning (DST switch) */#define DCFB_DST 0x0002 /* DST in effect */#define DCFB_LEAP 0x0004 /* LEAP warning (1 hour prior to occurrence) */#define DCFB_ALTERNATE 0x0008 /* alternate antenna used */struct clocktime /* clock time broken up from time code */{ long wday; /* Day of week: 1: Monday - 7: Sunday */ long day; long month; long year; long hour; long minute; long second; long usecond; long utcoffset; /* in minutes */ long flags; /* current clock status (DCF77 state flags) */};typedef struct clocktime clocktime_t;/* * (usually) quick constant multiplications */#define TIMES10(_X_) (((_X_) << 3) + ((_X_) << 1)) /* *8 + *2 */#define TIMES24(_X_) (((_X_) << 4) + ((_X_) << 3)) /* *16 + *8 */#define TIMES60(_X_) ((((_X_) << 4) - (_X_)) << 2) /* *(16 - 1) *4 *//* * generic l_abs() function */#define l_abs(_x_) (((_x_) < 0) ? -(_x_) : (_x_))/* * conversion related return/error codes */#define CVT_MASK 0x0000000F /* conversion exit code */#define CVT_NONE 0x00000001 /* format not applicable */#define CVT_FAIL 0x00000002 /* conversion failed - error code returned */#define CVT_OK 0x00000004 /* conversion succeeded */#define CVT_BADFMT 0x00000010 /* general format error - (unparsable) */#define CVT_BADDATE 0x00000020 /* invalid date */#define CVT_BADTIME 0x00000040 /* invalid time *//* * DCF77 raw time code * * From "Zur Zeit", Physikalisch-Technische Bundesanstalt (PTB), Braunschweig * und Berlin, Maerz 1989 * * Timecode transmission: * AM: * time marks are send every second except for the second before the * next minute mark * time marks consist of a reduction of transmitter power to 25% * of the nominal level * the falling edge is the time indication (on time) * time marks of a 100ms duration constitute a logical 0 * time marks of a 200ms duration constitute a logical 1 * FM: * see the spec. (basically a (non-)inverted psuedo random phase shift) * * Encoding: * Second Contents * 0 - 10 AM: free, FM: 0 * 11 - 14 free * 15 R - alternate antenna * 16 A1 - expect zone change (1 hour before) * 17 - 18 Z1,Z2 - time zone * 0 0 illegal * 0 1 MEZ (MET) * 1 0 MESZ (MED, MET DST) * 1 1 illegal * 19 A2 - expect leap insertion/deletion (1 hour before) * 20 S - start of time code (1) * 21 - 24 M1 - BCD (lsb first) Minutes * 25 - 27 M10 - BCD (lsb first) 10 Minutes * 28 P1 - Minute Parity (even) * 29 - 32 H1 - BCD (lsb first) Hours * 33 - 34 H10 - BCD (lsb first) 10 Hours * 35 P2 - Hour Parity (even) * 36 - 39 D1 - BCD (lsb first) Days * 40 - 41 D10 - BCD (lsb first) 10 Days * 42 - 44 DW - BCD (lsb first) day of week (1: Monday -> 7: Sunday) * 45 - 49 MO - BCD (lsb first) Month * 50 MO0 - 10 Months * 51 - 53 Y1 - BCD (lsb first) Years * 54 - 57 Y10 - BCD (lsb first) 10 Years * 58 P3 - Date Parity (even) * 59 - usually missing (minute indication), except for leap insertion *//*----------------------------------------------------------------------- * conversion table to map DCF77 bit stream into data fields. * Encoding: * Each field of the DCF77 code is described with two adjacent entries in * this table. The first entry specifies the offset into the DCF77 data stream * while the length is given as the difference between the start index and * the start index of the following field. */static struct rawdcfcode { char offset; /* start bit */} rawdcfcode[] ={ { 0 }, { 15 }, { 16 }, { 17 }, { 19 }, { 20 }, { 21 }, { 25 }, { 28 }, { 29 }, { 33 }, { 35 }, { 36 }, { 40 }, { 42 }, { 45 }, { 49 }, { 50 }, { 54 }, { 58 }, { 59 }};/*----------------------------------------------------------------------- * symbolic names for the fields of DCF77 describes in "rawdcfcode". * see comment above for the structure of the DCF77 data */#define DCF_M 0#define DCF_R 1#define DCF_A1 2#define DCF_Z 3#define DCF_A2 4#define DCF_S 5#define DCF_M1 6#define DCF_M10 7#define DCF_P1 8#define DCF_H1 9#define DCF_H10 10#define DCF_P2 11#define DCF_D1 12#define DCF_D10 13#define DCF_DW 14#define DCF_MO 15#define DCF_MO0 16#define DCF_Y1 17#define DCF_Y10 18#define DCF_P3 19/*----------------------------------------------------------------------- * parity field table (same encoding as rawdcfcode) * This table describes the sections of the DCF77 code that are * parity protected */static struct partab{ char offset; /* start bit of parity field */} partab[] ={ { 21 }, { 29 }, { 36 }, { 59 }};/*----------------------------------------------------------------------- * offsets for parity field descriptions */#define DCF_P_P1 0#define DCF_P_P2 1#define DCF_P_P3 2/*----------------------------------------------------------------------- * legal values for time zone information */#define DCF_Z_MET 0x2#define DCF_Z_MED 0x1/*----------------------------------------------------------------------- * symbolic representation if the DCF77 data stream */static struct dcfparam{ unsigned char onebits[60]; unsigned char zerobits[60];} dcfparam = { "###############RADMLS1248124P124812P1248121241248112481248P", /* 'ONE' representation */ "--------------------s-------p------p----------------------p" /* 'ZERO' representation */};/*----------------------------------------------------------------------- * extract a bitfield from DCF77 datastream * All numeric fields are LSB first. * buf holds a pointer to a DCF77 data buffer in symbolic * representation * idx holds the index to the field description in rawdcfcode */static unsigned longext_bf( register unsigned char *buf, register int idx ){ register unsigned long sum = 0; register int i, first; first = rawdcfcode[idx].offset; for (i = rawdcfcode[idx+1].offset - 1; i >= first; i--) { sum <<= 1; sum |= (buf[i] != dcfparam.zerobits[i]); } return sum;}/*----------------------------------------------------------------------- * check even parity integrity for a bitfield * * buf holds a pointer to a DCF77 data buffer in symbolic * representation * idx holds the index to the field description in partab */static unsignedpcheck( register unsigned char *buf, register int idx ){ register int i,last; register unsigned psum = 1; last = partab[idx+1].offset; for (i = partab[idx].offset; i < last; i++) psum ^= (buf[i] != dcfparam.zerobits[i]); return psum;}/*----------------------------------------------------------------------- * convert a DCF77 data buffer into wall clock time + flags * * buffer holds a pointer to a DCF77 data buffer in symbolic * representation * size describes the length of DCF77 information in bits (represented * as chars in symbolic notation * clock points to a wall clock time description of the DCF77 data (result) */static unsigned longconvert_rawdcf( unsigned char *buffer, int size, clocktime_t *clock_time ){ if (size < 57) { PRINTF("%-30s", "*** INCOMPLETE"); return CVT_NONE; } /* * check Start and Parity bits */ if ((ext_bf(buffer, DCF_S) == 1) && pcheck(buffer, DCF_P_P1) && pcheck(buffer, DCF_P_P2) && pcheck(buffer, DCF_P_P3)) { /* * buffer OK - extract all fields and build wall clock time from them */ clock_time->flags = 0; clock_time->usecond= 0; clock_time->second = 0; clock_time->minute = ext_bf(buffer, DCF_M10); clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1); clock_time->hour = ext_bf(buffer, DCF_H10); clock_time->hour = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1); clock_time->day = ext_bf(buffer, DCF_D10); clock_time->day = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1); clock_time->month = ext_bf(buffer, DCF_MO0); clock_time->month = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO); clock_time->year = ext_bf(buffer, DCF_Y10); clock_time->year = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1); clock_time->wday = ext_bf(buffer, DCF_DW); /* * determine offset to UTC by examining the time zone */ switch (ext_bf(buffer, DCF_Z)) { case DCF_Z_MET: clock_time->utcoffset = -60; break; case DCF_Z_MED: clock_time->flags |= DCFB_DST; clock_time->utcoffset = -120; break; default: PRINTF("%-30s", "*** BAD TIME ZONE"); return CVT_FAIL|CVT_BADFMT; } /* * extract various warnings from DCF77 */ if (ext_bf(buffer, DCF_A1)) clock_time->flags |= DCFB_ANNOUNCE; if (ext_bf(buffer, DCF_A2)) clock_time->flags |= DCFB_LEAP; if (ext_bf(buffer, DCF_R)) clock_time->flags |= DCFB_ALTERNATE; return CVT_OK; } else { /* * bad format - not for us */ PRINTF("%-30s", "*** BAD FORMAT (invalid/parity)"); return CVT_FAIL|CVT_BADFMT; }}/*----------------------------------------------------------------------- * raw dcf input routine - fix up 50 baud * characters for 1/0 decision */static unsigned longcvt_rawdcf( unsigned char *buffer, int size, clocktime_t *clock_time ){ register unsigned char *s = buffer; register unsigned char *e = buffer + size; register unsigned char *b = dcfparam.onebits; register unsigned char *c = dcfparam.zerobits; register unsigned rtc = CVT_NONE; register unsigned int i, lowmax, highmax, cutoff, span;#define BITS 9 unsigned char histbuf[BITS]; /* * the input buffer contains characters with runs of consecutive * bits set. These set bits are an indication of the DCF77 pulse * length. We assume that we receive the pulse at 50 Baud. Thus * a 100ms pulse would generate a 4 bit train (20ms per bit and * start bit) * a 200ms pulse would create all zeroes (and probably a frame error) * * The basic idea is that on corret reception we must have two * maxima in the pulse length distribution histogram. (one for * the zero representing pulses and one for the one representing * pulses) * There will always be ones in the datastream, thus we have to see * two maxima. * The best point to cut for a 1/0 decision is the minimum between those * between the maxima. The following code tries to find this cutoff point. */ /* * clear histogram buffer */ for (i = 0; i < BITS; i++) { histbuf[i] = 0; } cutoff = 0; lowmax = 0; /* * convert sequences of set bits into bits counts updating * the histogram alongway */ while (s < e) { register unsigned int ch = *s ^ 0xFF; /* * check integrity and update histogramm */ if (!((ch+1) & ch) || !*s) { /* * character ok */ for (i = 0; ch; i++) { ch >>= 1; } *s = i; histbuf[i]++; cutoff += i; lowmax++; } else { /* * invalid character (no consecutive bit sequence) */ dprintf(("parse: cvt_rawdcf: character check for 0x%x@%d FAILED\n", *s, s - buffer)); *s = (unsigned char)~0; rtc = CVT_FAIL|CVT_BADFMT; } s++; } /* * first cutoff estimate (average bit count - must be between both * maxima) */ if (lowmax) { cutoff /= lowmax; } else { cutoff = 4; /* doesn't really matter - it'll fail anyway, but gives error output */ } dprintf(("parse: cvt_rawdcf: average bit count: %d\n", cutoff)); lowmax = 0; /* weighted sum */ highmax = 0; /* bitcount */ /* * collect weighted sum of lower bits (left of initial guess) */ dprintf(("parse: cvt_rawdcf: histogram:")); for (i = 0; i <= cutoff; i++) { lowmax += histbuf[i] * i; highmax += histbuf[i]; dprintf((" %d", histbuf[i])); } dprintf((" <M>")); /* * round up */ lowmax += highmax / 2; /* * calculate lower bit maximum (weighted sum / bit count) * * avoid divide by zero
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -