diff options
author | delphij <delphij@FreeBSD.org> | 2015-07-15 19:21:26 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2015-07-15 19:21:26 +0000 |
commit | 2a25cee78ab1d37e7d2bc40ae675646974d99f56 (patch) | |
tree | b0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/ntpd/refclock_wwv.c | |
parent | a0741a75537b2e0514472ac3b28afc55a7846c30 (diff) | |
download | FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.zip FreeBSD-src-2a25cee78ab1d37e7d2bc40ae675646974d99f56.tar.gz |
MFC r280849,280915-280916,281015-281016,282097,282408,282415,283542,
284864,285169-285170,285435:
ntp 4.2.8p3.
Relnotes: yes
Approved by: re (?)
Diffstat (limited to 'contrib/ntp/ntpd/refclock_wwv.c')
-rw-r--r-- | contrib/ntp/ntpd/refclock_wwv.c | 456 |
1 files changed, 228 insertions, 228 deletions
diff --git a/contrib/ntp/ntpd/refclock_wwv.c b/contrib/ntp/ntpd/refclock_wwv.c index b7e0d9a..79c0afd 100644 --- a/contrib/ntp/ntpd/refclock_wwv.c +++ b/contrib/ntp/ntpd/refclock_wwv.c @@ -39,11 +39,12 @@ * tuned automatically using this program as propagation conditions * change throughout the weasons, both day and night. * - * The driver receives, demodulates and decodes the radio signals when - * connected to the audio codec of a workstation running Solaris, SunOS - * FreeBSD or Linux, and with a little help, other workstations with - * similar codecs or sound cards. In this implementation, only one audio - * driver and codec can be supported on a single machine. + * The driver requires an audio codec or sound card with sampling rate 8 + * kHz and mu-law companding. This is the same standard as used by the + * telephone industry and is supported by most hardware and operating + * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this + * implementation, only one audio driver and codec can be supported on a + * single machine. * * The demodulation and decoding algorithms used in this driver are * based on those developed for the TAPR DSP93 development board and the @@ -62,12 +63,16 @@ * * Fudge factors * - * Fudge flag4 causes the dubugging output described above to be + * Fudge flag4 causes the debugging output described above to be * recorded in the clockstats file. Fudge flag2 selects the audio input * port, where 0 is the mike port (default) and 1 is the line-in port. * It does not seem useful to select the compact disc player port. Fudge * flag3 enables audio monitoring of the input signal. For this purpose, * the monitor gain is set to a default value. + * + * CEVNT_BADTIME invalid date or time + * CEVNT_PROP propagation failure - no stations heard + * CEVNT_TIMEOUT timeout (see newgame() below) */ /* * General definitions. These ordinarily do not need to be changed. @@ -76,8 +81,8 @@ #define AUDIO_BUFSIZ 320 /* audio buffer size (50 ms) */ #define PRECISION (-10) /* precision assumed (about 1 ms) */ #define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */ -#define SECOND 8000 /* second epoch (sample rate) (Hz) */ -#define MINUTE (SECOND * 60) /* minute epoch */ +#define WWV_SEC 8000 /* second epoch (sample rate) (Hz) */ +#define WWV_MIN (WWV_SEC * 60) /* minute epoch */ #define OFFSET 128 /* companded sample offset */ #define SIZE 256 /* decompanding table size */ #define MAXAMP 6000. /* max signal level reference */ @@ -92,6 +97,7 @@ #define TCKSIZ (TCKCYC * MS) /* tick filter size */ #define NCHAN 5 /* number of radio channels */ #define AUDIO_PHI 5e-6 /* dispersion growth factor */ +#define TBUF 128 /* max monitor line length */ /* * Tunable parameters. The DGAIN parameter can be changed to fit the @@ -102,12 +108,10 @@ * radio is not tunable, the DCHAN parameter can be changed to fit the * expected best propagation frequency: higher if further from the * transmitter, lower if nearer. The compromise value works for the US - * right coast. The FREQ_OFFSET parameter can be used as a frequency - * vernier to correct codec requency if greater than MAXFREQ. + * right coast. */ #define DCHAN 3 /* default radio channel (15 Mhz) */ #define DGAIN 5. /* subcarrier gain */ -#define FREQ_OFFSET 0. /* codec frequency correction (PPM) */ /* * General purpose status bits (status) @@ -133,6 +137,7 @@ #define FGATE 0x0010 /* frequency gate */ #define DGATE 0x0020 /* data pulse amplitude error */ #define BGATE 0x0040 /* data pulse width error */ +#define METRIC 0x0080 /* one or more stations heard */ #define LEPSEC 0x1000 /* leap minute */ /* @@ -150,10 +155,10 @@ * These bits indicate various alarm conditions, which are decoded to * form the quality character included in the timecode. */ -#define CMPERR 1 /* digit or misc bit compare error */ -#define LOWERR 2 /* low bit or digit amplitude or SNR */ -#define NINERR 4 /* less than nine digits in minute */ -#define SYNERR 8 /* not tracking second sync */ +#define CMPERR 0x1 /* digit or misc bit compare error */ +#define LOWERR 0x2 /* low bit or digit amplitude or SNR */ +#define NINERR 0x4 /* less than nine digits in minute */ +#define SYNERR 0x8 /* not tracking second sync */ /* * Watchcat timeouts (watch) @@ -196,10 +201,10 @@ * Tone frequency definitions. The increments are for 4.5-deg sine * table. */ -#define MS (SECOND / 1000) /* samples per millisecond */ -#define IN100 ((100 * 80) / SECOND) /* 100 Hz increment */ -#define IN1000 ((1000 * 80) / SECOND) /* 1000 Hz increment */ -#define IN1200 ((1200 * 80) / SECOND) /* 1200 Hz increment */ +#define MS (WWV_SEC / 1000) /* samples per millisecond */ +#define IN100 ((100 * 80) / WWV_SEC) /* 100 Hz increment */ +#define IN1000 ((1000 * 80) / WWV_SEC) /* 1000 Hz increment */ +#define IN1200 ((1200 * 80) / WWV_SEC) /* 1200 Hz increment */ /* * Acquisition and tracking time constants @@ -225,15 +230,21 @@ #define SECWAR 0x40 /* 3 leap second warning */ /* - * The on-time synchronization point for the driver is the second epoch - * sync pulse produced by the FIR matched filters. As the 5-ms delay of - * these filters is compensated, the program delay is 1.1 ms due to the - * 600-Hz IIR bandpass filter. The measured receiver delay is 4.7 ms and - * the codec delay less than 0.2 ms. The additional propagation delay - * specific to each receiver location can be programmed in the fudge - * time1 and time2 values for WWV and WWVH, respectively. + * The on-time synchronization point is the positive-going zero crossing + * of the first cycle of the 5-ms second pulse. The IIR baseband filter + * phase delay is 0.91 ms, while the receiver delay is approximately 4.7 + * ms at 1000 Hz. The fudge value -0.45 ms due to the codec and other + * causes was determined by calibrating to a PPS signal from a GPS + * receiver. The additional propagation delay specific to each receiver + * location can be programmed in the fudge time1 and time2 values for + * WWV and WWVH, respectively. + * + * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are + * generally within .02 ms short-term with .02 ms jitter. The long-term + * offsets vary up to 0.3 ms due to ionosperhic layer height variations. + * The processor load due to the driver is 5.8 percent. */ -#define PDELAY (.0011 + .0047 + .0002) /* net system delay (s) */ +#define PDELAY ((.91 + 4.7 - 0.45) / 1000) /* system delay (s) */ /* * Table of sine values at 4.5-degree increments. This is used by the @@ -365,7 +376,7 @@ struct progx progx[] = { }; /* - * BCD coefficients for maximum likelihood digit decode + * BCD coefficients for maximum-likelihood digit decode */ #define P15 1. /* max positive number */ #define N15 -1. /* max negative number */ @@ -447,14 +458,13 @@ char dstcod[] = { /* * The decoding matrix consists of nine row vectors, one for each digit * of the timecode. The digits are stored from least to most significant - * order. The maximum likelihood timecode is formed from the digits - * corresponding to the maximum likelihood values reading in the + * order. The maximum-likelihood timecode is formed from the digits + * corresponding to the maximum-likelihood values reading in the * opposite order: yy ddd hh:mm. */ struct decvec { int radix; /* radix (3, 4, 6, 10) */ int digit; /* current clock digit */ - int mldigit; /* maximum likelihood digit */ int count; /* match count */ double digprb; /* max digit probability */ double digsnr; /* likelihood function (dB) */ @@ -503,6 +513,7 @@ struct wwvunit { l_fp tick; /* audio sample increment */ double phase, freq; /* logical clock phase and frequency */ double monitor; /* audio monitor point */ + double pdelay; /* propagation delay (s) */ #ifdef ICOM int fd_icom; /* ICOM file descriptor */ #endif /* ICOM */ @@ -513,7 +524,7 @@ struct wwvunit { * Audio codec variables */ double comp[SIZE]; /* decompanding table */ - int port; /* codec port */ + int port; /* codec port */ int gain; /* codec gain */ int mongain; /* codec monitor gain */ int clipcnt; /* sample clipped count */ @@ -568,32 +579,32 @@ struct wwvunit { /* * Function prototypes */ -static int wwv_start P((int, struct peer *)); -static void wwv_shutdown P((int, struct peer *)); -static void wwv_receive P((struct recvbuf *)); -static void wwv_poll P((int, struct peer *)); +static int wwv_start (int, struct peer *); +static void wwv_shutdown (int, struct peer *); +static void wwv_receive (struct recvbuf *); +static void wwv_poll (int, struct peer *); /* * More function prototypes */ -static void wwv_epoch P((struct peer *)); -static void wwv_rf P((struct peer *, double)); -static void wwv_endpoc P((struct peer *, int)); -static void wwv_rsec P((struct peer *, double)); -static void wwv_qrz P((struct peer *, struct sync *, int)); -static void wwv_corr4 P((struct peer *, struct decvec *, - double [], double [][4])); -static void wwv_gain P((struct peer *)); -static void wwv_tsec P((struct peer *)); -static int timecode P((struct wwvunit *, char *)); -static double wwv_snr P((double, double)); -static int carry P((struct decvec *)); -static int wwv_newchan P((struct peer *)); -static void wwv_newgame P((struct peer *)); -static double wwv_metric P((struct sync *)); -static void wwv_clock P((struct peer *)); +static void wwv_epoch (struct peer *); +static void wwv_rf (struct peer *, double); +static void wwv_endpoc (struct peer *, int); +static void wwv_rsec (struct peer *, double); +static void wwv_qrz (struct peer *, struct sync *, int); +static void wwv_corr4 (struct peer *, struct decvec *, + double [], double [][4]); +static void wwv_gain (struct peer *); +static void wwv_tsec (struct peer *); +static int timecode (struct wwvunit *, char *, size_t); +static double wwv_snr (double, double); +static int carry (struct decvec *); +static int wwv_newchan (struct peer *); +static void wwv_newgame (struct peer *); +static double wwv_metric (struct sync *); +static void wwv_clock (struct peer *); #ifdef ICOM -static int wwv_qsy P((struct peer *, int)); +static int wwv_qsy (struct peer *, int); #endif /* ICOM */ static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */ @@ -648,15 +659,10 @@ wwv_start( /* * Allocate and initialize unit structure */ - if (!(up = (struct wwvunit *)emalloc(sizeof(struct wwvunit)))) { - close(fd); - return (0); - } - memset(up, 0, sizeof(struct wwvunit)); + up = emalloc_zero(sizeof(*up)); pp = peer->procptr; - pp->unitptr = (caddr_t)up; pp->io.clock_recv = wwv_receive; - pp->io.srcclock = (caddr_t)peer; + pp->io.srcclock = peer; pp->io.datalen = 0; pp->io.fd = fd; if (!io_addclock(&pp->io)) { @@ -664,6 +670,7 @@ wwv_start( free(up); return (0); } + pp->unitptr = up; /* * Initialize miscellaneous variables @@ -682,10 +689,10 @@ wwv_start( for (i = 3; i < OFFSET; i++) { up->comp[i] = up->comp[i - 1] + step; up->comp[OFFSET + i] = -up->comp[i]; - if (i % 16 == 0) - step *= 2.; + if (i % 16 == 0) + step *= 2.; } - DTOLFP(1. / SECOND, &up->tick); + DTOLFP(1. / WWV_SEC, &up->tick); /* * Initialize the decoding matrix with the radix for each digit @@ -705,7 +712,9 @@ wwv_start( /* * Initialize autotune if available. Note that the ICOM select * code must be less than 128, so the high order bit can be used - * to select the line speed 0 (9600 bps) or 1 (1200 bps). + * to select the line speed 0 (9600 bps) or 1 (1200 bps). Note + * we don't complain if the ICOM device is not there; but, if it + * is, the radio better be working. */ temp = 0; #ifdef DEBUG @@ -719,25 +728,14 @@ wwv_start( else up->fd_icom = icom_init("/dev/icom", B9600, temp); - if (up->fd_icom < 0) { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: %m"); - up->errflg = CEVNT_FAULT; - } } if (up->fd_icom > 0) { if (wwv_qsy(peer, DCHAN) != 0) { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: radio not found"); - up->errflg = CEVNT_FAULT; + msyslog(LOG_NOTICE, "icom: radio not found"); close(up->fd_icom); up->fd_icom = 0; } else { - NLOG(NLOG_SYNCEVENT | NLOG_SYSEVENT) - msyslog(LOG_NOTICE, - "icom: autotune enabled"); + msyslog(LOG_NOTICE, "icom: autotune enabled"); } } #endif /* ICOM */ @@ -763,7 +761,7 @@ wwv_shutdown( struct wwvunit *up; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; if (up == NULL) return; @@ -801,15 +799,15 @@ wwv_receive( int bufcnt; /* buffer counter */ l_fp ltemp; - peer = (struct peer *)rbufp->recv_srcclock; + peer = rbufp->recv_peer; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Main loop - read until there ain't no more. Note codec * samples are bit-inverted. */ - DTOLFP((double)rbufp->recv_length / SECOND, <emp); + DTOLFP((double)rbufp->recv_length / WWV_SEC, <emp); L_SUB(&rbufp->recv_time, <emp); up->timestamp = rbufp->recv_time; dpt = rbufp->recv_buffer; @@ -837,8 +835,7 @@ wwv_receive( * per second, which results in a frequency change of * 125 PPM. */ - up->phase += up->freq / SECOND; - up->phase += FREQ_OFFSET / 1e6; + up->phase += (up->freq + clock_codec) / WWV_SEC; if (up->phase >= .5) { up->phase -= 1.; } else if (up->phase < -.5) { @@ -883,9 +880,7 @@ wwv_poll( struct wwvunit *up; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; - if (pp->coderecv == pp->codeproc) - up->errflg = CEVNT_TIMEOUT; + up = pp->unitptr; if (up->errflg) refclock_report(peer, up->errflg); up->errflg = 0; @@ -969,18 +964,17 @@ wwv_rf( static double hsiamp; /* wwvh I tick amplitude */ static double hsqamp; /* wwvh Q tick amplitude */ - static double epobuf[SECOND]; /* second sync comb filter */ + static double epobuf[WWV_SEC]; /* second sync comb filter */ static double epomax, nxtmax; /* second sync amplitude buffer */ static int epopos; /* epoch second sync position buffer */ static int iniflg; /* initialization flag */ - int pdelay; /* propagation delay (samples) */ int epoch; /* comb filter index */ double dtemp; int i; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; if (!iniflg) { iniflg = 1; @@ -1012,7 +1006,7 @@ wwv_rf( * compensate for the radio audio response at 100 Hz. * * Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB - * passband ripple, -50 dB stopband ripple. + * passband ripple, -50 dB stopband ripple, phase delay 0.97 ms. */ data = (lpf[4] = lpf[3]) * 8.360961e-01; data += (lpf[3] = lpf[2]) * -3.481740e+00; @@ -1056,7 +1050,7 @@ wwv_rf( * tones and most of the noise and voice modulation components. * * Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB - * passband ripple, -50 dB stopband ripple. + * passband ripple, -50 dB stopband ripple, phase delay 0.91 ms. */ syncx = (bpf[8] = bpf[7]) * 4.897278e-01; syncx += (bpf[7] = bpf[6]) * -2.765914e+00; @@ -1097,8 +1091,8 @@ wwv_rf( * while the second counter (epoch) counts the samples in the * second. */ - up->mphase = (up->mphase + 1) % MINUTE; - epoch = up->mphase % SECOND; + up->mphase = (up->mphase + 1) % WWV_MIN; + epoch = up->mphase % WWV_SEC; /* * WWV @@ -1126,7 +1120,7 @@ wwv_rf( sp = &up->mitig[up->achan].wwv; sp->amp = sqrt(ciamp * ciamp + cqamp * cqamp) / SYNCYC; if (!(up->status & MSYNC)) - wwv_qrz(peer, sp, (int)(pp->fudgetime1 * SECOND)); + wwv_qrz(peer, sp, (int)(pp->fudgetime1 * WWV_SEC)); /* * WWVH @@ -1154,7 +1148,7 @@ wwv_rf( rp = &up->mitig[up->achan].wwvh; rp->amp = sqrt(hiamp * hiamp + hqamp * hqamp) / SYNCYC; if (!(up->status & MSYNC)) - wwv_qrz(peer, rp, (int)(pp->fudgetime2 * SECOND)); + wwv_qrz(peer, rp, (int)(pp->fudgetime2 * WWV_SEC)); jptr = (jptr + 1) % SYNSIZ; kptr = (kptr + 1) % TCKSIZ; @@ -1174,10 +1168,6 @@ wwv_rf( */ if (!wwv_newchan(peer)) up->watch = 0; -#ifdef ICOM - if (up->fd_icom > 0) - wwv_qsy(peer, up->dchan); -#endif /* ICOM */ } else { /* @@ -1186,9 +1176,9 @@ wwv_rf( * don't miss a beat. */ if (up->status & LEPSEC) { - up->mphase -= SECOND; + up->mphase -= WWV_SEC; if (up->mphase < 0) - up->mphase += MINUTE; + up->mphase += WWV_MIN; } } } @@ -1212,8 +1202,9 @@ wwv_rf( wwv_epoch(peer); } else if (up->sptr != NULL) { sp = up->sptr; - if (sp->metric >= TTHR && epoch == sp->mepoch % SECOND) { - up->rsec = (60 - sp->mepoch / SECOND) % 60; + if (sp->metric >= TTHR && epoch == sp->mepoch % WWV_SEC) + { + up->rsec = (60 - sp->mepoch / WWV_SEC) % 60; up->rphase = 0; up->status |= MSYNC; up->watch = 0; @@ -1232,18 +1223,14 @@ wwv_rf( * provides a resolution of one sample (125 us). The filters run * only if the station has been reliably determined. */ - if (up->status & SELV) { - pdelay = (int)(pp->fudgetime1 * SECOND); + if (up->status & SELV) mfsync = sqrt(csiamp * csiamp + csqamp * csqamp) / TCKCYC; - } else if (up->status & SELH) { - pdelay = (int)(pp->fudgetime2 * SECOND); + else if (up->status & SELH) mfsync = sqrt(hsiamp * hsiamp + hsqamp * hsqamp) / TCKCYC; - } else { - pdelay = 0; + else mfsync = 0; - } /* * Enhance the seconds sync pulse using a 1-s (8000-sample) comb @@ -1265,15 +1252,15 @@ wwv_rf( epopos = epoch; j = epoch - 6 * MS; if (j < 0) - j += SECOND; + j += WWV_SEC; nxtmax = fabs(epobuf[j]); } if (epoch == 0) { up->epomax = epomax; up->eposnr = wwv_snr(epomax, nxtmax); - epopos -= pdelay + TCKCYC * MS; + epopos -= TCKCYC * MS; if (epopos < 0) - epopos += SECOND; + epopos += WWV_SEC; wwv_endpoc(peer, epopos); if (!(up->status & SSYNC)) up->alarm |= SYNERR; @@ -1313,11 +1300,11 @@ wwv_qrz( { struct refclockproc *pp; struct wwvunit *up; - char tbuf[80]; /* monitor buffer */ + char tbuf[TBUF]; /* monitor buffer */ long epoch; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Find the sample with peak amplitude, which defines the minute @@ -1326,7 +1313,7 @@ wwv_qrz( */ epoch = up->mphase - pdelay - SYNSIZ; if (epoch < 0) - epoch += MINUTE; + epoch += WWV_MIN; if (sp->amp > sp->maxeng) { sp->maxeng = sp->amp; sp->pos = epoch; @@ -1343,15 +1330,15 @@ wwv_qrz( if (up->mphase == 0) { sp->synmax = sp->maxeng; sp->synsnr = wwv_snr(sp->synmax, (sp->noieng - - sp->synmax) / MINUTE); + sp->synmax) / WWV_MIN); if (sp->count == 0) sp->lastpos = sp->pos; - epoch = (sp->pos - sp->lastpos) % MINUTE; + epoch = (sp->pos - sp->lastpos) % WWV_MIN; sp->reach <<= 1; if (sp->reach & (1 << AMAX)) sp->count--; if (sp->synmax > ATHR && sp->synsnr > ASNR) { - if (abs(epoch) < AWND * MS) { + if (labs(epoch) < AWND * MS) { sp->reach |= 1; sp->count++; sp->mepoch = sp->lastpos = sp->pos; @@ -1364,11 +1351,11 @@ wwv_qrz( else sp->metric = wwv_metric(sp); if (pp->sloppyclockflag & CLK_FLAG4) { - sprintf(tbuf, - "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %4ld %4ld", + snprintf(tbuf, sizeof(tbuf), + "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %ld %ld", up->status, up->gain, sp->refid, sp->reach & 0xffff, sp->metric, sp->synmax, - sp->synsnr, sp->pos % SECOND, epoch); + sp->synsnr, sp->pos % WWV_SEC, epoch); record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG if (debug) @@ -1413,15 +1400,15 @@ wwv_endpoc( static int avgcnt; /* averaging interval counter */ static int avginc; /* averaging ratchet */ static int iniflg; /* initialization flag */ - char tbuf[80]; /* monitor buffer */ + char tbuf[TBUF]; /* monitor buffer */ double dtemp; int tmp2; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; if (!iniflg) { iniflg = 1; - memset((char *)epoch_mf, 0, sizeof(epoch_mf)); + ZERO(epoch_mf); } /* @@ -1475,7 +1462,7 @@ wwv_endpoc( * interval while the comb filter charges up and noise * dissapates.. */ - tmp2 = (tepoch - xepoch) % SECOND; + tmp2 = (tepoch - xepoch) % WWV_SEC; if (tmp2 == 0) { syncnt++; if (syncnt > SCMP && up->status & MSYNC && (up->status & @@ -1489,9 +1476,9 @@ wwv_endpoc( mepoch = xepoch; syncnt = 0; } - if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & MSYNC)) - { - sprintf(tbuf, + if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & + MSYNC)) { + snprintf(tbuf, sizeof(tbuf), "wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d", up->status, up->gain, tepoch, up->epomax, up->eposnr, tmp2, avgcnt, syncnt, @@ -1551,16 +1538,16 @@ wwv_endpoc( * to zero; if it decrements to -3, the interval is halved and * the counter set to zero. */ - dtemp = (mepoch - zepoch) % SECOND; + dtemp = (mepoch - zepoch) % WWV_SEC; if (up->status & FGATE) { - if (abs(dtemp) < MAXFREQ * MINAVG) { + if (fabs(dtemp) < MAXFREQ * MINAVG) { up->freq += (dtemp / 2.) / ((mcount - zcount) * FCONST); if (up->freq > MAXFREQ) up->freq = MAXFREQ; else if (up->freq < -MAXFREQ) up->freq = -MAXFREQ; - if (abs(dtemp) < MAXFREQ * MINAVG / 2.) { + if (fabs(dtemp) < MAXFREQ * MINAVG / 2.) { if (avginc < 3) { avginc++; } else { @@ -1582,11 +1569,11 @@ wwv_endpoc( } } if (pp->sloppyclockflag & CLK_FLAG4) { - sprintf(tbuf, + snprintf(tbuf, sizeof(tbuf), "wwv2 %04x %5.0f %5.1f %5d %4d %4d %4d %4.0f %7.2f", up->status, up->epomax, up->eposnr, mepoch, up->avgint, maxrun, mcount - zcount, dtemp, - up->freq * 1e6 / SECOND); + up->freq * 1e6 / WWV_SEC); record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG if (debug) @@ -1634,7 +1621,7 @@ wwv_epoch( static double sigmin, sigzer, sigone, engmax, engmin; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Find the maximum minute sync pulse energy for both the @@ -1708,7 +1695,7 @@ wwv_epoch( * next pulse. */ up->rphase++; - if (up->mphase % SECOND == up->repoch) { + if (up->mphase % WWV_SEC == up->repoch) { up->status &= ~(DGATE | BGATE); engmin = sqrt(up->irig * up->irig + up->qrig * up->qrig); @@ -1768,14 +1755,14 @@ wwv_rsec( struct wwvunit *up; struct chan *cp; struct sync *sp, *rp; - char tbuf[80]; /* monitor buffer */ + char tbuf[TBUF]; /* monitor buffer */ int sw, arg, nsec; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; if (!iniflg) { iniflg = 1; - memset((char *)bitvec, 0, sizeof(bitvec)); + ZERO(bitvec); } /* @@ -1869,7 +1856,7 @@ wwv_rsec( } rp->metric = wwv_metric(rp); if (pp->sloppyclockflag & CLK_FLAG4) { - sprintf(tbuf, + snprintf(tbuf, sizeof(tbuf), "wwv5 %04x %3d %4d %.0f/%.1f %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f", up->status, up->gain, up->yepoch, up->epomax, up->eposnr, up->datsig, @@ -1887,35 +1874,28 @@ wwv_rsec( up->errcnt = up->digcnt = up->alarm = 0; /* - * We now begin the minute scan. If not yet synchronized - * to a station, restart if the units digit has not been - * found within the DATA timeout (15 m) or if not - * synchronized within the SYNCH timeout (40 m). After - * synchronizing to a station, restart if no stations - * are found within the PANIC timeout (2 days). + * If synchronized to a station, restart if no stations + * have been heard within the PANIC timeout (2 days). If + * not and the minute digit has been found, restart if + * not synchronized withing the SYNCH timeout (40 m). If + * not, restart if the unit digit has not been found + * within the DATA timeout (15 m). */ if (up->status & INSYNC) { if (up->watch > PANIC) { wwv_newgame(peer); return; } - } else { - if (!(up->status & DSYNC)) { - if (up->watch > DATA) { - wwv_newgame(peer); - return; - } - } + } else if (up->status & DSYNC) { if (up->watch > SYNCH) { wwv_newgame(peer); return; } + } else if (up->watch > DATA) { + wwv_newgame(peer); + return; } wwv_newchan(peer); -#ifdef ICOM - if (up->fd_icom > 0) - wwv_qsy(peer, up->dchan); -#endif /* ICOM */ break; /* @@ -1987,7 +1967,7 @@ wwv_rsec( /* * Save the data channel gain, then QSY to the probe channel and - * dim the seconds comb filters. The newchan() routine will + * dim the seconds comb filters. The www_newchan() routine will * light them back up. */ case MSC21: /* 58 */ @@ -2041,7 +2021,7 @@ wwv_rsec( } if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & DSYNC)) { - sprintf(tbuf, + snprintf(tbuf, sizeof(tbuf), "wwv3 %2d %04x %3d %4d %5.0f %5.1f %5.0f %5.1f %5.0f", nsec, up->status, up->gain, up->yepoch, up->epomax, up->eposnr, up->datsig, up->datsnr, bit); @@ -2075,7 +2055,7 @@ wwv_clock( l_fp offset; /* offset in NTP seconds */ pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; if (!(up->status & SSYNC)) up->alarm |= SYNERR; if (up->digcnt < 9) @@ -2107,11 +2087,12 @@ wwv_clock( pp->disp = 0; pp->lastref = up->timestamp; refclock_process_offset(pp, offset, - up->timestamp, PDELAY); + up->timestamp, PDELAY + up->pdelay); refclock_receive(peer); } } - pp->lencode = timecode(up, pp->a_lastcode); + pp->lencode = timecode(up, pp->a_lastcode, + sizeof(pp->a_lastcode)); record_clock_stats(&peer->srcadr, pp->a_lastcode); #ifdef DEBUG if (debug) @@ -2122,12 +2103,12 @@ wwv_clock( /* - * wwv_corr4 - determine maximum likelihood digit + * wwv_corr4 - determine maximum-likelihood digit * * This routine correlates the received digit vector with the BCD * coefficient vectors corresponding to all valid digits at the given * position in the decoding matrix. The maximum value corresponds to the - * maximum likelihood digit, while the ratio of this value to the next + * maximum-likelihood digit, while the ratio of this value to the next * lower value determines the likelihood function. Note that, if the * digit is invalid, the likelihood vector is averaged toward a miss. */ @@ -2143,12 +2124,12 @@ wwv_corr4( struct wwvunit *up; double topmax, nxtmax; /* metrics */ double acc; /* accumulator */ - char tbuf[80]; /* monitor buffer */ + char tbuf[TBUF]; /* monitor buffer */ int mldigit; /* max likelihood digit */ int i, j; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Correlate digit vector with each BCD coefficient vector. If @@ -2176,9 +2157,9 @@ wwv_corr4( vp->digsnr = wwv_snr(topmax, nxtmax); /* - * The current maximum likelihood digit is compared to the last - * maximum likelihood digit. If different, the compare counter - * and maximum likelihood digit are reset. When the compare + * The current maximum-likelihood digit is compared to the last + * maximum-likelihood digit. If different, the compare counter + * and maximum-likelihood digit are reset. When the compare * counter reaches the BCMP threshold (3), the digit is assumed * correct. When the compare counter of all nine digits have * reached threshold, the clock is assumed correct. @@ -2188,34 +2169,31 @@ wwv_corr4( * not considered correct until all nine clock digits have * reached threshold. This is intended as eye candy, but avoids * mistakes when the signal is low and the SNR is very marginal. - * once correctly set, the maximum likelihood digit is ignored - * on the assumption the clock will always be correct unless for - * some reason it drifts to a different second. */ - vp->mldigit = mldigit; if (vp->digprb < BTHR || vp->digsnr < BSNR) { - vp->count = 0; up->status |= BGATE; } else { - up->status |= DSYNC; if (vp->digit != mldigit) { - vp->count = 0; up->alarm |= CMPERR; - if (!(up->status & INSYNC)) + if (vp->count > 0) + vp->count--; + if (vp->count == 0) vp->digit = mldigit; } else { if (vp->count < BCMP) vp->count++; - else + if (vp->count == BCMP) { + up->status |= DSYNC; up->digcnt++; + } } } if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & INSYNC)) { - sprintf(tbuf, + snprintf(tbuf, sizeof(tbuf), "wwv4 %2d %04x %3d %4d %5.0f %2d %d %d %d %5.0f %5.1f", up->rsec - 1, up->status, up->gain, up->yepoch, - up->epomax, vp->radix, vp->digit, vp->mldigit, + up->epomax, vp->radix, vp->digit, mldigit, vp->count, vp->digprb, vp->digsnr); record_clock_stats(&peer->srcadr, tbuf); #ifdef DEBUG @@ -2244,7 +2222,7 @@ wwv_tsec( int temp; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Advance minute unit of the day. Don't propagate carries until @@ -2326,7 +2304,7 @@ wwv_tsec( * This routine rotates a likelihood vector one position and increments * the clock digit modulo the radix. It returns the new clock digit or * zero if a carry occurred. Once synchronized, the clock digit will - * match the maximum likelihood digit corresponding to that position. + * match the maximum-likelihood digit corresponding to that position. */ static int carry( @@ -2420,16 +2398,14 @@ wwv_newchan( struct wwvunit *up; struct sync *sp, *rp; double rank, dtemp; - int i, j; + int i, j, rval; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Search all five station pairs looking for the channel with - * maximum metric. If no station is found above thresholds, tune - * to WWV on 15 MHz, set the reference ID to NONE and wait for - * hotter ions. + * maximum metric. */ sp = NULL; j = 0; @@ -2453,39 +2429,57 @@ wwv_newchan( /* * If the strongest signal is less than the MTHR threshold (13), - * we are beneath the waves, so squelch the second sync. If the - * strongest signal is greater than the threshold, tune to that - * frequency and transmitter QTH. + * we are beneath the waves, so squelch the second sync and + * advance to the next station. This makes sure all stations are + * scanned when the ions grow dim. If the strongest signal is + * greater than the threshold, tune to that frequency and + * transmitter QTH. */ + up->status &= ~(SELV | SELH); if (rank < MTHR) { up->dchan = (up->dchan + 1) % NCHAN; - up->status &= ~(SELV | SELH); - return (FALSE); + if (up->status & METRIC) { + up->status &= ~METRIC; + refclock_report(peer, CEVNT_PROP); + } + rval = FALSE; + } else { + up->dchan = j; + up->sptr = sp; + memcpy(&pp->refid, sp->refid, 4); + peer->refid = pp->refid; + up->status |= METRIC; + if (sp->select & SELV) { + up->status |= SELV; + up->pdelay = pp->fudgetime1; + } else if (sp->select & SELH) { + up->status |= SELH; + up->pdelay = pp->fudgetime2; + } else { + up->pdelay = 0; + } + rval = TRUE; } - up->dchan = j; - up->status |= SELV | SELH; - up->sptr = sp; - memcpy(&pp->refid, sp->refid, 4); - peer->refid = pp->refid; - return (TRUE); +#ifdef ICOM + if (up->fd_icom > 0) + wwv_qsy(peer, up->dchan); +#endif /* ICOM */ + return (rval); } /* * wwv_newgame - reset and start over * - * There are four conditions resulting in a new game: - * - * 1 During initial acquisition (MSYNC dark) going 6 minutes (ACQSN) - * without reliably finding the minute pulse (MSYNC lit). + * There are three conditions resulting in a new game: * - * 2 After finding the minute pulse (MSYNC lit), going 15 minutes + * 1 After finding the minute pulse (MSYNC lit), going 15 minutes * (DATA) without finding the unit seconds digit. * - * 3 After finding good data (DATA lit), going more than 40 minutes + * 2 After finding good data (DSYNC lit), going more than 40 minutes * (SYNCH) without finding station sync (INSYNC lit). * - * 4 After finding station sync (INSYNC lit), going more than 2 days + * 3 After finding station sync (INSYNC lit), going more than 2 days * (PANIC) without finding any station. */ static void @@ -2499,12 +2493,14 @@ wwv_newgame( int i; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Initialize strategic values. Note we set the leap bits * NOTINSYNC and the refid "NONE". */ + if (up->status) + up->errflg = CEVNT_TIMEOUT; peer->leap = LEAP_NOTINSYNC; up->watch = up->status = up->alarm = 0; up->avgint = MINAVG; @@ -2514,24 +2510,23 @@ wwv_newgame( /* * Initialize the station processes for audio gain, select bit, * station/frequency identifier and reference identifier. Start - * probing at the next channel after the data channel. + * probing at the strongest channel or the default channel if + * nothing heard. */ memset(up->mitig, 0, sizeof(up->mitig)); for (i = 0; i < NCHAN; i++) { cp = &up->mitig[i]; cp->gain = up->gain; cp->wwv.select = SELV; - sprintf(cp->wwv.refid, "WV%.0f", floor(qsy[i])); + snprintf(cp->wwv.refid, sizeof(cp->wwv.refid), "WV%.0f", + floor(qsy[i])); cp->wwvh.select = SELH; - sprintf(cp->wwvh.refid, "WH%.0f", floor(qsy[i])); + snprintf(cp->wwvh.refid, sizeof(cp->wwvh.refid), "WH%.0f", + floor(qsy[i])); } - up->dchan = (DCHAN + NCHAN - 1) % NCHAN;; + up->dchan = (DCHAN + NCHAN - 1) % NCHAN; wwv_newchan(peer); - up->achan = up->schan = up->dchan; -#ifdef ICOM - if (up->fd_icom > 0) - wwv_qsy(peer, up->dchan); -#endif /* ICOM */ + up->schan = up->dchan; } /* @@ -2577,7 +2572,7 @@ wwv_qsy( struct wwvunit *up; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; if (up->fd_icom > 0) { up->mitig[up->achan].gain = up->gain; rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, @@ -2618,7 +2613,8 @@ wwv_qsy( static int timecode( struct wwvunit *up, /* driver structure pointer */ - char *ptr /* target string */ + char * tc, /* target string */ + size_t tcsiz /* target max chars */ ) { struct sync *sp; @@ -2643,20 +2639,23 @@ timecode( dut = up->misc & 0x7; if (!(up->misc & DUTS)) dut = -dut; - sprintf(ptr, "%c%1X", synchar, up->alarm); - sprintf(cptr, " %4d %03d %02d:%02d:%02d %c%c %+d", - year, day, hour, minute, second, leapchar, dst, dut); - strcat(ptr, cptr); + snprintf(tc, tcsiz, "%c%1X", synchar, up->alarm); + snprintf(cptr, sizeof(cptr), + " %4d %03d %02d:%02d:%02d %c%c %+d", + year, day, hour, minute, second, leapchar, dst, dut); + strlcat(tc, cptr, tcsiz); /* * Specific variable-format fields */ sp = up->sptr; - sprintf(cptr, " %d %d %s %.0f %d %.1f %d", up->watch, - up->mitig[up->dchan].gain, sp->refid, sp->metric, - up->errcnt, up->freq / SECOND * 1e6, up->avgint); - strcat(ptr, cptr); - return (strlen(ptr)); + snprintf(cptr, sizeof(cptr), " %d %d %s %.0f %d %.1f %d", + up->watch, up->mitig[up->dchan].gain, sp->refid, + sp->metric, up->errcnt, up->freq / WWV_SEC * 1e6, + up->avgint); + strlcat(tc, cptr, tcsiz); + + return strlen(tc); } @@ -2668,7 +2667,8 @@ timecode( * there are no clips, the gain is bumped up; if there are more than * MAXCLP clips (100), it is bumped down. The decoder is relatively * insensitive to amplitude, so this crudity works just peachy. The - * input port is set and the error flag is cleared, mostly to be ornery. + * routine also jiggles the input port and selectively mutes the + * monitor. */ static void wwv_gain( @@ -2679,7 +2679,7 @@ wwv_gain( struct wwvunit *up; pp = peer->procptr; - up = (struct wwvunit *)pp->unitptr; + up = pp->unitptr; /* * Apparently, the codec uses only the high order bits of the |