* 9600 bps if the high order 0x80 bit of the mode is zero and 1200 bps
* if one. The C-IV trace is turned on if the debug level is greater
* than one.
+ *
+ * Alarm codes
+ *
+ * CEVNT_BADTIME invalid date or time
+ * CEVNT_PROP propagation failure - no stations heard
*/
/*
* Interface definitions
#define MINDIST 28 /* min burst distance (of 40) */
#define MINSYNC 8 /* min sync distance (of 16) */
#define MINSTAMP 20 /* min timestamps (of 60) */
-#define METRIC 50 /* min channel metric (of 160) */
+#define MINMETRIC 50 /* min channel metric (of 160) */
/*
* The offset to the last stop bit of the first character, which defines
#define AVALID 0x0100 /* valid A frame */
#define BVALID 0x0200 /* valid B frame */
#define INSYNC 0x0400 /* clock synchronized */
+#define METRIC 0x0800 /* one or more stations heard */
/*
* Alarm status bits (alarm)
double step; /* codec adjustment */
/*
- * Open audio device.
+ * Open audio device. Don't complain if not there.
*/
fd_audio = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);
#ifdef DEBUG
#endif
/*
- * Open serial port in raw mode.
+ * If audio is unavailable, Open serial port in raw mode.
*/
if (fd_audio > 0) {
fd = fd_audio;
sprintf(device, DEVICE, unit);
fd = refclock_open(device, SPEED232, LDISC_RAW);
#endif /* HAVE_AUDIO */
- if (fd <= 0)
+ if (fd < 0)
return (0);
/*
}
if (up->fd_icom > 0) {
if (chu_newchan(peer, 0) != 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 */
qual |= DECERR;
if (up->status & STAMP)
qual |= TSPERR;
- if (up->status & BVALID && dtemp >= METRIC)
+ if (up->status & BVALID && dtemp >= MINMETRIC)
up->status |= INSYNC;
synchar = leapchar = ' ';
if (!(up->status & INSYNC)) {
/*
* If in sync and the signal metric is above threshold, the
* timecode is ipso fatso valid and can be selected to
- * discipline the clock. Be sure not to leave stray timestamps
- * around if signals are too weak or the clock time is invalid.
+ * discipline the clock.
*/
if (up->status & INSYNC && !(up->status & (DECODE | STAMP)) &&
- dtemp > METRIC) {
+ dtemp > MINMETRIC) {
if (!clocktime(pp->day, pp->hour, pp->minute, 0, GMT,
up->tstamp[0].l_ui, &pp->yearstart, &offset.l_ui)) {
up->errflg = CEVNT_BADTIME;
* matrix encodes the number of occurences of each digit found
* at the corresponding position. The maximum over all
* occurrences at each position is the distance for this
- * position and the corresponding digit is the maximum
+ * position and the corresponding digit is the maximum-
* likelihood candidate. If the distance is not more than half
* the total number of occurences, a majority has not been found
* and the data are discarded. The decoding distance is defined
*/
up->ndx = up->prevsec = 0;
up->burstcnt = up->ntstamp = 0;
- up->status &= INSYNC;
+ up->status &= INSYNC | METRIC;
for (i = 0; i < 20; i++) {
for (j = 0; j < 16; j++)
up->decode[i][j] = 0;
for (i = 0; i < NCHAN; i++) {
up->xmtr[i].probe++;
if (up->xmtr[i].metric > metric) {
+ up->status |= METRIC;
metric = up->xmtr[i].metric;
up->chan = i;
}
}
/*
- * Start the next dwell. If the first or no stations have been
- * heard, continue round-robin scan. If no stations are heard,
- * skew the minute by a few seconds in case we landed in the
- * middle of a burst.
+ * Start the next dwell. If the first dwell or no stations have
+ * been heard, continue round-robin scan.
*/
up->dwell = (up->dwell + 1) % DWELL;
if (up->dwell == 0 || metric == 0) {
TUNE);
sprintf(up->ident, "CHU%d", up->chan);
memcpy(&pp->refid, up->ident, 4);
- memcpy(&peer->refid, up->ident, 4);
+ memcpy(&peer->refid, up->ident, 4);
+ if (metric == 0 && up->status & METRIC) {
+ up->status &= ~METRIC;
+ refclock_report(peer, CEVNT_PROP);
+ }
return (rval);
}
#endif /* ICOM */
* 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. Fudgetime2 is used as a
+ * the monitor gain is set t a default value. Fudgetime2 is used as a
* frequency vernier for broken codec sample frequency.
+ *
+ * Alarm codes
+ *
+ * CEVNT_BADTIME invalid date or time
+ * CEVNT_TIMEOUT no IRIG data since last poll
*/
/*
* Interface definitions
#define SIZE 256 /* decompanding table size */
#define CYCLE 8 /* samples per bit */
#define SUBFLD 10 /* bits per frame */
-#define FIELD 10 /* frames per second */
+#define FIELD 100 /* bits per second */
#define MINTC 2 /* min PLL time constant */
#define MAXTC 20 /* max PLL time constant max */
#define MAXAMP 6000. /* maximum signal level */
#define BITP 2 /* position identifier */
/*
- * Error flags (up->errflg)
+ * Error flags
*/
#define IRIG_ERR_AMP 0x01 /* low carrier amplitude */
#define IRIG_ERR_FREQ 0x02 /* frequency tolerance exceeded */
* IRIG unit control structure
*/
struct irigunit {
- u_char timecode[21]; /* timecode string */
+ u_char timecode[2 * SUBFLD + 1]; /* timecode string */
l_fp timestamp; /* audio sample timestamp */
l_fp tick; /* audio sample increment */
l_fp refstamp; /* reference timestamp */
double bpf[9]; /* IRIG-B filter shift register */
double lpf[5]; /* IRIG-E filter shift register */
double intmin, intmax; /* integrated envelope min and max */
- double envmax; /* peak amplitude */
- double envmin; /* noise amplitude */
double maxsignal; /* integrated peak amplitude */
double noise; /* integrated noise amplitude */
double lastenv[CYCLE]; /* last cycle amplitudes */
int decim; /* sample decimation factor */
int envphase; /* envelope phase */
int envptr; /* envelope phase pointer */
- int carphase; /* carrier phase */
int envsw; /* envelope state */
int envxing; /* envelope slice crossing */
int tc; /* time constant */
int pulse; /* cycle counter */
int cycles; /* carrier cycles */
int dcycles; /* data cycles */
- int xptr; /* translate table pointer */
int lastbit; /* last code element */
int second; /* previous second */
int bitcnt; /* bit count in character */
*/
double lope; /* integrator output */
double env; /* envelope detector output */
- double dtemp; /* double temp */
+ int carphase; /* carrier phase */
+ double dtemp;
+ l_fp ltemp;
pp = peer->procptr;
up = (struct irigunit *)pp->unitptr;
* raw and integrated data for later use.
*/
up->envphase = (up->envphase + 1) % BAUD;
- up->carphase = (up->carphase + 1) % CYCLE;
up->integ[up->envphase] += (sample - up->integ[up->envphase]) /
(5 * up->tc);
lope = up->integ[up->envphase];
- up->lastenv[up->carphase] = sample;
- up->lastint[up->carphase] = lope;
+ carphase = up->envphase % CYCLE;
+ up->lastenv[carphase] = sample;
+ up->lastint[carphase] = lope;
/*
* Phase detector. Sample amplitudes are integrated over the
* change of 360 degrees produces an output change of one unit.
*/
if (up->lastsig > 0 && lope <= 0)
- up->zxing += (double)(up->carphase - 4) / CYCLE;
+ up->zxing += (double)(carphase - 4) / CYCLE;
up->lastsig = lope;
/*
* Update signal/noise estimates and PLL phase/frequency.
*/
if (up->envphase == 0) {
-
- /*
- * Update envelope signal and noise estimates and mess
- * with error bits.
- */
- up->maxsignal = up->intmax;
- up->noise = up->intmin;
+ up->maxsignal = up->intmax; up->noise = up->intmin;
+ up->intmin = 1e6; up->intmax = -1e6;
if (up->maxsignal < DRPOUT)
up->errflg |= IRIG_ERR_AMP;
if (up->maxsignal > 0)
- up->modndx = (up->intmax - up->intmin) /
- up->intmax;
+ up->modndx = (up->maxsignal - up->noise) /
+ up->maxsignal;
else
up->modndx = 0;
if (up->modndx < MODMIN)
up->errflg |= IRIG_ERR_MOD;
- up->intmin = 1e6; up->intmax = 0;
if (up->errflg & (IRIG_ERR_AMP | IRIG_ERR_FREQ |
IRIG_ERR_MOD | IRIG_ERR_SYNCH)) {
up->tc = MINTC;
* raw samples. The raw data bits are demodulated relative to
* the slice level and left-shifted in the decoding register.
*/
- if (up->carphase != 7)
+ if (carphase != 0)
return;
env = (up->lastenv[2] - up->lastenv[6]) / 2.;
* when three correct frames have been found.
*/
up->pulse = (up->pulse + 1) % 10;
- if (up->pulse == 1)
- up->envmax = env;
- else if (up->pulse == 9)
- up->envmin = env;
up->dcycles <<= 1;
- if (env >= (up->envmax + up->envmin) / 2.)
+ if (env >= (up->maxsignal + up->noise) / 2.)
up->dcycles |= 1;
up->cycles <<= 1;
if (lope >= (up->maxsignal + up->noise) / 2.)
up->cycles |= 1;
if ((up->cycles & 0x303c0f03) == 0x300c0300) {
- l_fp ltemp;
- int bitz;
-
- /*
- * The PLL time constant starts out small, in order to
- * sustain a frequency tolerance of 250 PPM. It
- * gradually increases as the loop settles down. Note
- * that small wiggles are not believed, unless they
- * persist for lots of samples.
- */
- if (up->pulse != 9)
+ if (up->pulse != 0)
up->errflg |= IRIG_ERR_SYNCH;
- up->pulse = 9;
- up->exing = -up->yxing;
- if (fabs(up->envxing - up->envphase) <= 1) {
- up->tcount++;
- if (up->tcount > 50 * up->tc) {
- up->tc++;
- if (up->tc > MAXTC)
- up->tc = MAXTC;
- up->tcount = 0;
- up->envxing = up->envphase;
- } else {
- up->exing -= up->envxing - up->envphase;
- }
- } else {
+ up->pulse = 0;
+ }
+ if (up->pulse != 0)
+ return;
+
+ /*
+ * The PLL time constant starts out small, in order to
+ * sustain a frequency tolerance of 250 PPM. It
+ * gradually increases as the loop settles down. Note
+ * that small wiggles are not believed, unless they
+ * persist for lots of samples.
+ */
+ up->exing = -up->yxing;
+ if (fabs(up->envxing - up->envphase) <= 1) {
+ up->tcount++;
+ if (up->tcount > 50 * up->tc) {
+ up->tc++;
+ if (up->tc > MAXTC)
+ up->tc = MAXTC;
up->tcount = 0;
up->envxing = up->envphase;
+ } else {
+ up->exing -= up->envxing - up->envphase;
}
+ } else {
+ up->tcount = 0;
+ up->envxing = up->envphase;
+ }
- /*
- * Strike the character timestamp as the positive zero
- * crossing of the first bit, accounting for the codec
- * delay and filter delay.
- */
- dtemp = up->decim * ((up->exing + 7 + BAUD) / SECOND) +
- up->fdelay;
- DTOLFP(dtemp, <emp);
- up->chrstamp = up->timestamp;
- L_SUB(&up->chrstamp, <emp);
+ /*
+ * Strike the character timestamp as the positive zero
+ * crossing of the first bit, accounting for the codec
+ * delay and filter delay.
+ */
+ dtemp = up->decim * ((up->exing + 7 + BAUD) / SECOND) +
+ up->fdelay;
+ DTOLFP(dtemp, <emp);
+ up->chrstamp = up->timestamp;
+ L_SUB(&up->chrstamp, <emp);
- /*
- * The data bits are collected in ten-bit frames. The
- * first two and last two bits are determined by frame
- * sync and ignored here; the resulting patterns
- * represent zero (0-1 bits), one (2-4 bits) and
- * position identifier (5-6 bits). The remaining
- * patterns represent errors and are treated as zeros.
- */
- bitz = up->dcycles & 0xfc;
- switch(bitz) {
-
- case 0x00:
- case 0x80:
- irig_decode(peer, BIT0);
- break;
-
- case 0xc0:
- case 0xe0:
- case 0xf0:
- irig_decode(peer, BIT1);
- break;
-
- case 0xf8:
- case 0xfc:
- irig_decode(peer, BITP);
- break;
-
- default:
- irig_decode(peer, 0);
- up->errflg |= IRIG_ERR_DECODE;
- }
+ /*
+ * The data bits are collected in ten-bit frames. The first two
+ * bits are not used; the resulting patterns represent zero (0-2
+ * bits), one (3-5 bits) and position identifier PI (6-7 bits).
+ * The remaining patterns represent errors and are treated as
+ * zeros.
+ */
+ switch (up->dcycles & 0xff) {
+
+ case 0x00: /* 0 */
+ case 0x80:
+ case 0xc0:
+ irig_decode(peer, BIT0);
+ break;
+
+ case 0xe0: /* 1 */
+ case 0xf0:
+ case 0xf8:
+ irig_decode(peer, BIT1);
+ break;
+
+ case 0xfc: /* PI */
+ case 0xfe:
+ irig_decode(peer, BITP);
+ break;
+
+ default: /* error */
+ irig_decode(peer, B0);
+ up->errflg |= IRIG_ERR_DECODE;
}
}
char syncchar; /* sync character (Spectracom) */
char sbs[6]; /* binary seconds since 0h */
char spare[2]; /* mulligan digits */
+ int i;
+ int temp;
pp = peer->procptr;
up = (struct irigunit *)pp->unitptr;
* mark the beginning of the second. The reference time
* is the beginning of the second position identifier,
* so copy the character timestamp to the reference
- * timestamp
+ * timestamp.
*/
- up->bitcnt = 1;
- up->frmcnt = 0;
- up->errflg = 0;
+ up->frmcnt = 1;
up->refstamp = up->chrstamp;
}
up->lastbit = bit;
- up->bitcnt = (up->bitcnt + 1) % SUBFLD;
- if (up->bitcnt == 0) {
+ if (up->frmcnt % SUBFLD == 0) {
/*
- * End of character. Encode two hexadecimal digits in
+ * End of frame. Encode two hexadecimal digits in
* little-endian timecode field.
*/
- if (up->frmcnt == 0)
- up->bits <<= 1;
- if (up->xptr < 2)
- up->xptr = 2 * FIELD;
- up->timecode[--up->xptr] = hexchar[(up->bits >> 5) &
+ temp = up->bits;
+ i = (SUBFLD - 1 - up->frmcnt / SUBFLD) * 2;
+
+printf (" %d %1c%1c", i, hexchar[(temp >> 5) & 0xf], hexchar[temp & 0xf]);
+
+ up->timecode[i - 1] = hexchar[(temp >> 5) &
0xf];
- up->timecode[--up->xptr] = hexchar[up->bits & 0xf];
- up->frmcnt = (up->frmcnt + 1) % FIELD;
+
+
+ up->timecode[i - 2] = hexchar[temp & 0xf];
if (up->frmcnt == 0) {
+printf("\n");
+printf("%20s\n", up->timecode);
+
/*
* End of second. Decode the timecode and wind
* the clock. Not all IRIG generators have the
* refclock_process() will reject the timecode
* as invalid.
*/
- up->xptr = 2 * FIELD;
if (sscanf((char *)up->timecode,
"%6s%2d%c%2s%3d%2d%2d%2d", sbs, &pp->year,
&syncchar, spare, &pp->day, &pp->hour,
if (up->errflg == 0) {
pp->lastref = pp->lastrec;
pp->lastrec = up->refstamp;
- refclock_process(pp);
+ if (!refclock_process(pp))
+ refclock_report(peer,
+ CEVNT_BADTIME);
}
sprintf(pp->a_lastcode,
"%02x %c %02d %03d %02d:%02d:%02d %4.0f %3d %6.3f %2d %6.2f %6.1f %s",
up->tc, up->exing * 1e6 / SECOND, up->freq *
1e6 / SECOND, ulfptoa(&pp->lastrec, 6));
pp->lencode = strlen(pp->a_lastcode);
+ up->errflg = 0;
if (pp->sloppyclockflag & CLK_FLAG4) {
record_clock_stats(&peer->srcadr,
pp->a_lastcode);
- up->errflg = 0;
#ifdef DEBUG
if (debug)
printf("irig %s\n",
}
}
}
+ up->frmcnt = (up->frmcnt + 1) % FIELD;
}
*
* This routine sweeps up the timecode updates since the last poll. For
* IRIG-B there should be at least 60 updates; for IRIG-E there should
- * be at least 6. If nothing is heard, a timeout event is declared and
- * any orphaned timecode updates are sent to foster care.
+ * be at least 6. If nothing is heard, a timeout event is declared.
*/
static void
irig_poll(
return;
}
+ refclock_receive(peer);
if (!(pp->sloppyclockflag & CLK_FLAG4)) {
- refclock_receive(peer);
record_clock_stats(&peer->srcadr, pp->a_lastcode);
- up->errflg = 0;
#ifdef DEBUG
if (debug)
printf("irig %s\n", pp->a_lastcode);
* 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.
#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 */
/*
* 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
+ * the codec delay about 0.5 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.
*/
-#define PDELAY (.0011 + .0047 + .0002) /* net system delay (s) */
+#define PDELAY (.0011 + .0047 + .0005) /* net system delay (s) */
/*
* Table of sine values at 4.5-degree increments. This is used by the
/*
* 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
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 */
pp = peer->procptr;
up = (struct wwvunit *)pp->unitptr;
- if (pp->coderecv == pp->codeproc)
- up->errflg = CEVNT_TIMEOUT;
if (up->errflg)
refclock_report(peer, up->errflg);
up->errflg = 0;
mepoch = xepoch;
syncnt = 0;
}
- if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status & MSYNC))
- {
+ if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
+ MSYNC)) {
sprintf(tbuf,
"wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d",
up->status, up->gain, tepoch, up->epomax,
} else {
if (vp->count < BCMP)
vp->count++;
- else
+ if (vp->count == BCMP)
up->digcnt++;
}
}
if (rank < MTHR) {
up->dchan = (up->dchan + 1) % NCHAN;
up->status &= ~(SELV | SELH);
+ 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;
rval = TRUE;
}
#ifdef ICOM
/*
* wwv_newgame - reset and start over
*
- * There are four conditions resulting in a new game:
+ * There are three conditions resulting in a new game:
*
- * 1 During initial acquisition (MSYNC dark) going 6 minutes (ACQSN)
- * without reliably finding the minute pulse (MSYNC lit).
- *
- * 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
* 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;