Coverage Report

Created: 2023-05-19 06:16

/src/ntp-dev/ntpd/refclock_wwv.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * refclock_wwv - clock driver for NIST WWV/H time/frequency station
3
 */
4
#ifdef HAVE_CONFIG_H
5
#include <config.h>
6
#endif
7
8
#if defined(REFCLOCK) && defined(CLOCK_WWV)
9
10
#include "ntpd.h"
11
#include "ntp_io.h"
12
#include "ntp_refclock.h"
13
#include "ntp_calendar.h"
14
#include "ntp_stdlib.h"
15
#include "audio.h"
16
17
#include <stdio.h>
18
#include <ctype.h>
19
#include <math.h>
20
#ifdef HAVE_SYS_IOCTL_H
21
# include <sys/ioctl.h>
22
#endif /* HAVE_SYS_IOCTL_H */
23
24
#define ICOM 1
25
26
#ifdef ICOM
27
#include "icom.h"
28
#endif /* ICOM */
29
30
/*
31
 * Audio WWV/H demodulator/decoder
32
 *
33
 * This driver synchronizes the computer time using data encoded in
34
 * radio transmissions from NIST time/frequency stations WWV in Boulder,
35
 * CO, and WWVH in Kauai, HI. Transmissions are made continuously on
36
 * 2.5, 5, 10 and 15 MHz from WWV and WWVH, and 20 MHz from WWV. An
37
 * ordinary AM shortwave receiver can be tuned manually to one of these
38
 * frequencies or, in the case of ICOM receivers, the receiver can be
39
 * tuned automatically using this program as propagation conditions
40
 * change throughout the weasons, both day and night.
41
 *
42
 * The driver requires an audio codec or sound card with sampling rate 8
43
 * kHz and mu-law companding. This is the same standard as used by the
44
 * telephone industry and is supported by most hardware and operating
45
 * systems, including Solaris, SunOS, FreeBSD, NetBSD and Linux. In this
46
 * implementation, only one audio driver and codec can be supported on a
47
 * single machine.
48
 *
49
 * The demodulation and decoding algorithms used in this driver are
50
 * based on those developed for the TAPR DSP93 development board and the
51
 * TI 320C25 digital signal processor described in: Mills, D.L. A
52
 * precision radio clock for WWV transmissions. Electrical Engineering
53
 * Report 97-8-1, University of Delaware, August 1997, 25 pp., available
54
 * from www.eecis.udel.edu/~mills/reports.html. The algorithms described
55
 * in this report have been modified somewhat to improve performance
56
 * under weak signal conditions and to provide an automatic station
57
 * identification feature.
58
 *
59
 * The ICOM code is normally compiled in the driver. It isn't used,
60
 * unless the mode keyword on the server configuration command specifies
61
 * a nonzero ICOM ID select code. The C-IV trace is turned on if the
62
 * debug level is greater than one.
63
 *
64
 * Fudge factors
65
 *
66
 * Fudge flag4 causes the debugging output described above to be
67
 * recorded in the clockstats file. Fudge flag2 selects the audio input
68
 * port, where 0 is the mike port (default) and 1 is the line-in port.
69
 * It does not seem useful to select the compact disc player port. Fudge
70
 * flag3 enables audio monitoring of the input signal. For this purpose,
71
 * the monitor gain is set to a default value.
72
 *
73
 * CEVNT_BADTIME  invalid date or time
74
 * CEVNT_PROP   propagation failure - no stations heard
75
 * CEVNT_TIMEOUT  timeout (see newgame() below)
76
 */
77
/*
78
 * General definitions. These ordinarily do not need to be changed.
79
 */
80
0
#define DEVICE_AUDIO  "/dev/audio" /* audio device name */
81
0
#define AUDIO_BUFSIZ  320  /* audio buffer size (50 ms) */
82
0
#define PRECISION (-10)  /* precision assumed (about 1 ms) */
83
0
#define DESCRIPTION "WWV/H Audio Demodulator/Decoder" /* WRU */
84
0
#define WWV_SEC   8000  /* second epoch (sample rate) (Hz) */
85
0
#define WWV_MIN   (WWV_SEC * 60) /* minute epoch */
86
0
#define OFFSET    128  /* companded sample offset */
87
#define SIZE    256 /* decompanding table size */
88
0
#define MAXAMP    6000.  /* max signal level reference */
89
0
#define MAXCLP    100  /* max clips above reference per s */
90
0
#define MAXSNR    40.  /* max SNR reference */
91
0
#define MAXFREQ   1.5  /* max frequency tolerance (187 PPM) */
92
0
#define DATCYC    170  /* data filter cycles */
93
0
#define DATSIZ    (DATCYC * MS) /* data filter size */
94
0
#define SYNCYC    800  /* minute filter cycles */
95
0
#define SYNSIZ    (SYNCYC * MS) /* minute filter size */
96
0
#define TCKCYC    5  /* tick filter cycles */
97
0
#define TCKSIZ    (TCKCYC * MS) /* tick filter size */
98
0
#define NCHAN   5  /* number of radio channels */
99
0
#define AUDIO_PHI 5e-6  /* dispersion growth factor */
100
#define TBUF    128 /* max monitor line length */
101
102
/*
103
 * Tunable parameters. The DGAIN parameter can be changed to fit the
104
 * audio response of the radio at 100 Hz. The WWV/WWVH data subcarrier
105
 * is transmitted at about 20 percent percent modulation; the matched
106
 * filter boosts it by a factor of 17 and the receiver response does
107
 * what it does. The compromise value works for ICOM radios. If the
108
 * radio is not tunable, the DCHAN parameter can be changed to fit the
109
 * expected best propagation frequency: higher if further from the
110
 * transmitter, lower if nearer. The compromise value works for the US
111
 * right coast.
112
 */
113
0
#define DCHAN   3  /* default radio channel (15 Mhz) */
114
0
#define DGAIN   5.  /* subcarrier gain */
115
116
/*
117
 * General purpose status bits (status)
118
 *
119
 * SELV and/or SELH are set when WWV or WWVH have been heard and cleared
120
 * on signal loss. SSYNC is set when the second sync pulse has been
121
 * acquired and cleared by signal loss. MSYNC is set when the minute
122
 * sync pulse has been acquired. DSYNC is set when the units digit has
123
 * has reached the threshold and INSYNC is set when all nine digits have
124
 * reached the threshold. The MSYNC, DSYNC and INSYNC bits are cleared
125
 * only by timeout, upon which the driver starts over from scratch.
126
 *
127
 * DGATE is lit if the data bit amplitude or SNR is below thresholds and
128
 * BGATE is lit if the pulse width amplitude or SNR is below thresolds.
129
 * LEPSEC is set during the last minute of the leap day. At the end of
130
 * this minute the driver inserts second 60 in the seconds state machine
131
 * and the minute sync slips a second.
132
 */
133
0
#define MSYNC   0x0001  /* minute epoch sync */
134
0
#define SSYNC   0x0002  /* second epoch sync */
135
0
#define DSYNC   0x0004  /* minute units sync */
136
0
#define INSYNC    0x0008  /* clock synchronized */
137
0
#define FGATE   0x0010  /* frequency gate */
138
0
#define DGATE   0x0020  /* data pulse amplitude error */
139
0
#define BGATE   0x0040  /* data pulse width error */
140
0
#define METRIC    0x0080  /* one or more stations heard */
141
0
#define LEPSEC    0x1000  /* leap minute */
142
143
/*
144
 * Station scoreboard bits
145
 *
146
 * These are used to establish the signal quality for each of the five
147
 * frequencies and two stations.
148
 */
149
0
#define SELV    0x0100  /* WWV station select */
150
0
#define SELH    0x0200  /* WWVH station select */
151
152
/*
153
 * Alarm status bits (alarm)
154
 *
155
 * These bits indicate various alarm conditions, which are decoded to
156
 * form the quality character included in the timecode.
157
 */
158
0
#define CMPERR    0x1  /* digit or misc bit compare error */
159
0
#define LOWERR    0x2  /* low bit or digit amplitude or SNR */
160
0
#define NINERR    0x4  /* less than nine digits in minute */
161
0
#define SYNERR    0x8  /* not tracking second sync */
162
163
/*
164
 * Watchcat timeouts (watch)
165
 *
166
 * If these timeouts expire, the status bits are mashed to zero and the
167
 * driver starts from scratch. Suitably more refined procedures may be
168
 * developed in future. All these are in minutes.
169
 */
170
0
#define ACQSN   6  /* station acquisition timeout */
171
0
#define DATA    15  /* unit minutes timeout */
172
0
#define SYNCH   40  /* station sync timeout */
173
0
#define PANIC   (2 * 1440) /* panic timeout */
174
175
/*
176
 * Thresholds. These establish the minimum signal level, minimum SNR and
177
 * maximum jitter thresholds which establish the error and false alarm
178
 * rates of the driver. The values defined here may be on the
179
 * adventurous side in the interest of the highest sensitivity.
180
 */
181
0
#define MTHR    13.  /* minute sync gate (percent) */
182
0
#define TTHR    50.  /* minute sync threshold (percent) */
183
0
#define AWND    20  /* minute sync jitter threshold (ms) */
184
0
#define ATHR    2500.  /* QRZ minute sync threshold */
185
0
#define ASNR    20.  /* QRZ minute sync SNR threshold (dB) */
186
0
#define QTHR    2500.  /* QSY minute sync threshold */
187
0
#define QSNR    20.  /* QSY minute sync SNR threshold (dB) */
188
0
#define STHR    2500.  /* second sync threshold */
189
0
#define SSNR    15.  /* second sync SNR threshold (dB) */
190
0
#define SCMP    10  /* second sync compare threshold */
191
0
#define DTHR    1000.  /* bit threshold */
192
0
#define DSNR    10.  /* bit SNR threshold (dB) */
193
#define AMIN    3 /* min bit count */
194
0
#define AMAX    6  /* max bit count */
195
0
#define BTHR    1000.  /* digit threshold */
196
0
#define BSNR    3.  /* digit likelihood threshold (dB) */
197
0
#define BCMP    3  /* digit compare threshold */
198
0
#define MAXERR    40  /* maximum error alarm */
199
200
/*
201
 * Tone frequency definitions. The increments are for 4.5-deg sine
202
 * table.
203
 */
204
0
#define MS    (WWV_SEC / 1000) /* samples per millisecond */
205
0
#define IN100   ((100 * 80) / WWV_SEC) /* 100 Hz increment */
206
0
#define IN1000    ((1000 * 80) / WWV_SEC) /* 1000 Hz increment */
207
0
#define IN1200    ((1200 * 80) / WWV_SEC) /* 1200 Hz increment */
208
209
/*
210
 * Acquisition and tracking time constants
211
 */
212
0
#define MINAVG    8  /* min averaging time */
213
0
#define MAXAVG    1024  /* max averaging time */
214
0
#define FCONST    3  /* frequency time constant */
215
0
#define TCONST    16  /* data bit/digit time constant */
216
217
/*
218
 * Miscellaneous status bits (misc)
219
 *
220
 * These bits correspond to designated bits in the WWV/H timecode. The
221
 * bit probabilities are exponentially averaged over several minutes and
222
 * processed by a integrator and threshold.
223
 */
224
#define DUT1    0x01  /* 56 DUT .1 */
225
#define DUT2    0x02  /* 57 DUT .2 */
226
#define DUT4    0x04  /* 58 DUT .4 */
227
0
#define DUTS    0x08  /* 50 DUT sign */
228
#define DST1    0x10  /* 55 DST1 leap warning */
229
#define DST2    0x20  /* 2 DST2 DST1 delayed one day */
230
0
#define SECWAR    0x40  /* 3 leap second warning */
231
232
/*
233
 * The on-time synchronization point is the positive-going zero crossing
234
 * of the first cycle of the 5-ms second pulse. The IIR baseband filter
235
 * phase delay is 0.91 ms, while the receiver delay is approximately 4.7
236
 * ms at 1000 Hz. The fudge value -0.45 ms due to the codec and other
237
 * causes was determined by calibrating to a PPS signal from a GPS
238
 * receiver. The additional propagation delay specific to each receiver
239
 * location can be  programmed in the fudge time1 and time2 values for
240
 * WWV and WWVH, respectively.
241
 *
242
 * The resulting offsets with a 2.4-GHz P4 running FreeBSD 6.1 are
243
 * generally within .02 ms short-term with .02 ms jitter. The long-term
244
 * offsets vary up to 0.3 ms due to ionosperhic layer height variations.
245
 * The processor load due to the driver is 5.8 percent.
246
 */
247
0
#define PDELAY  ((.91 + 4.7 - 0.45) / 1000) /* system delay (s) */
248
249
/*
250
 * Table of sine values at 4.5-degree increments. This is used by the
251
 * synchronous matched filter demodulators.
252
 */
253
double sintab[] = {
254
 0.000000e+00,  7.845910e-02,  1.564345e-01,  2.334454e-01, /* 0-3 */
255
 3.090170e-01,  3.826834e-01,  4.539905e-01,  5.224986e-01, /* 4-7 */
256
 5.877853e-01,  6.494480e-01,  7.071068e-01,  7.604060e-01, /* 8-11 */
257
 8.090170e-01,  8.526402e-01,  8.910065e-01,  9.238795e-01, /* 12-15 */
258
 9.510565e-01,  9.723699e-01,  9.876883e-01,  9.969173e-01, /* 16-19 */
259
 1.000000e+00,  9.969173e-01,  9.876883e-01,  9.723699e-01, /* 20-23 */
260
 9.510565e-01,  9.238795e-01,  8.910065e-01,  8.526402e-01, /* 24-27 */
261
 8.090170e-01,  7.604060e-01,  7.071068e-01,  6.494480e-01, /* 28-31 */
262
 5.877853e-01,  5.224986e-01,  4.539905e-01,  3.826834e-01, /* 32-35 */
263
 3.090170e-01,  2.334454e-01,  1.564345e-01,  7.845910e-02, /* 36-39 */
264
-0.000000e+00, -7.845910e-02, -1.564345e-01, -2.334454e-01, /* 40-43 */
265
-3.090170e-01, -3.826834e-01, -4.539905e-01, -5.224986e-01, /* 44-47 */
266
-5.877853e-01, -6.494480e-01, -7.071068e-01, -7.604060e-01, /* 48-51 */
267
-8.090170e-01, -8.526402e-01, -8.910065e-01, -9.238795e-01, /* 52-55 */
268
-9.510565e-01, -9.723699e-01, -9.876883e-01, -9.969173e-01, /* 56-59 */
269
-1.000000e+00, -9.969173e-01, -9.876883e-01, -9.723699e-01, /* 60-63 */
270
-9.510565e-01, -9.238795e-01, -8.910065e-01, -8.526402e-01, /* 64-67 */
271
-8.090170e-01, -7.604060e-01, -7.071068e-01, -6.494480e-01, /* 68-71 */
272
-5.877853e-01, -5.224986e-01, -4.539905e-01, -3.826834e-01, /* 72-75 */
273
-3.090170e-01, -2.334454e-01, -1.564345e-01, -7.845910e-02, /* 76-79 */
274
 0.000000e+00};               /* 80 */
275
276
/*
277
 * Decoder operations at the end of each second are driven by a state
278
 * machine. The transition matrix consists of a dispatch table indexed
279
 * by second number. Each entry in the table contains a case switch
280
 * number and argument.
281
 */
282
struct progx {
283
  int sw;     /* case switch number */
284
  int arg;    /* argument */
285
};
286
287
/*
288
 * Case switch numbers
289
 */
290
0
#define IDLE    0  /* no operation */
291
0
#define COEF    1  /* BCD bit */
292
0
#define COEF1   2  /* BCD bit for minute unit */
293
0
#define COEF2   3  /* BCD bit not used */
294
0
#define DECIM9    4  /* BCD digit 0-9 */
295
0
#define DECIM6    5  /* BCD digit 0-6 */
296
0
#define DECIM3    6  /* BCD digit 0-3 */
297
0
#define DECIM2    7  /* BCD digit 0-2 */
298
0
#define MSCBIT    8  /* miscellaneous bit */
299
0
#define MSC20   9  /* miscellaneous bit */   
300
0
#define MSC21   10  /* QSY probe channel */   
301
0
#define MIN1    11  /* latch time */    
302
0
#define MIN2    12  /* leap second */
303
0
#define SYNC2   13  /* latch minute sync pulse */   
304
0
#define SYNC3   14  /* latch data pulse */    
305
306
/*
307
 * Offsets in decoding matrix
308
 */
309
0
#define MN    0  /* minute digits (2) */
310
0
#define HR    2  /* hour digits (2) */
311
0
#define DA    4  /* day digits (3) */
312
0
#define YR    7  /* year digits (2) */
313
314
struct progx progx[] = {
315
  {SYNC2, 0},   /* 0 latch minute sync pulse */
316
  {SYNC3, 0},   /* 1 latch data pulse */
317
  {MSCBIT, DST2},   /* 2 dst2 */
318
  {MSCBIT, SECWAR}, /* 3 lw */
319
  {COEF,  0},   /* 4 1 year units */
320
  {COEF,  1},   /* 5 2 */
321
  {COEF,  2},   /* 6 4 */
322
  {COEF,  3},   /* 7 8 */
323
  {DECIM9, YR},   /* 8 */
324
  {IDLE,  0},   /* 9 p1 */
325
  {COEF1, 0},   /* 10 1 minute units */
326
  {COEF1, 1},   /* 11 2 */
327
  {COEF1, 2},   /* 12 4 */
328
  {COEF1, 3},   /* 13 8 */
329
  {DECIM9, MN},   /* 14 */
330
  {COEF,  0},   /* 15 10 minute tens */
331
  {COEF,  1},   /* 16 20 */
332
  {COEF,  2},   /* 17 40 */
333
  {COEF2, 3},   /* 18 80 (not used) */
334
  {DECIM6, MN + 1}, /* 19 p2 */
335
  {COEF,  0},   /* 20 1 hour units */
336
  {COEF,  1},   /* 21 2 */
337
  {COEF,  2},   /* 22 4 */
338
  {COEF,  3},   /* 23 8 */
339
  {DECIM9, HR},   /* 24 */
340
  {COEF,  0},   /* 25 10 hour tens */
341
  {COEF,  1},   /* 26 20 */
342
  {COEF2, 2},   /* 27 40 (not used) */
343
  {COEF2, 3},   /* 28 80 (not used) */
344
  {DECIM2, HR + 1}, /* 29 p3 */
345
  {COEF,  0},   /* 30 1 day units */
346
  {COEF,  1},   /* 31 2 */
347
  {COEF,  2},   /* 32 4 */
348
  {COEF,  3},   /* 33 8 */
349
  {DECIM9, DA},   /* 34 */
350
  {COEF,  0},   /* 35 10 day tens */
351
  {COEF,  1},   /* 36 20 */
352
  {COEF,  2},   /* 37 40 */
353
  {COEF,  3},   /* 38 80 */
354
  {DECIM9, DA + 1}, /* 39 p4 */
355
  {COEF,  0},   /* 40 100 day hundreds */
356
  {COEF,  1},   /* 41 200 */
357
  {COEF2, 2},   /* 42 400 (not used) */
358
  {COEF2, 3},   /* 43 800 (not used) */
359
  {DECIM3, DA + 2}, /* 44 */
360
  {IDLE,  0},   /* 45 */
361
  {IDLE,  0},   /* 46 */
362
  {IDLE,  0},   /* 47 */
363
  {IDLE,  0},   /* 48 */
364
  {IDLE,  0},   /* 49 p5 */
365
  {MSCBIT, DUTS},   /* 50 dut+- */
366
  {COEF,  0},   /* 51 10 year tens */
367
  {COEF,  1},   /* 52 20 */
368
  {COEF,  2},   /* 53 40 */
369
  {COEF,  3},   /* 54 80 */
370
  {MSC20, DST1},    /* 55 dst1 */
371
  {MSCBIT, DUT1},   /* 56 0.1 dut */
372
  {MSCBIT, DUT2},   /* 57 0.2 */
373
  {MSC21, DUT4},    /* 58 0.4 QSY probe channel */
374
  {MIN1,  0},   /* 59 p6 latch time */
375
  {MIN2,  0}    /* 60 leap second */
376
};
377
378
/*
379
 * BCD coefficients for maximum-likelihood digit decode
380
 */
381
#define P15 1.    /* max positive number */
382
#define N15 -1.   /* max negative number */
383
384
/*
385
 * Digits 0-9
386
 */
387
#define P9  (P15 / 4) /* mark (+1) */
388
#define N9  (N15 / 4) /* space (-1) */
389
390
double bcd9[][4] = {
391
  {N9, N9, N9, N9},   /* 0 */
392
  {P9, N9, N9, N9},   /* 1 */
393
  {N9, P9, N9, N9},   /* 2 */
394
  {P9, P9, N9, N9},   /* 3 */
395
  {N9, N9, P9, N9},   /* 4 */
396
  {P9, N9, P9, N9},   /* 5 */
397
  {N9, P9, P9, N9},   /* 6 */
398
  {P9, P9, P9, N9},   /* 7 */
399
  {N9, N9, N9, P9},   /* 8 */
400
  {P9, N9, N9, P9},   /* 9 */
401
  {0, 0, 0, 0}    /* backstop */
402
};
403
404
/*
405
 * Digits 0-6 (minute tens)
406
 */
407
#define P6  (P15 / 3) /* mark (+1) */
408
#define N6  (N15 / 3) /* space (-1) */
409
410
double bcd6[][4] = {
411
  {N6, N6, N6, 0},  /* 0 */
412
  {P6, N6, N6, 0},  /* 1 */
413
  {N6, P6, N6, 0},  /* 2 */
414
  {P6, P6, N6, 0},  /* 3 */
415
  {N6, N6, P6, 0},  /* 4 */
416
  {P6, N6, P6, 0},  /* 5 */
417
  {N6, P6, P6, 0},  /* 6 */
418
  {0, 0, 0, 0}    /* backstop */
419
};
420
421
/*
422
 * Digits 0-3 (day hundreds)
423
 */
424
#define P3  (P15 / 2) /* mark (+1) */
425
#define N3  (N15 / 2) /* space (-1) */
426
427
double bcd3[][4] = {
428
  {N3, N3, 0, 0},   /* 0 */
429
  {P3, N3, 0, 0},   /* 1 */
430
  {N3, P3, 0, 0},   /* 2 */
431
  {P3, P3, 0, 0},   /* 3 */
432
  {0, 0, 0, 0}    /* backstop */
433
};
434
435
/*
436
 * Digits 0-2 (hour tens)
437
 */
438
#define P2  (P15 / 2) /* mark (+1) */
439
#define N2  (N15 / 2) /* space (-1) */
440
441
double bcd2[][4] = {
442
  {N2, N2, 0, 0},   /* 0 */
443
  {P2, N2, 0, 0},   /* 1 */
444
  {N2, P2, 0, 0},   /* 2 */
445
  {0, 0, 0, 0}    /* backstop */
446
};
447
448
/*
449
 * DST decode (DST2 DST1) for prettyprint
450
 */
451
char dstcod[] = {
452
  'S',      /* 00 standard time */
453
  'I',      /* 01 set clock ahead at 0200 local */
454
  'O',      /* 10 set clock back at 0200 local */
455
  'D'     /* 11 daylight time */
456
};
457
458
/*
459
 * The decoding matrix consists of nine row vectors, one for each digit
460
 * of the timecode. The digits are stored from least to most significant
461
 * order. The maximum-likelihood timecode is formed from the digits
462
 * corresponding to the maximum-likelihood values reading in the
463
 * opposite order: yy ddd hh:mm.
464
 */
465
struct decvec {
466
  int radix;    /* radix (3, 4, 6, 10) */
467
  int digit;    /* current clock digit */
468
  int count;    /* match count */
469
  double digprb;    /* max digit probability */
470
  double digsnr;    /* likelihood function (dB) */
471
  double like[10];  /* likelihood integrator 0-9 */
472
};
473
474
/*
475
 * The station structure (sp) is used to acquire the minute pulse from
476
 * WWV and/or WWVH. These stations are distinguished by the frequency
477
 * used for the second and minute sync pulses, 1000 Hz for WWV and 1200
478
 * Hz for WWVH. Other than frequency, the format is the same.
479
 */
480
struct sync {
481
  double  epoch;    /* accumulated epoch differences */
482
  double  maxeng;   /* sync max energy */
483
  double  noieng;   /* sync noise energy */
484
  long  pos;    /* max amplitude position */
485
  long  lastpos;  /* last max position */
486
  long  mepoch;   /* minute synch epoch */
487
488
  double  amp;    /* sync signal */
489
  double  syneng;   /* sync signal max */
490
  double  synmax;   /* sync signal max latched at 0 s */
491
  double  synsnr;   /* sync signal SNR */
492
  double  metric;   /* signal quality metric */
493
  int reach;    /* reachability register */
494
  int count;    /* bit counter */
495
  int select;   /* select bits */
496
  char  refid[5]; /* reference identifier */
497
};
498
499
/*
500
 * The channel structure (cp) is used to mitigate between channels.
501
 */
502
struct chan {
503
  int gain;   /* audio gain */
504
  struct sync wwv;  /* wwv station */
505
  struct sync wwvh; /* wwvh station */
506
};
507
508
/*
509
 * WWV unit control structure (up)
510
 */
511
struct wwvunit {
512
  l_fp  timestamp;  /* audio sample timestamp */
513
  l_fp  tick;   /* audio sample increment */
514
  double  phase, freq;  /* logical clock phase and frequency */
515
  double  monitor;  /* audio monitor point */
516
  double  pdelay;   /* propagation delay (s) */
517
#ifdef ICOM
518
  int fd_icom;  /* ICOM file descriptor */
519
#endif /* ICOM */
520
  int errflg;   /* error flags */
521
  int watch;    /* watchcat */
522
523
  /*
524
   * Audio codec variables
525
   */
526
  double  comp[SIZE]; /* decompanding table */
527
  int port;   /* codec port */
528
  int gain;   /* codec gain */
529
  int mongain;  /* codec monitor gain */
530
  int clipcnt;  /* sample clipped count */
531
532
  /*
533
   * Variables used to establish basic system timing
534
   */
535
  int avgint;   /* master time constant */
536
  int yepoch;   /* sync epoch */
537
  int repoch;   /* buffered sync epoch */
538
  double  epomax;   /* second sync amplitude */
539
  double  eposnr;   /* second sync SNR */
540
  double  irig;   /* data I channel amplitude */
541
  double  qrig;   /* data Q channel amplitude */
542
  int datapt;   /* 100 Hz ramp */
543
  double  datpha;   /* 100 Hz VFO control */
544
  int rphase;   /* second sample counter */
545
  long  mphase;   /* minute sample counter */
546
547
  /*
548
   * Variables used to mitigate which channel to use
549
   */
550
  struct chan mitig[NCHAN]; /* channel data */
551
  struct sync *sptr;  /* station pointer */
552
  int dchan;    /* data channel */
553
  int schan;    /* probe channel */
554
  int achan;    /* active channel */
555
556
  /*
557
   * Variables used by the clock state machine
558
   */
559
  struct decvec decvec[9]; /* decoding matrix */
560
  int rsec;   /* seconds counter */
561
  int digcnt;   /* count of digits synchronized */
562
563
  /*
564
   * Variables used to estimate signal levels and bit/digit
565
   * probabilities
566
   */
567
  double  datsig;   /* data signal max */
568
  double  datsnr;   /* data signal SNR (dB) */
569
570
  /*
571
   * Variables used to establish status and alarm conditions
572
   */
573
  int status;   /* status bits */
574
  int alarm;    /* alarm flashers */
575
  int misc;   /* miscellaneous timecode bits */
576
  int errcnt;   /* data bit error counter */
577
};
578
579
/*
580
 * Function prototypes
581
 */
582
static  int wwv_start (int, struct peer *);
583
static  void  wwv_shutdown  (int, struct peer *);
584
static  void  wwv_receive (struct recvbuf *);
585
static  void  wwv_poll  (int, struct peer *);
586
587
/*
588
 * More function prototypes
589
 */
590
static  void  wwv_epoch (struct peer *);
591
static  void  wwv_rf    (struct peer *, double);
592
static  void  wwv_endpoc  (struct peer *, int);
593
static  void  wwv_rsec  (struct peer *, double);
594
static  void  wwv_qrz   (struct peer *, struct sync *, int);
595
static  void  wwv_corr4 (struct peer *, struct decvec *,
596
            double [], double [][4]);
597
static  void  wwv_gain  (struct peer *);
598
static  void  wwv_tsec  (struct peer *);
599
static  int timecode  (struct wwvunit *, char *, size_t);
600
static  double  wwv_snr   (double, double);
601
static  int carry   (struct decvec *);
602
static  int wwv_newchan (struct peer *);
603
static  void  wwv_newgame (struct peer *);
604
static  double  wwv_metric  (struct sync *);
605
static  void  wwv_clock (struct peer *);
606
#ifdef ICOM
607
static  int wwv_qsy   (struct peer *, int);
608
#endif /* ICOM */
609
610
static double qsy[NCHAN] = {2.5, 5, 10, 15, 20}; /* frequencies (MHz) */
611
612
/*
613
 * Transfer vector
614
 */
615
struct  refclock refclock_wwv = {
616
  wwv_start,    /* start up driver */
617
  wwv_shutdown,   /* shut down driver */
618
  wwv_poll,   /* transmit poll message */
619
  noentry,    /* not used (old wwv_control) */
620
  noentry,    /* initialize driver (not used) */
621
  noentry,    /* not used (old wwv_buginfo) */
622
  NOFLAGS     /* not used */
623
};
624
625
626
/*
627
 * wwv_start - open the devices and initialize data for processing
628
 */
629
static int
630
wwv_start(
631
  int unit,   /* instance number (used by PCM) */
632
  struct peer *peer /* peer structure pointer */
633
  )
634
0
{
635
0
  struct refclockproc *pp;
636
0
  struct wwvunit *up;
637
0
#ifdef ICOM
638
0
  int temp;
639
0
#endif /* ICOM */
640
641
  /*
642
   * Local variables
643
   */
644
0
  int fd;   /* file descriptor */
645
0
  int i;    /* index */
646
0
  double  step;   /* codec adjustment */
647
648
  /*
649
   * Open audio device
650
   */
651
0
  fd = audio_init(DEVICE_AUDIO, AUDIO_BUFSIZ, unit);
652
0
  if (fd < 0)
653
0
    return (0);
654
0
#ifdef DEBUG
655
0
  if (debug)
656
0
    audio_show();
657
0
#endif /* DEBUG */
658
659
  /*
660
   * Allocate and initialize unit structure
661
   */
662
0
  up = emalloc_zero(sizeof(*up));
663
0
  pp = peer->procptr;
664
0
  pp->io.clock_recv = wwv_receive;
665
0
  pp->io.srcclock = peer;
666
0
  pp->io.datalen = 0;
667
0
  pp->io.fd = fd;
668
0
  if (!io_addclock(&pp->io)) {
669
0
    close(fd);
670
0
    free(up);
671
0
    return (0);
672
0
  }
673
0
  pp->unitptr = up;
674
675
  /*
676
   * Initialize miscellaneous variables
677
   */
678
0
  peer->precision = PRECISION;
679
0
  pp->clockdesc = DESCRIPTION;
680
681
  /*
682
   * The companded samples are encoded sign-magnitude. The table
683
   * contains all the 256 values in the interest of speed.
684
   */
685
0
  up->comp[0] = up->comp[OFFSET] = 0.;
686
0
  up->comp[1] = 1.; up->comp[OFFSET + 1] = -1.;
687
0
  up->comp[2] = 3.; up->comp[OFFSET + 2] = -3.;
688
0
  step = 2.;
689
0
  for (i = 3; i < OFFSET; i++) {
690
0
    up->comp[i] = up->comp[i - 1] + step;
691
0
    up->comp[OFFSET + i] = -up->comp[i];
692
0
    if (i % 16 == 0)
693
0
      step *= 2.;
694
0
  }
695
0
  DTOLFP(1. / WWV_SEC, &up->tick);
696
697
  /*
698
   * Initialize the decoding matrix with the radix for each digit
699
   * position.
700
   */
701
0
  up->decvec[MN].radix = 10; /* minutes */
702
0
  up->decvec[MN + 1].radix = 6;
703
0
  up->decvec[HR].radix = 10; /* hours */
704
0
  up->decvec[HR + 1].radix = 3;
705
0
  up->decvec[DA].radix = 10; /* days */
706
0
  up->decvec[DA + 1].radix = 10;
707
0
  up->decvec[DA + 2].radix = 4;
708
0
  up->decvec[YR].radix = 10; /* years */
709
0
  up->decvec[YR + 1].radix = 10;
710
711
0
#ifdef ICOM
712
  /*
713
   * Initialize autotune if available. Note that the ICOM select
714
   * code must be less than 128, so the high order bit can be used
715
   * to select the line speed 0 (9600 bps) or 1 (1200 bps). Note
716
   * we don't complain if the ICOM device is not there; but, if it
717
   * is, the radio better be working.
718
   */
719
0
  temp = 0;
720
0
#ifdef DEBUG
721
0
  if (debug > 1)
722
0
    temp = P_TRACE;
723
0
#endif /* DEBUG */
724
0
  if (peer->ttl != 0) {
725
0
    if (peer->ttl & 0x80)
726
0
      up->fd_icom = icom_init("/dev/icom", B1200,
727
0
          temp);
728
0
    else
729
0
      up->fd_icom = icom_init("/dev/icom", B9600,
730
0
          temp);
731
0
  }
732
0
  if (up->fd_icom > 0) {
733
0
    if (wwv_qsy(peer, DCHAN) != 0) {
734
0
      msyslog(LOG_NOTICE, "icom: radio not found");
735
0
      close(up->fd_icom);
736
0
      up->fd_icom = 0;
737
0
    } else {
738
0
      msyslog(LOG_NOTICE, "icom: autotune enabled");
739
0
    }
740
0
  }
741
0
#endif /* ICOM */
742
743
  /*
744
   * Let the games begin.
745
   */
746
0
  wwv_newgame(peer);
747
0
  return (1);
748
0
}
749
750
751
/*
752
 * wwv_shutdown - shut down the clock
753
 */
754
static void
755
wwv_shutdown(
756
  int unit,   /* instance number (not used) */
757
  struct peer *peer /* peer structure pointer */
758
  )
759
0
{
760
0
  struct refclockproc *pp;
761
0
  struct wwvunit *up;
762
763
0
  pp = peer->procptr;
764
0
  up = pp->unitptr;
765
0
  if (up == NULL)
766
0
    return;
767
768
0
  io_closeclock(&pp->io);
769
0
#ifdef ICOM
770
0
  if (up->fd_icom > 0)
771
0
    close(up->fd_icom);
772
0
#endif /* ICOM */
773
0
  free(up);
774
0
}
775
776
777
/*
778
 * wwv_receive - receive data from the audio device
779
 *
780
 * This routine reads input samples and adjusts the logical clock to
781
 * track the A/D sample clock by dropping or duplicating codec samples.
782
 * It also controls the A/D signal level with an AGC loop to mimimize
783
 * quantization noise and avoid overload.
784
 */
785
static void
786
wwv_receive(
787
  struct recvbuf *rbufp /* receive buffer structure pointer */
788
  )
789
0
{
790
0
  struct peer *peer;
791
0
  struct refclockproc *pp;
792
0
  struct wwvunit *up;
793
794
  /*
795
   * Local variables
796
   */
797
0
  double  sample;   /* codec sample */
798
0
  u_char  *dpt;   /* buffer pointer */
799
0
  int bufcnt;   /* buffer counter */
800
0
  l_fp  ltemp;
801
802
0
  peer = rbufp->recv_peer;
803
0
  pp = peer->procptr;
804
0
  up = pp->unitptr;
805
806
  /*
807
   * Main loop - read until there ain't no more. Note codec
808
   * samples are bit-inverted.
809
   */
810
0
  DTOLFP((double)rbufp->recv_length / WWV_SEC, &ltemp);
811
0
  L_SUB(&rbufp->recv_time, &ltemp);
812
0
  up->timestamp = rbufp->recv_time;
813
0
  dpt = rbufp->recv_buffer;
814
0
  for (bufcnt = 0; bufcnt < rbufp->recv_length; bufcnt++) {
815
0
    sample = up->comp[~*dpt++ & 0xff];
816
817
    /*
818
     * Clip noise spikes greater than MAXAMP (6000) and
819
     * record the number of clips to be used later by the
820
     * AGC.
821
     */
822
0
    if (sample > MAXAMP) {
823
0
      sample = MAXAMP;
824
0
      up->clipcnt++;
825
0
    } else if (sample < -MAXAMP) {
826
0
      sample = -MAXAMP;
827
0
      up->clipcnt++;
828
0
    }
829
830
    /*
831
     * Variable frequency oscillator. The codec oscillator
832
     * runs at the nominal rate of 8000 samples per second,
833
     * or 125 us per sample. A frequency change of one unit
834
     * results in either duplicating or deleting one sample
835
     * per second, which results in a frequency change of
836
     * 125 PPM.
837
     */
838
0
    up->phase += (up->freq + clock_codec) / WWV_SEC;
839
0
    if (up->phase >= .5) {
840
0
      up->phase -= 1.;
841
0
    } else if (up->phase < -.5) {
842
0
      up->phase += 1.;
843
0
      wwv_rf(peer, sample);
844
0
      wwv_rf(peer, sample);
845
0
    } else {
846
0
      wwv_rf(peer, sample);
847
0
    }
848
0
    L_ADD(&up->timestamp, &up->tick);
849
0
  }
850
851
  /*
852
   * Set the input port and monitor gain for the next buffer.
853
   */
854
0
  if (pp->sloppyclockflag & CLK_FLAG2)
855
0
    up->port = 2;
856
0
  else
857
0
    up->port = 1;
858
0
  if (pp->sloppyclockflag & CLK_FLAG3)
859
0
    up->mongain = MONGAIN;
860
0
  else
861
0
    up->mongain = 0;
862
0
}
863
864
865
/*
866
 * wwv_poll - called by the transmit procedure
867
 *
868
 * This routine keeps track of status. If no offset samples have been
869
 * processed during a poll interval, a timeout event is declared. If
870
 * errors have have occurred during the interval, they are reported as
871
 * well.
872
 */
873
static void
874
wwv_poll(
875
  int unit,   /* instance number (not used) */
876
  struct peer *peer /* peer structure pointer */
877
  )
878
0
{
879
0
  struct refclockproc *pp;
880
0
  struct wwvunit *up;
881
882
0
  pp = peer->procptr;
883
0
  up = pp->unitptr;
884
0
  if (up->errflg)
885
0
    refclock_report(peer, up->errflg);
886
0
  up->errflg = 0;
887
0
  pp->polls++;
888
0
}
889
890
891
/*
892
 * wwv_rf - process signals and demodulate to baseband
893
 *
894
 * This routine grooms and filters decompanded raw audio samples. The
895
 * output signal is the 100-Hz filtered baseband data signal in
896
 * quadrature phase. The routine also determines the minute synch epoch,
897
 * as well as certain signal maxima, minima and related values.
898
 *
899
 * There are two 1-s ramps used by this program. Both count the 8000
900
 * logical clock samples spanning exactly one second. The epoch ramp
901
 * counts the samples starting at an arbitrary time. The rphase ramp
902
 * counts the samples starting at the 5-ms second sync pulse found
903
 * during the epoch ramp.
904
 *
905
 * There are two 1-m ramps used by this program. The mphase ramp counts
906
 * the 480,000 logical clock samples spanning exactly one minute and
907
 * starting at an arbitrary time. The rsec ramp counts the 60 seconds of
908
 * the minute starting at the 800-ms minute sync pulse found during the
909
 * mphase ramp. The rsec ramp drives the seconds state machine to
910
 * determine the bits and digits of the timecode. 
911
 *
912
 * Demodulation operations are based on three synthesized quadrature
913
 * sinusoids: 100 Hz for the data signal, 1000 Hz for the WWV sync
914
 * signal and 1200 Hz for the WWVH sync signal. These drive synchronous
915
 * matched filters for the data signal (170 ms at 100 Hz), WWV minute
916
 * sync signal (800 ms at 1000 Hz) and WWVH minute sync signal (800 ms
917
 * at 1200 Hz). Two additional matched filters are switched in
918
 * as required for the WWV second sync signal (5 cycles at 1000 Hz) and
919
 * WWVH second sync signal (6 cycles at 1200 Hz).
920
 */
921
static void
922
wwv_rf(
923
  struct peer *peer,  /* peerstructure pointer */
924
  double isig   /* input signal */
925
  )
926
0
{
927
0
  struct refclockproc *pp;
928
0
  struct wwvunit *up;
929
0
  struct sync *sp, *rp;
930
931
0
  static double lpf[5]; /* 150-Hz lpf delay line */
932
0
  double data;    /* lpf output */
933
0
  static double bpf[9]; /* 1000/1200-Hz bpf delay line */
934
0
  double syncx;   /* bpf output */
935
0
  static double mf[41]; /* 1000/1200-Hz mf delay line */
936
0
  double mfsync;    /* mf output */
937
938
0
  static int iptr;  /* data channel pointer */
939
0
  static double ibuf[DATSIZ]; /* data I channel delay line */
940
0
  static double qbuf[DATSIZ]; /* data Q channel delay line */
941
942
0
  static int jptr;  /* sync channel pointer */
943
0
  static int kptr;  /* tick channel pointer */
944
945
0
  static int csinptr; /* wwv channel phase */
946
0
  static double cibuf[SYNSIZ]; /* wwv I channel delay line */
947
0
  static double cqbuf[SYNSIZ]; /* wwv Q channel delay line */
948
0
  static double ciamp;  /* wwv I channel amplitude */
949
0
  static double cqamp;  /* wwv Q channel amplitude */
950
951
0
  static double csibuf[TCKSIZ]; /* wwv I tick delay line */
952
0
  static double csqbuf[TCKSIZ]; /* wwv Q tick delay line */
953
0
  static double csiamp; /* wwv I tick amplitude */
954
0
  static double csqamp; /* wwv Q tick amplitude */
955
956
0
  static int hsinptr; /* wwvh channel phase */
957
0
  static double hibuf[SYNSIZ]; /* wwvh I channel delay line */
958
0
  static double hqbuf[SYNSIZ]; /* wwvh Q channel delay line */
959
0
  static double hiamp;  /* wwvh I channel amplitude */
960
0
  static double hqamp;  /* wwvh Q channel amplitude */
961
962
0
  static double hsibuf[TCKSIZ]; /* wwvh I tick delay line */
963
0
  static double hsqbuf[TCKSIZ]; /* wwvh Q tick delay line */
964
0
  static double hsiamp; /* wwvh I tick amplitude */
965
0
  static double hsqamp; /* wwvh Q tick amplitude */
966
967
0
  static double epobuf[WWV_SEC]; /* second sync comb filter */
968
0
  static double epomax, nxtmax; /* second sync amplitude buffer */
969
0
  static int epopos;  /* epoch second sync position buffer */
970
971
0
  static int iniflg;  /* initialization flag */
972
0
  int epoch;    /* comb filter index */
973
0
  double  dtemp;
974
0
  int i;
975
976
0
  pp = peer->procptr;
977
0
  up = pp->unitptr;
978
979
0
  if (!iniflg) {
980
0
    iniflg = 1;
981
0
    memset((char *)lpf, 0, sizeof(lpf));
982
0
    memset((char *)bpf, 0, sizeof(bpf));
983
0
    memset((char *)mf, 0, sizeof(mf));
984
0
    memset((char *)ibuf, 0, sizeof(ibuf));
985
0
    memset((char *)qbuf, 0, sizeof(qbuf));
986
0
    memset((char *)cibuf, 0, sizeof(cibuf));
987
0
    memset((char *)cqbuf, 0, sizeof(cqbuf));
988
0
    memset((char *)csibuf, 0, sizeof(csibuf));
989
0
    memset((char *)csqbuf, 0, sizeof(csqbuf));
990
0
    memset((char *)hibuf, 0, sizeof(hibuf));
991
0
    memset((char *)hqbuf, 0, sizeof(hqbuf));
992
0
    memset((char *)hsibuf, 0, sizeof(hsibuf));
993
0
    memset((char *)hsqbuf, 0, sizeof(hsqbuf));
994
0
    memset((char *)epobuf, 0, sizeof(epobuf));
995
0
  }
996
997
  /*
998
   * Baseband data demodulation. The 100-Hz subcarrier is
999
   * extracted using a 150-Hz IIR lowpass filter. This attenuates
1000
   * the 1000/1200-Hz sync signals, as well as the 440-Hz and
1001
   * 600-Hz tones and most of the noise and voice modulation
1002
   * components.
1003
   *
1004
   * The subcarrier is transmitted 10 dB down from the carrier.
1005
   * The DGAIN parameter can be adjusted for this and to
1006
   * compensate for the radio audio response at 100 Hz.
1007
   *
1008
   * Matlab IIR 4th-order IIR elliptic, 150 Hz lowpass, 0.2 dB
1009
   * passband ripple, -50 dB stopband ripple, phase delay 0.97 ms.
1010
   */
1011
0
  data = (lpf[4] = lpf[3]) * 8.360961e-01;
1012
0
  data += (lpf[3] = lpf[2]) * -3.481740e+00;
1013
0
  data += (lpf[2] = lpf[1]) * 5.452988e+00;
1014
0
  data += (lpf[1] = lpf[0]) * -3.807229e+00;
1015
0
  lpf[0] = isig * DGAIN - data;
1016
0
  data = lpf[0] * 3.281435e-03
1017
0
      + lpf[1] * -1.149947e-02
1018
0
      + lpf[2] * 1.654858e-02
1019
0
      + lpf[3] * -1.149947e-02
1020
0
      + lpf[4] * 3.281435e-03;
1021
1022
  /*
1023
   * The 100-Hz data signal is demodulated using a pair of
1024
   * quadrature multipliers, matched filters and a phase lock
1025
   * loop. The I and Q quadrature data signals are produced by
1026
   * multiplying the filtered signal by 100-Hz sine and cosine
1027
   * signals, respectively. The signals are processed by 170-ms
1028
   * synchronous matched filters to produce the amplitude and
1029
   * phase signals used by the demodulator. The signals are scaled
1030
   * to produce unit energy at the maximum value.
1031
   */
1032
0
  i = up->datapt;
1033
0
  up->datapt = (up->datapt + IN100) % 80;
1034
0
  dtemp = sintab[i] * data / (MS / 2. * DATCYC);
1035
0
  up->irig -= ibuf[iptr];
1036
0
  ibuf[iptr] = dtemp;
1037
0
  up->irig += dtemp;
1038
1039
0
  i = (i + 20) % 80;
1040
0
  dtemp = sintab[i] * data / (MS / 2. * DATCYC);
1041
0
  up->qrig -= qbuf[iptr];
1042
0
  qbuf[iptr] = dtemp;
1043
0
  up->qrig += dtemp;
1044
0
  iptr = (iptr + 1) % DATSIZ;
1045
1046
  /*
1047
   * Baseband sync demodulation. The 1000/1200 sync signals are
1048
   * extracted using a 600-Hz IIR bandpass filter. This removes
1049
   * the 100-Hz data subcarrier, as well as the 440-Hz and 600-Hz
1050
   * tones and most of the noise and voice modulation components.
1051
   *
1052
   * Matlab 4th-order IIR elliptic, 800-1400 Hz bandpass, 0.2 dB
1053
   * passband ripple, -50 dB stopband ripple, phase delay 0.91 ms.
1054
   */
1055
0
  syncx = (bpf[8] = bpf[7]) * 4.897278e-01;
1056
0
  syncx += (bpf[7] = bpf[6]) * -2.765914e+00;
1057
0
  syncx += (bpf[6] = bpf[5]) * 8.110921e+00;
1058
0
  syncx += (bpf[5] = bpf[4]) * -1.517732e+01;
1059
0
  syncx += (bpf[4] = bpf[3]) * 1.975197e+01;
1060
0
  syncx += (bpf[3] = bpf[2]) * -1.814365e+01;
1061
0
  syncx += (bpf[2] = bpf[1]) * 1.159783e+01;
1062
0
  syncx += (bpf[1] = bpf[0]) * -4.735040e+00;
1063
0
  bpf[0] = isig - syncx;
1064
0
  syncx = bpf[0] * 8.203628e-03
1065
0
      + bpf[1] * -2.375732e-02
1066
0
      + bpf[2] * 3.353214e-02
1067
0
      + bpf[3] * -4.080258e-02
1068
0
      + bpf[4] * 4.605479e-02
1069
0
      + bpf[5] * -4.080258e-02
1070
0
      + bpf[6] * 3.353214e-02
1071
0
      + bpf[7] * -2.375732e-02
1072
0
      + bpf[8] * 8.203628e-03;
1073
1074
  /*
1075
   * The 1000/1200 sync signals are demodulated using a pair of
1076
   * quadrature multipliers and matched filters. However,
1077
   * synchronous demodulation at these frequencies is impractical,
1078
   * so only the signal amplitude is used. The I and Q quadrature
1079
   * sync signals are produced by multiplying the filtered signal
1080
   * by 1000-Hz (WWV) and 1200-Hz (WWVH) sine and cosine signals,
1081
   * respectively. The WWV and WWVH signals are processed by 800-
1082
   * ms synchronous matched filters and combined to produce the
1083
   * minute sync signal and detect which one (or both) the WWV or
1084
   * WWVH signal is present. The WWV and WWVH signals are also
1085
   * processed by 5-ms synchronous matched filters and combined to
1086
   * produce the second sync signal. The signals are scaled to
1087
   * produce unit energy at the maximum value.
1088
   *
1089
   * Note the master timing ramps, which run continuously. The
1090
   * minute counter (mphase) counts the samples in the minute,
1091
   * while the second counter (epoch) counts the samples in the
1092
   * second.
1093
   */
1094
0
  up->mphase = (up->mphase + 1) % WWV_MIN;
1095
0
  epoch = up->mphase % WWV_SEC;
1096
1097
  /*
1098
   * WWV
1099
   */
1100
0
  i = csinptr;
1101
0
  csinptr = (csinptr + IN1000) % 80;
1102
1103
0
  dtemp = sintab[i] * syncx / (MS / 2.);
1104
0
  ciamp -= cibuf[jptr];
1105
0
  cibuf[jptr] = dtemp;
1106
0
  ciamp += dtemp;
1107
0
  csiamp -= csibuf[kptr];
1108
0
  csibuf[kptr] = dtemp;
1109
0
  csiamp += dtemp;
1110
1111
0
  i = (i + 20) % 80;
1112
0
  dtemp = sintab[i] * syncx / (MS / 2.);
1113
0
  cqamp -= cqbuf[jptr];
1114
0
  cqbuf[jptr] = dtemp;
1115
0
  cqamp += dtemp;
1116
0
  csqamp -= csqbuf[kptr];
1117
0
  csqbuf[kptr] = dtemp;
1118
0
  csqamp += dtemp;
1119
1120
0
  sp = &up->mitig[up->achan].wwv;
1121
0
  sp->amp = sqrt(ciamp * ciamp + cqamp * cqamp) / SYNCYC;
1122
0
  if (!(up->status & MSYNC))
1123
0
    wwv_qrz(peer, sp, (int)(pp->fudgetime1 * WWV_SEC));
1124
1125
  /*
1126
   * WWVH
1127
   */
1128
0
  i = hsinptr;
1129
0
  hsinptr = (hsinptr + IN1200) % 80;
1130
1131
0
  dtemp = sintab[i] * syncx / (MS / 2.);
1132
0
  hiamp -= hibuf[jptr];
1133
0
  hibuf[jptr] = dtemp;
1134
0
  hiamp += dtemp;
1135
0
  hsiamp -= hsibuf[kptr];
1136
0
  hsibuf[kptr] = dtemp;
1137
0
  hsiamp += dtemp;
1138
1139
0
  i = (i + 20) % 80;
1140
0
  dtemp = sintab[i] * syncx / (MS / 2.);
1141
0
  hqamp -= hqbuf[jptr];
1142
0
  hqbuf[jptr] = dtemp;
1143
0
  hqamp += dtemp;
1144
0
  hsqamp -= hsqbuf[kptr];
1145
0
  hsqbuf[kptr] = dtemp;
1146
0
  hsqamp += dtemp;
1147
1148
0
  rp = &up->mitig[up->achan].wwvh;
1149
0
  rp->amp = sqrt(hiamp * hiamp + hqamp * hqamp) / SYNCYC;
1150
0
  if (!(up->status & MSYNC))
1151
0
    wwv_qrz(peer, rp, (int)(pp->fudgetime2 * WWV_SEC));
1152
0
  jptr = (jptr + 1) % SYNSIZ;
1153
0
  kptr = (kptr + 1) % TCKSIZ;
1154
1155
  /*
1156
   * The following section is called once per minute. It does
1157
   * housekeeping and timeout functions and empties the dustbins.
1158
   */
1159
0
  if (up->mphase == 0) {
1160
0
    up->watch++;
1161
0
    if (!(up->status & MSYNC)) {
1162
1163
      /*
1164
       * If minute sync has not been acquired before
1165
       * ACQSN timeout (6 min), or if no signal is
1166
       * heard, the program cycles to the next
1167
       * frequency and tries again.
1168
       */
1169
0
      if (!wwv_newchan(peer))
1170
0
        up->watch = 0;
1171
0
    } else {
1172
1173
      /*
1174
       * If the leap bit is set, set the minute epoch
1175
       * back one second so the station processes
1176
       * don't miss a beat.
1177
       */
1178
0
      if (up->status & LEPSEC) {
1179
0
        up->mphase -= WWV_SEC;
1180
0
        if (up->mphase < 0)
1181
0
          up->mphase += WWV_MIN;
1182
0
      }
1183
0
    }
1184
0
  }
1185
1186
  /*
1187
   * When the channel metric reaches threshold and the second
1188
   * counter matches the minute epoch within the second, the
1189
   * driver has synchronized to the station. The second number is
1190
   * the remaining seconds until the next minute epoch, while the
1191
   * sync epoch is zero. Watch out for the first second; if
1192
   * already synchronized to the second, the buffered sync epoch
1193
   * must be set.
1194
   *
1195
   * Note the guard interval is 200 ms; if for some reason the
1196
   * clock drifts more than that, it might wind up in the wrong
1197
   * second. If the maximum frequency error is not more than about
1198
   * 1 PPM, the clock can go as much as two days while still in
1199
   * the same second.
1200
   */
1201
0
  if (up->status & MSYNC) {
1202
0
    wwv_epoch(peer);
1203
0
  } else if (up->sptr != NULL) {
1204
0
    sp = up->sptr;
1205
0
    if (sp->metric >= TTHR && epoch == sp->mepoch % WWV_SEC)
1206
0
        {
1207
0
      up->rsec = (60 - sp->mepoch / WWV_SEC) % 60;
1208
0
      up->rphase = 0;
1209
0
      up->status |= MSYNC;
1210
0
      up->watch = 0;
1211
0
      if (!(up->status & SSYNC))
1212
0
        up->repoch = up->yepoch = epoch;
1213
0
      else
1214
0
        up->repoch = up->yepoch;
1215
      
1216
0
    }
1217
0
  }
1218
1219
  /*
1220
   * The second sync pulse is extracted using 5-ms (40 sample) FIR
1221
   * matched filters at 1000 Hz for WWV or 1200 Hz for WWVH. This
1222
   * pulse is used for the most precise synchronization, since if
1223
   * provides a resolution of one sample (125 us). The filters run
1224
   * only if the station has been reliably determined.
1225
   */
1226
0
  if (up->status & SELV)
1227
0
    mfsync = sqrt(csiamp * csiamp + csqamp * csqamp) /
1228
0
        TCKCYC;
1229
0
  else if (up->status & SELH)
1230
0
    mfsync = sqrt(hsiamp * hsiamp + hsqamp * hsqamp) /
1231
0
        TCKCYC;
1232
0
  else
1233
0
    mfsync = 0;
1234
1235
  /*
1236
   * Enhance the seconds sync pulse using a 1-s (8000-sample) comb
1237
   * filter. Correct for the FIR matched filter delay, which is 5
1238
   * ms for both the WWV and WWVH filters, and also for the
1239
   * propagation delay. Once each second look for second sync. If
1240
   * not in minute sync, fiddle the codec gain. Note the SNR is
1241
   * computed from the maximum sample and the envelope of the
1242
   * sample 6 ms before it, so if we slip more than a cycle the
1243
   * SNR should plummet. The signal is scaled to produce unit
1244
   * energy at the maximum value.
1245
   */
1246
0
  dtemp = (epobuf[epoch] += (mfsync - epobuf[epoch]) /
1247
0
      up->avgint);
1248
0
  if (dtemp > epomax) {
1249
0
    int j;
1250
1251
0
    epomax = dtemp;
1252
0
    epopos = epoch;
1253
0
    j = epoch - 6 * MS;
1254
0
    if (j < 0)
1255
0
      j += WWV_SEC;
1256
0
    nxtmax = fabs(epobuf[j]);
1257
0
  }
1258
0
  if (epoch == 0) {
1259
0
    up->epomax = epomax;
1260
0
    up->eposnr = wwv_snr(epomax, nxtmax);
1261
0
    epopos -= TCKCYC * MS;
1262
0
    if (epopos < 0)
1263
0
      epopos += WWV_SEC;
1264
0
    wwv_endpoc(peer, epopos);
1265
0
    if (!(up->status & SSYNC))
1266
0
      up->alarm |= SYNERR;
1267
0
    epomax = 0;
1268
0
    if (!(up->status & MSYNC))
1269
0
      wwv_gain(peer);
1270
0
  }
1271
0
}
1272
1273
1274
/*
1275
 * wwv_qrz - identify and acquire WWV/WWVH minute sync pulse
1276
 *
1277
 * This routine implements a virtual station process used to acquire
1278
 * minute sync and to mitigate among the ten frequency and station
1279
 * combinations. During minute sync acquisition the process probes each
1280
 * frequency and station in turn for the minute pulse, which
1281
 * involves searching through the entire 480,000-sample minute. The
1282
 * process finds the maximum signal and RMS noise plus signal. Then, the
1283
 * actual noise is determined by subtracting the energy of the matched
1284
 * filter.
1285
 *
1286
 * Students of radar receiver technology will discover this algorithm
1287
 * amounts to a range-gate discriminator. A valid pulse must have peak
1288
 * amplitude at least QTHR (2500) and SNR at least QSNR (20) dB and the
1289
 * difference between the current and previous epoch must be less than
1290
 * AWND (20 ms). Note that the discriminator peak occurs about 800 ms
1291
 * into the second, so the timing is retarded to the previous second
1292
 * epoch.
1293
 */
1294
static void
1295
wwv_qrz(
1296
  struct peer *peer,  /* peer structure pointer */
1297
  struct sync *sp,  /* sync channel structure */
1298
  int pdelay    /* propagation delay (samples) */
1299
  )
1300
0
{
1301
0
  struct refclockproc *pp;
1302
0
  struct wwvunit *up;
1303
0
  char  tbuf[TBUF]; /* monitor buffer */
1304
0
  long  epoch;
1305
1306
0
  pp = peer->procptr;
1307
0
  up = pp->unitptr;
1308
1309
  /*
1310
   * Find the sample with peak amplitude, which defines the minute
1311
   * epoch. Accumulate all samples to determine the total noise
1312
   * energy.
1313
   */
1314
0
  epoch = up->mphase - pdelay - SYNSIZ;
1315
0
  if (epoch < 0)
1316
0
    epoch += WWV_MIN;
1317
0
  if (sp->amp > sp->maxeng) {
1318
0
    sp->maxeng = sp->amp;
1319
0
    sp->pos = epoch;
1320
0
  }
1321
0
  sp->noieng += sp->amp;
1322
1323
  /*
1324
   * At the end of the minute, determine the epoch of the minute
1325
   * sync pulse, as well as the difference between the current and
1326
   * previous epoches due to the intrinsic frequency error plus
1327
   * jitter. When calculating the SNR, subtract the pulse energy
1328
   * from the total noise energy and then normalize.
1329
   */
1330
0
  if (up->mphase == 0) {
1331
0
    sp->synmax = sp->maxeng;
1332
0
    sp->synsnr = wwv_snr(sp->synmax, (sp->noieng -
1333
0
        sp->synmax) / WWV_MIN);
1334
0
    if (sp->count == 0)
1335
0
      sp->lastpos = sp->pos;
1336
0
    epoch = (sp->pos - sp->lastpos) % WWV_MIN;
1337
0
    sp->reach <<= 1;
1338
0
    if (sp->reach & (1 << AMAX))
1339
0
      sp->count--;
1340
0
    if (sp->synmax > ATHR && sp->synsnr > ASNR) {
1341
0
      if (labs(epoch) < AWND * MS) {
1342
0
        sp->reach |= 1;
1343
0
        sp->count++;
1344
0
        sp->mepoch = sp->lastpos = sp->pos;
1345
0
      } else if (sp->count == 1) {
1346
0
        sp->lastpos = sp->pos;
1347
0
      }
1348
0
    }
1349
0
    if (up->watch > ACQSN)
1350
0
      sp->metric = 0;
1351
0
    else
1352
0
      sp->metric = wwv_metric(sp);
1353
0
    if (pp->sloppyclockflag & CLK_FLAG4) {
1354
0
      snprintf(tbuf, sizeof(tbuf),
1355
0
          "wwv8 %04x %3d %s %04x %.0f %.0f/%.1f %ld %ld",
1356
0
          up->status, up->gain, sp->refid,
1357
0
          sp->reach & 0xffff, sp->metric, sp->synmax,
1358
0
          sp->synsnr, sp->pos % WWV_SEC, epoch);
1359
0
      record_clock_stats(&peer->srcadr, tbuf);
1360
0
#ifdef DEBUG
1361
0
      if (debug)
1362
0
        printf("%s\n", tbuf);
1363
0
#endif /* DEBUG */
1364
0
    }
1365
0
    sp->maxeng = sp->noieng = 0;
1366
0
  }
1367
0
}
1368
1369
1370
/*
1371
 * wwv_endpoc - identify and acquire second sync pulse
1372
 *
1373
 * This routine is called at the end of the second sync interval. It
1374
 * determines the second sync epoch position within the second and
1375
 * disciplines the sample clock using a frequency-lock loop (FLL).
1376
 *
1377
 * Second sync is determined in the RF input routine as the maximum
1378
 * over all 8000 samples in the second comb filter. To assure accurate
1379
 * and reliable time and frequency discipline, this routine performs a
1380
 * great deal of heavy-handed heuristic data filtering and grooming.
1381
 */
1382
static void
1383
wwv_endpoc(
1384
  struct peer *peer,  /* peer structure pointer */
1385
  int epopos    /* epoch max position */
1386
  )
1387
0
{
1388
0
  struct refclockproc *pp;
1389
0
  struct wwvunit *up;
1390
0
  static int epoch_mf[3]; /* epoch median filter */
1391
0
  static int tepoch;  /* current second epoch */
1392
0
  static int xepoch;  /* last second epoch */
1393
0
  static int zepoch;  /* last run epoch */
1394
0
  static int zcount;  /* last run end time */
1395
0
  static int scount;  /* seconds counter */
1396
0
  static int syncnt;  /* run length counter */
1397
0
  static int maxrun;  /* longest run length */
1398
0
  static int mepoch;  /* longest run end epoch */
1399
0
  static int mcount;  /* longest run end time */
1400
0
  static int avgcnt;  /* averaging interval counter */
1401
0
  static int avginc;  /* averaging ratchet */
1402
0
  static int iniflg;  /* initialization flag */
1403
0
  char tbuf[TBUF];    /* monitor buffer */
1404
0
  double dtemp;
1405
0
  int tmp2;
1406
1407
0
  pp = peer->procptr;
1408
0
  up = pp->unitptr;
1409
0
  if (!iniflg) {
1410
0
    iniflg = 1;
1411
0
    ZERO(epoch_mf);
1412
0
  }
1413
1414
  /*
1415
   * If the signal amplitude or SNR fall below thresholds, dim the
1416
   * second sync lamp and wait for hotter ions. If no stations are
1417
   * heard, we are either in a probe cycle or the ions are really
1418
   * cold. 
1419
   */
1420
0
  scount++;
1421
0
  if (up->epomax < STHR || up->eposnr < SSNR) {
1422
0
    up->status &= ~(SSYNC | FGATE);
1423
0
    avgcnt = syncnt = maxrun = 0;
1424
0
    return;
1425
0
  }
1426
0
  if (!(up->status & (SELV | SELH)))
1427
0
    return;
1428
1429
  /*
1430
   * A three-stage median filter is used to help denoise the
1431
   * second sync pulse. The median sample becomes the candidate
1432
   * epoch.
1433
   */
1434
0
  epoch_mf[2] = epoch_mf[1];
1435
0
  epoch_mf[1] = epoch_mf[0];
1436
0
  epoch_mf[0] = epopos;
1437
0
  if (epoch_mf[0] > epoch_mf[1]) {
1438
0
    if (epoch_mf[1] > epoch_mf[2])
1439
0
      tepoch = epoch_mf[1]; /* 0 1 2 */
1440
0
    else if (epoch_mf[2] > epoch_mf[0])
1441
0
      tepoch = epoch_mf[0]; /* 2 0 1 */
1442
0
    else
1443
0
      tepoch = epoch_mf[2]; /* 0 2 1 */
1444
0
  } else {
1445
0
    if (epoch_mf[1] < epoch_mf[2])
1446
0
      tepoch = epoch_mf[1]; /* 2 1 0 */
1447
0
    else if (epoch_mf[2] < epoch_mf[0])
1448
0
      tepoch = epoch_mf[0]; /* 1 0 2 */
1449
0
    else
1450
0
      tepoch = epoch_mf[2]; /* 1 2 0 */
1451
0
  }
1452
1453
1454
  /*
1455
   * If the epoch candidate is the same as the last one, increment
1456
   * the run counter. If not, save the length, epoch and end
1457
   * time of the current run for use later and reset the counter.
1458
   * The epoch is considered valid if the run is at least SCMP
1459
   * (10) s, the minute is synchronized and the interval since the
1460
   * last epoch  is not greater than the averaging interval. Thus,
1461
   * after a long absence, the program will wait a full averaging
1462
   * interval while the comb filter charges up and noise
1463
   * dissapates..
1464
   */
1465
0
  tmp2 = (tepoch - xepoch) % WWV_SEC;
1466
0
  if (tmp2 == 0) {
1467
0
    syncnt++;
1468
0
    if (syncnt > SCMP && up->status & MSYNC && (up->status &
1469
0
        FGATE || scount - zcount <= up->avgint)) {
1470
0
      up->status |= SSYNC;
1471
0
      up->yepoch = tepoch;
1472
0
    }
1473
0
  } else if (syncnt >= maxrun) {
1474
0
    maxrun = syncnt;
1475
0
    mcount = scount;
1476
0
    mepoch = xepoch;
1477
0
    syncnt = 0;
1478
0
  }
1479
0
  if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
1480
0
      MSYNC)) {
1481
0
    snprintf(tbuf, sizeof(tbuf),
1482
0
        "wwv1 %04x %3d %4d %5.0f %5.1f %5d %4d %4d %4d",
1483
0
        up->status, up->gain, tepoch, up->epomax,
1484
0
        up->eposnr, tmp2, avgcnt, syncnt,
1485
0
        maxrun);
1486
0
    record_clock_stats(&peer->srcadr, tbuf);
1487
0
#ifdef DEBUG
1488
0
    if (debug)
1489
0
      printf("%s\n", tbuf);
1490
0
#endif /* DEBUG */
1491
0
  }
1492
0
  avgcnt++;
1493
0
  if (avgcnt < up->avgint) {
1494
0
    xepoch = tepoch;
1495
0
    return;
1496
0
  }
1497
1498
  /*
1499
   * The sample clock frequency is disciplined using a first-order
1500
   * feedback loop with time constant consistent with the Allan
1501
   * intercept of typical computer clocks. During each averaging
1502
   * interval the candidate epoch at the end of the longest run is
1503
   * determined. If the longest run is zero, all epoches in the
1504
   * interval are different, so the candidate epoch is the current
1505
   * epoch. The frequency update is computed from the candidate
1506
   * epoch difference (125-us units) and time difference (seconds)
1507
   * between updates.
1508
   */
1509
0
  if (syncnt >= maxrun) {
1510
0
    maxrun = syncnt;
1511
0
    mcount = scount;
1512
0
    mepoch = xepoch;
1513
0
  }
1514
0
  xepoch = tepoch;
1515
0
  if (maxrun == 0) {
1516
0
    mepoch = tepoch;
1517
0
    mcount = scount;
1518
0
  }
1519
1520
  /*
1521
   * The master clock runs at the codec sample frequency of 8000
1522
   * Hz, so the intrinsic time resolution is 125 us. The frequency
1523
   * resolution ranges from 18 PPM at the minimum averaging
1524
   * interval of 8 s to 0.12 PPM at the maximum interval of 1024
1525
   * s. An offset update is determined at the end of the longest
1526
   * run in each averaging interval. The frequency adjustment is
1527
   * computed from the difference between offset updates and the
1528
   * interval between them.
1529
   *
1530
   * The maximum frequency adjustment ranges from 187 PPM at the
1531
   * minimum interval to 1.5 PPM at the maximum. If the adjustment
1532
   * exceeds the maximum, the update is discarded and the
1533
   * hysteresis counter is decremented. Otherwise, the frequency
1534
   * is incremented by the adjustment, but clamped to the maximum
1535
   * 187.5 PPM. If the update is less than half the maximum, the
1536
   * hysteresis counter is incremented. If the counter increments
1537
   * to +3, the averaging interval is doubled and the counter set
1538
   * to zero; if it decrements to -3, the interval is halved and
1539
   * the counter set to zero.
1540
   */
1541
0
  dtemp = (mepoch - zepoch) % WWV_SEC;
1542
0
  if (up->status & FGATE) {
1543
0
    if (fabs(dtemp) < MAXFREQ * MINAVG) {
1544
0
      up->freq += (dtemp / 2.) / ((mcount - zcount) *
1545
0
          FCONST);
1546
0
      if (up->freq > MAXFREQ)
1547
0
        up->freq = MAXFREQ;
1548
0
      else if (up->freq < -MAXFREQ)
1549
0
        up->freq = -MAXFREQ;
1550
0
      if (fabs(dtemp) < MAXFREQ * MINAVG / 2.) {
1551
0
        if (avginc < 3) {
1552
0
          avginc++;
1553
0
        } else {
1554
0
          if (up->avgint < MAXAVG) {
1555
0
            up->avgint <<= 1;
1556
0
            avginc = 0;
1557
0
          }
1558
0
        }
1559
0
      }
1560
0
    } else {
1561
0
      if (avginc > -3) {
1562
0
        avginc--;
1563
0
      } else {
1564
0
        if (up->avgint > MINAVG) {
1565
0
          up->avgint >>= 1;
1566
0
          avginc = 0;
1567
0
        }
1568
0
      }
1569
0
    }
1570
0
  }
1571
0
  if (pp->sloppyclockflag & CLK_FLAG4) {
1572
0
    snprintf(tbuf, sizeof(tbuf),
1573
0
        "wwv2 %04x %5.0f %5.1f %5d %4d %4d %4d %4.0f %7.2f",
1574
0
        up->status, up->epomax, up->eposnr, mepoch,
1575
0
        up->avgint, maxrun, mcount - zcount, dtemp,
1576
0
        up->freq * 1e6 / WWV_SEC);
1577
0
    record_clock_stats(&peer->srcadr, tbuf);
1578
0
#ifdef DEBUG
1579
0
    if (debug)
1580
0
      printf("%s\n", tbuf);
1581
0
#endif /* DEBUG */
1582
0
  }
1583
1584
  /*
1585
   * This is a valid update; set up for the next interval.
1586
   */
1587
0
  up->status |= FGATE;
1588
0
  zepoch = mepoch;
1589
0
  zcount = mcount;
1590
0
  avgcnt = syncnt = maxrun = 0;
1591
0
}
1592
1593
1594
/*
1595
 * wwv_epoch - epoch scanner
1596
 *
1597
 * This routine extracts data signals from the 100-Hz subcarrier. It
1598
 * scans the receiver second epoch to determine the signal amplitudes
1599
 * and pulse timings. Receiver synchronization is determined by the
1600
 * minute sync pulse detected in the wwv_rf() routine and the second
1601
 * sync pulse detected in the wwv_epoch() routine. The transmitted
1602
 * signals are delayed by the propagation delay, receiver delay and
1603
 * filter delay of this program. Delay corrections are introduced
1604
 * separately for WWV and WWVH. 
1605
 *
1606
 * Most communications radios use a highpass filter in the audio stages,
1607
 * which can do nasty things to the subcarrier phase relative to the
1608
 * sync pulses. Therefore, the data subcarrier reference phase is
1609
 * disciplined using the hardlimited quadrature-phase signal sampled at
1610
 * the same time as the in-phase signal. The phase tracking loop uses
1611
 * phase adjustments of plus-minus one sample (125 us). 
1612
 */
1613
static void
1614
wwv_epoch(
1615
  struct peer *peer /* peer structure pointer */
1616
  )
1617
0
{
1618
0
  struct refclockproc *pp;
1619
0
  struct wwvunit *up;
1620
0
  struct chan *cp;
1621
0
  static double sigmin, sigzer, sigone, engmax, engmin;
1622
1623
0
  pp = peer->procptr;
1624
0
  up = pp->unitptr;
1625
1626
  /*
1627
   * Find the maximum minute sync pulse energy for both the
1628
   * WWV and WWVH stations. This will be used later for channel
1629
   * and station mitigation. Also set the seconds epoch at 800 ms
1630
   * well before the end of the second to make sure we never set
1631
   * the epoch backwards.
1632
   */
1633
0
  cp = &up->mitig[up->achan];
1634
0
  if (cp->wwv.amp > cp->wwv.syneng) 
1635
0
    cp->wwv.syneng = cp->wwv.amp;
1636
0
  if (cp->wwvh.amp > cp->wwvh.syneng) 
1637
0
    cp->wwvh.syneng = cp->wwvh.amp;
1638
0
  if (up->rphase == 800 * MS)
1639
0
    up->repoch = up->yepoch;
1640
1641
  /*
1642
   * Use the signal amplitude at epoch 15 ms as the noise floor.
1643
   * This gives a guard time of +-15 ms from the beginning of the
1644
   * second until the second pulse rises at 30 ms. There is a
1645
   * compromise here; we want to delay the sample as long as
1646
   * possible to give the radio time to change frequency and the
1647
   * AGC to stabilize, but as early as possible if the second
1648
   * epoch is not exact.
1649
   */
1650
0
  if (up->rphase == 15 * MS)
1651
0
    sigmin = sigzer = sigone = up->irig;
1652
1653
  /*
1654
   * Latch the data signal at 200 ms. Keep this around until the
1655
   * end of the second. Use the signal energy as the peak to
1656
   * compute the SNR. Use the Q sample to adjust the 100-Hz
1657
   * reference oscillator phase.
1658
   */
1659
0
  if (up->rphase == 200 * MS) {
1660
0
    sigzer = up->irig;
1661
0
    engmax = sqrt(up->irig * up->irig + up->qrig *
1662
0
        up->qrig);
1663
0
    up->datpha = up->qrig / up->avgint;
1664
0
    if (up->datpha >= 0) {
1665
0
      up->datapt++;
1666
0
      if (up->datapt >= 80)
1667
0
        up->datapt -= 80;
1668
0
    } else {
1669
0
      up->datapt--;
1670
0
      if (up->datapt < 0)
1671
0
        up->datapt += 80;
1672
0
    }
1673
0
  }
1674
1675
1676
  /*
1677
   * Latch the data signal at 500 ms. Keep this around until the
1678
   * end of the second.
1679
   */
1680
0
  else if (up->rphase == 500 * MS)
1681
0
    sigone = up->irig;
1682
1683
  /*
1684
   * At the end of the second crank the clock state machine and
1685
   * adjust the codec gain. Note the epoch is buffered from the
1686
   * center of the second in order to avoid jitter while the
1687
   * seconds synch is diddling the epoch. Then, determine the true
1688
   * offset and update the median filter in the driver interface.
1689
   *
1690
   * Use the energy at the end of the second as the noise to
1691
   * compute the SNR for the data pulse. This gives a better
1692
   * measurement than the beginning of the second, especially when
1693
   * returning from the probe channel. This gives a guard time of
1694
   * 30 ms from the decay of the longest pulse to the rise of the
1695
   * next pulse.
1696
   */
1697
0
  up->rphase++;
1698
0
  if (up->mphase % WWV_SEC == up->repoch) {
1699
0
    up->status &= ~(DGATE | BGATE);
1700
0
    engmin = sqrt(up->irig * up->irig + up->qrig *
1701
0
        up->qrig);
1702
0
    up->datsig = engmax;
1703
0
    up->datsnr = wwv_snr(engmax, engmin);
1704
1705
    /*
1706
     * If the amplitude or SNR is below threshold, average a
1707
     * 0 in the the integrators; otherwise, average the
1708
     * bipolar signal. This is done to avoid noise polution.
1709
     */
1710
0
    if (engmax < DTHR || up->datsnr < DSNR) {
1711
0
      up->status |= DGATE;
1712
0
      wwv_rsec(peer, 0);
1713
0
    } else {
1714
0
      sigzer -= sigone;
1715
0
      sigone -= sigmin;
1716
0
      wwv_rsec(peer, sigone - sigzer);
1717
0
    }
1718
0
    if (up->status & (DGATE | BGATE))
1719
0
      up->errcnt++;
1720
0
    if (up->errcnt > MAXERR)
1721
0
      up->alarm |= LOWERR;
1722
0
    wwv_gain(peer);
1723
0
    cp = &up->mitig[up->achan];
1724
0
    cp->wwv.syneng = 0;
1725
0
    cp->wwvh.syneng = 0;
1726
0
    up->rphase = 0;
1727
0
  }
1728
0
}
1729
1730
1731
/*
1732
 * wwv_rsec - process receiver second
1733
 *
1734
 * This routine is called at the end of each receiver second to
1735
 * implement the per-second state machine. The machine assembles BCD
1736
 * digit bits, decodes miscellaneous bits and dances the leap seconds.
1737
 *
1738
 * Normally, the minute has 60 seconds numbered 0-59. If the leap
1739
 * warning bit is set, the last minute (1439) of 30 June (day 181 or 182
1740
 * for leap years) or 31 December (day 365 or 366 for leap years) is
1741
 * augmented by one second numbered 60. This is accomplished by
1742
 * extending the minute interval by one second and teaching the state
1743
 * machine to ignore it.
1744
 */
1745
static void
1746
wwv_rsec(
1747
  struct peer *peer,  /* peer structure pointer */
1748
  double bit
1749
  )
1750
0
{
1751
0
  static int iniflg;  /* initialization flag */
1752
0
  static double bcddld[4]; /* BCD data bits */
1753
0
  static double bitvec[61]; /* bit integrator for misc bits */
1754
0
  struct refclockproc *pp;
1755
0
  struct wwvunit *up;
1756
0
  struct chan *cp;
1757
0
  struct sync *sp, *rp;
1758
0
  char  tbuf[TBUF]; /* monitor buffer */
1759
0
  int sw, arg, nsec;
1760
1761
0
  pp = peer->procptr;
1762
0
  up = pp->unitptr;
1763
0
  if (!iniflg) {
1764
0
    iniflg = 1;
1765
0
    ZERO(bitvec);
1766
0
  }
1767
1768
  /*
1769
   * The bit represents the probability of a hit on zero (negative
1770
   * values), a hit on one (positive values) or a miss (zero
1771
   * value). The likelihood vector is the exponential average of
1772
   * these probabilities. Only the bits of this vector
1773
   * corresponding to the miscellaneous bits of the timecode are
1774
   * used, but it's easier to do them all. After that, crank the
1775
   * seconds state machine.
1776
   */
1777
0
  nsec = up->rsec;
1778
0
  up->rsec++;
1779
0
  bitvec[nsec] += (bit - bitvec[nsec]) / TCONST;
1780
0
  sw = progx[nsec].sw;
1781
0
  arg = progx[nsec].arg;
1782
1783
  /*
1784
   * The minute state machine. Fly off to a particular section as
1785
   * directed by the transition matrix and second number.
1786
   */
1787
0
  switch (sw) {
1788
1789
  /*
1790
   * Ignore this second.
1791
   */
1792
0
  case IDLE:     /* 9, 45-49 */
1793
0
    break;
1794
1795
  /*
1796
   * Probe channel stuff
1797
   *
1798
   * The WWV/H format contains data pulses in second 59 (position
1799
   * identifier) and second 1, but not in second 0. The minute
1800
   * sync pulse is contained in second 0. At the end of second 58
1801
   * QSY to the probe channel, which rotates in turn over all
1802
   * WWV/H frequencies. At the end of second 0 measure the minute
1803
   * sync pulse. At the end of second 1 measure the data pulse and
1804
   * QSY back to the data channel. Note that the actions commented
1805
   * here happen at the end of the second numbered as shown.
1806
   *
1807
   * At the end of second 0 save the minute sync amplitude latched
1808
   * at 800 ms as the signal later used to calculate the SNR. 
1809
   */
1810
0
  case SYNC2:     /* 0 */
1811
0
    cp = &up->mitig[up->achan];
1812
0
    cp->wwv.synmax = cp->wwv.syneng;
1813
0
    cp->wwvh.synmax = cp->wwvh.syneng;
1814
0
    break;
1815
1816
  /*
1817
   * At the end of second 1 use the minute sync amplitude latched
1818
   * at 800 ms as the noise to calculate the SNR. If the minute
1819
   * sync pulse and SNR are above thresholds and the data pulse
1820
   * amplitude and SNR are above thresolds, shift a 1 into the
1821
   * station reachability register; otherwise, shift a 0. The
1822
   * number of 1 bits in the last six intervals is a component of
1823
   * the channel metric computed by the wwv_metric() routine.
1824
   * Finally, QSY back to the data channel.
1825
   */
1826
0
  case SYNC3:     /* 1 */
1827
0
    cp = &up->mitig[up->achan];
1828
1829
    /*
1830
     * WWV station
1831
     */
1832
0
    sp = &cp->wwv;
1833
0
    sp->synsnr = wwv_snr(sp->synmax, sp->amp);
1834
0
    sp->reach <<= 1;
1835
0
    if (sp->reach & (1 << AMAX))
1836
0
      sp->count--;
1837
0
    if (sp->synmax >= QTHR && sp->synsnr >= QSNR &&
1838
0
        !(up->status & (DGATE | BGATE))) {
1839
0
      sp->reach |= 1;
1840
0
      sp->count++;
1841
0
    }
1842
0
    sp->metric = wwv_metric(sp);
1843
1844
    /*
1845
     * WWVH station
1846
     */
1847
0
    rp = &cp->wwvh;
1848
0
    rp->synsnr = wwv_snr(rp->synmax, rp->amp);
1849
0
    rp->reach <<= 1;
1850
0
    if (rp->reach & (1 << AMAX))
1851
0
      rp->count--;
1852
0
    if (rp->synmax >= QTHR && rp->synsnr >= QSNR &&
1853
0
        !(up->status & (DGATE | BGATE))) {
1854
0
      rp->reach |= 1;
1855
0
      rp->count++;
1856
0
    }
1857
0
    rp->metric = wwv_metric(rp);
1858
0
    if (pp->sloppyclockflag & CLK_FLAG4) {
1859
0
      snprintf(tbuf, sizeof(tbuf),
1860
0
          "wwv5 %04x %3d %4d %.0f/%.1f %.0f/%.1f %s %04x %.0f %.0f/%.1f %s %04x %.0f %.0f/%.1f",
1861
0
          up->status, up->gain, up->yepoch,
1862
0
          up->epomax, up->eposnr, up->datsig,
1863
0
          up->datsnr,
1864
0
          sp->refid, sp->reach & 0xffff,
1865
0
          sp->metric, sp->synmax, sp->synsnr,
1866
0
          rp->refid, rp->reach & 0xffff,
1867
0
          rp->metric, rp->synmax, rp->synsnr);
1868
0
      record_clock_stats(&peer->srcadr, tbuf);
1869
0
#ifdef DEBUG
1870
0
      if (debug)
1871
0
        printf("%s\n", tbuf);
1872
0
#endif /* DEBUG */
1873
0
    }
1874
0
    up->errcnt = up->digcnt = up->alarm = 0;
1875
1876
    /*
1877
     * If synchronized to a station, restart if no stations
1878
     * have been heard within the PANIC timeout (2 days). If
1879
     * not and the minute digit has been found, restart if
1880
     * not synchronized withing the SYNCH timeout (40 m). If
1881
     * not, restart if the unit digit has not been found
1882
     * within the DATA timeout (15 m).
1883
     */
1884
0
    if (up->status & INSYNC) {
1885
0
      if (up->watch > PANIC) {
1886
0
        wwv_newgame(peer);
1887
0
        return;
1888
0
      }
1889
0
    } else if (up->status & DSYNC) {
1890
0
      if (up->watch > SYNCH) {
1891
0
        wwv_newgame(peer);
1892
0
        return;
1893
0
      }
1894
0
    } else if (up->watch > DATA) {
1895
0
      wwv_newgame(peer);
1896
0
      return;
1897
0
    }
1898
0
    wwv_newchan(peer);
1899
0
    break;
1900
1901
  /*
1902
   * Save the bit probability in the BCD data vector at the index
1903
   * given by the argument. Bits not used in the digit are forced
1904
   * to zero.
1905
   */
1906
0
  case COEF1:     /* 4-7 */ 
1907
0
    bcddld[arg] = bit;
1908
0
    break;
1909
1910
0
  case COEF:     /* 10-13, 15-17, 20-23, 25-26,
1911
             30-33, 35-38, 40-41, 51-54 */
1912
0
    if (up->status & DSYNC) 
1913
0
      bcddld[arg] = bit;
1914
0
    else
1915
0
      bcddld[arg] = 0;
1916
0
    break;
1917
1918
0
  case COEF2:     /* 18, 27-28, 42-43 */
1919
0
    bcddld[arg] = 0;
1920
0
    break;
1921
1922
  /*
1923
   * Correlate coefficient vector with each valid digit vector and
1924
   * save in decoding matrix. We step through the decoding matrix
1925
   * digits correlating each with the coefficients and saving the
1926
   * greatest and the next lower for later SNR calculation.
1927
   */
1928
0
  case DECIM2:     /* 29 */
1929
0
    wwv_corr4(peer, &up->decvec[arg], bcddld, bcd2);
1930
0
    break;
1931
1932
0
  case DECIM3:     /* 44 */
1933
0
    wwv_corr4(peer, &up->decvec[arg], bcddld, bcd3);
1934
0
    break;
1935
1936
0
  case DECIM6:     /* 19 */
1937
0
    wwv_corr4(peer, &up->decvec[arg], bcddld, bcd6);
1938
0
    break;
1939
1940
0
  case DECIM9:     /* 8, 14, 24, 34, 39 */
1941
0
    wwv_corr4(peer, &up->decvec[arg], bcddld, bcd9);
1942
0
    break;
1943
1944
  /*
1945
   * Miscellaneous bits. If above the positive threshold, declare
1946
   * 1; if below the negative threshold, declare 0; otherwise
1947
   * raise the BGATE bit. The design is intended to avoid
1948
   * integrating noise under low SNR conditions.
1949
   */
1950
0
  case MSC20:     /* 55 */
1951
0
    wwv_corr4(peer, &up->decvec[YR + 1], bcddld, bcd9);
1952
    /* fall through */
1953
1954
0
  case MSCBIT:     /* 2-3, 50, 56-57 */
1955
0
    if (bitvec[nsec] > BTHR) {
1956
0
      if (!(up->misc & arg))
1957
0
        up->alarm |= CMPERR;
1958
0
      up->misc |= arg;
1959
0
    } else if (bitvec[nsec] < -BTHR) {
1960
0
      if (up->misc & arg)
1961
0
        up->alarm |= CMPERR;
1962
0
      up->misc &= ~arg;
1963
0
    } else {
1964
0
      up->status |= BGATE;
1965
0
    }
1966
0
    break;
1967
1968
  /*
1969
   * Save the data channel gain, then QSY to the probe channel and
1970
   * dim the seconds comb filters. The www_newchan() routine will
1971
   * light them back up.
1972
   */
1973
0
  case MSC21:     /* 58 */
1974
0
    if (bitvec[nsec] > BTHR) {
1975
0
      if (!(up->misc & arg))
1976
0
        up->alarm |= CMPERR;
1977
0
      up->misc |= arg;
1978
0
    } else if (bitvec[nsec] < -BTHR) {
1979
0
      if (up->misc & arg)
1980
0
        up->alarm |= CMPERR;
1981
0
      up->misc &= ~arg;
1982
0
    } else {
1983
0
      up->status |= BGATE;
1984
0
    }
1985
0
    up->status &= ~(SELV | SELH);
1986
0
#ifdef ICOM
1987
0
    if (up->fd_icom > 0) {
1988
0
      up->schan = (up->schan + 1) % NCHAN;
1989
0
      wwv_qsy(peer, up->schan);
1990
0
    } else {
1991
0
      up->mitig[up->achan].gain = up->gain;
1992
0
    }
1993
#else
1994
    up->mitig[up->achan].gain = up->gain;
1995
#endif /* ICOM */
1996
0
    break;
1997
1998
  /*
1999
   * The endgames
2000
   *
2001
   * During second 59 the receiver and codec AGC are settling
2002
   * down, so the data pulse is unusable as quality metric. If
2003
   * LEPSEC is set on the last minute of 30 June or 31 December,
2004
   * the transmitter and receiver insert an extra second (60) in
2005
   * the timescale and the minute sync repeats the second. Once
2006
   * leaps occurred at intervals of about 18 months, but the last
2007
   * leap before the most recent leap in 1995 was in  1998.
2008
   */
2009
0
  case MIN1:     /* 59 */
2010
0
    if (up->status & LEPSEC)
2011
0
      break;
2012
2013
    /* fall through */
2014
2015
0
  case MIN2:     /* 60 */
2016
0
    up->status &= ~LEPSEC;
2017
0
    wwv_tsec(peer);
2018
0
    up->rsec = 0;
2019
0
    wwv_clock(peer);
2020
0
    break;
2021
0
  }
2022
0
  if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
2023
0
      DSYNC)) {
2024
0
    snprintf(tbuf, sizeof(tbuf),
2025
0
        "wwv3 %2d %04x %3d %4d %5.0f %5.1f %5.0f %5.1f %5.0f",
2026
0
        nsec, up->status, up->gain, up->yepoch, up->epomax,
2027
0
        up->eposnr, up->datsig, up->datsnr, bit);
2028
0
    record_clock_stats(&peer->srcadr, tbuf);
2029
0
#ifdef DEBUG
2030
0
    if (debug)
2031
0
      printf("%s\n", tbuf);
2032
0
#endif /* DEBUG */
2033
0
  }
2034
0
  pp->disp += AUDIO_PHI;
2035
0
}
2036
2037
/*
2038
 * The radio clock is set if the alarm bits are all zero. After that,
2039
 * the time is considered valid if the second sync bit is lit. It should
2040
 * not be a surprise, especially if the radio is not tunable, that
2041
 * sometimes no stations are above the noise and the integrators
2042
 * discharge below the thresholds. We assume that, after a day of signal
2043
 * loss, the minute sync epoch will be in the same second. This requires
2044
 * the codec frequency be accurate within 6 PPM. Practical experience
2045
 * shows the frequency typically within 0.1 PPM, so after a day of
2046
 * signal loss, the time should be within 8.6 ms.. 
2047
 */
2048
static void
2049
wwv_clock(
2050
  struct peer *peer /* peer unit pointer */
2051
  )
2052
0
{
2053
0
  struct refclockproc *pp;
2054
0
  struct wwvunit *up;
2055
0
  l_fp  offset;   /* offset in NTP seconds */
2056
2057
0
  pp = peer->procptr;
2058
0
  up = pp->unitptr;
2059
0
  if (!(up->status & SSYNC))
2060
0
    up->alarm |= SYNERR;
2061
0
  if (up->digcnt < 9)
2062
0
    up->alarm |= NINERR;
2063
0
  if (!(up->alarm))
2064
0
    up->status |= INSYNC;
2065
0
  if (up->status & INSYNC && up->status & SSYNC) {
2066
0
    if (up->misc & SECWAR)
2067
0
      pp->leap = LEAP_ADDSECOND;
2068
0
    else
2069
0
      pp->leap = LEAP_NOWARNING;
2070
0
    pp->second = up->rsec;
2071
0
    pp->minute = up->decvec[MN].digit + up->decvec[MN +
2072
0
        1].digit * 10;
2073
0
    pp->hour = up->decvec[HR].digit + up->decvec[HR +
2074
0
        1].digit * 10;
2075
0
    pp->day = up->decvec[DA].digit + up->decvec[DA +
2076
0
        1].digit * 10 + up->decvec[DA + 2].digit * 100;
2077
0
    pp->year = up->decvec[YR].digit + up->decvec[YR +
2078
0
        1].digit * 10;
2079
0
    pp->year += 2000;
2080
0
    L_CLR(&offset);
2081
0
    if (!clocktime(pp->day, pp->hour, pp->minute,
2082
0
        pp->second, GMT, up->timestamp.l_ui,
2083
0
        &pp->yearstart, &offset.l_ui)) {
2084
0
      up->errflg = CEVNT_BADTIME;
2085
0
    } else {
2086
0
      up->watch = 0;
2087
0
      pp->disp = 0;
2088
0
      pp->lastref = up->timestamp;
2089
0
      refclock_process_offset(pp, offset,
2090
0
          up->timestamp, PDELAY + up->pdelay);
2091
0
      refclock_receive(peer);
2092
0
    }
2093
0
  }
2094
0
  pp->lencode = timecode(up, pp->a_lastcode,
2095
0
             sizeof(pp->a_lastcode));
2096
0
  record_clock_stats(&peer->srcadr, pp->a_lastcode);
2097
0
#ifdef DEBUG
2098
0
  if (debug)
2099
0
    printf("wwv: timecode %d %s\n", pp->lencode,
2100
0
        pp->a_lastcode);
2101
0
#endif /* DEBUG */
2102
0
}
2103
2104
2105
/*
2106
 * wwv_corr4 - determine maximum-likelihood digit
2107
 *
2108
 * This routine correlates the received digit vector with the BCD
2109
 * coefficient vectors corresponding to all valid digits at the given
2110
 * position in the decoding matrix. The maximum value corresponds to the
2111
 * maximum-likelihood digit, while the ratio of this value to the next
2112
 * lower value determines the likelihood function. Note that, if the
2113
 * digit is invalid, the likelihood vector is averaged toward a miss.
2114
 */
2115
static void
2116
wwv_corr4(
2117
  struct peer *peer,  /* peer unit pointer */
2118
  struct decvec *vp,  /* decoding table pointer */
2119
  double  data[],   /* received data vector */
2120
  double  tab[][4]  /* correlation vector array */
2121
  )
2122
0
{
2123
0
  struct refclockproc *pp;
2124
0
  struct wwvunit *up;
2125
0
  double  topmax, nxtmax; /* metrics */
2126
0
  double  acc;    /* accumulator */
2127
0
  char  tbuf[TBUF]; /* monitor buffer */
2128
0
  int mldigit;  /* max likelihood digit */
2129
0
  int i, j;
2130
2131
0
  pp = peer->procptr;
2132
0
  up = pp->unitptr;
2133
2134
  /*
2135
   * Correlate digit vector with each BCD coefficient vector. If
2136
   * any BCD digit bit is bad, consider all bits a miss. Until the
2137
   * minute units digit has been resolved, don't to anything else.
2138
   * Note the SNR is calculated as the ratio of the largest
2139
   * likelihood value to the next largest likelihood value.
2140
   */
2141
0
  mldigit = 0;
2142
0
  topmax = nxtmax = -MAXAMP;
2143
0
  for (i = 0; tab[i][0] != 0; i++) {
2144
0
    acc = 0;
2145
0
    for (j = 0; j < 4; j++)
2146
0
      acc += data[j] * tab[i][j];
2147
0
    acc = (vp->like[i] += (acc - vp->like[i]) / TCONST);
2148
0
    if (acc > topmax) {
2149
0
      nxtmax = topmax;
2150
0
      topmax = acc;
2151
0
      mldigit = i;
2152
0
    } else if (acc > nxtmax) {
2153
0
      nxtmax = acc;
2154
0
    }
2155
0
  }
2156
0
  vp->digprb = topmax;
2157
0
  vp->digsnr = wwv_snr(topmax, nxtmax);
2158
2159
  /*
2160
   * The current maximum-likelihood digit is compared to the last
2161
   * maximum-likelihood digit. If different, the compare counter
2162
   * and maximum-likelihood digit are reset.  When the compare
2163
   * counter reaches the BCMP threshold (3), the digit is assumed
2164
   * correct. When the compare counter of all nine digits have
2165
   * reached threshold, the clock is assumed correct.
2166
   *
2167
   * Note that the clock display digit is set before the compare
2168
   * counter has reached threshold; however, the clock display is
2169
   * not considered correct until all nine clock digits have
2170
   * reached threshold. This is intended as eye candy, but avoids
2171
   * mistakes when the signal is low and the SNR is very marginal.
2172
   */
2173
0
  if (vp->digprb < BTHR || vp->digsnr < BSNR) {
2174
0
    up->status |= BGATE;
2175
0
  } else {
2176
0
    if (vp->digit != mldigit) {
2177
0
      up->alarm |= CMPERR;
2178
0
      if (vp->count > 0)
2179
0
        vp->count--;
2180
0
      if (vp->count == 0)
2181
0
        vp->digit = mldigit;
2182
0
    } else {
2183
0
      if (vp->count < BCMP)
2184
0
        vp->count++;
2185
0
      if (vp->count == BCMP) {
2186
0
        up->status |= DSYNC;
2187
0
        up->digcnt++;
2188
0
      }
2189
0
    }
2190
0
  }
2191
0
  if ((pp->sloppyclockflag & CLK_FLAG4) && !(up->status &
2192
0
      INSYNC)) {
2193
0
    snprintf(tbuf, sizeof(tbuf),
2194
0
        "wwv4 %2d %04x %3d %4d %5.0f %2d %d %d %d %5.0f %5.1f",
2195
0
        up->rsec - 1, up->status, up->gain, up->yepoch,
2196
0
        up->epomax, vp->radix, vp->digit, mldigit,
2197
0
        vp->count, vp->digprb, vp->digsnr);
2198
0
    record_clock_stats(&peer->srcadr, tbuf);
2199
0
#ifdef DEBUG
2200
0
    if (debug)
2201
0
      printf("%s\n", tbuf);
2202
0
#endif /* DEBUG */
2203
0
  }
2204
0
}
2205
2206
2207
/*
2208
 * wwv_tsec - transmitter minute processing
2209
 *
2210
 * This routine is called at the end of the transmitter minute. It
2211
 * implements a state machine that advances the logical clock subject to
2212
 * the funny rules that govern the conventional clock and calendar.
2213
 */
2214
static void
2215
wwv_tsec(
2216
  struct peer *peer /* driver structure pointer */
2217
  )
2218
0
{
2219
0
  struct refclockproc *pp;
2220
0
  struct wwvunit *up;
2221
0
  int minute, day, isleap;
2222
0
  int temp;
2223
2224
0
  pp = peer->procptr;
2225
0
  up = pp->unitptr;
2226
2227
  /*
2228
   * Advance minute unit of the day. Don't propagate carries until
2229
   * the unit minute digit has been found.
2230
   */
2231
0
  temp = carry(&up->decvec[MN]); /* minute units */
2232
0
  if (!(up->status & DSYNC))
2233
0
    return;
2234
2235
  /*
2236
   * Propagate carries through the day.
2237
   */ 
2238
0
  if (temp == 0)     /* carry minutes */
2239
0
    temp = carry(&up->decvec[MN + 1]);
2240
0
  if (temp == 0)     /* carry hours */
2241
0
    temp = carry(&up->decvec[HR]);
2242
0
  if (temp == 0)
2243
0
    temp = carry(&up->decvec[HR + 1]);
2244
  // XXX: Does temp have an expected value here?
2245
2246
  /*
2247
   * Decode the current minute and day. Set leap day if the
2248
   * timecode leap bit is set on 30 June or 31 December. Set leap
2249
   * minute if the last minute on leap day, but only if the clock
2250
   * is syncrhronized. This code fails in 2400 AD.
2251
   */
2252
0
  minute = up->decvec[MN].digit + up->decvec[MN + 1].digit *
2253
0
      10 + up->decvec[HR].digit * 60 + up->decvec[HR +
2254
0
      1].digit * 600;
2255
0
  day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
2256
0
      up->decvec[DA + 2].digit * 100;
2257
2258
  /*
2259
   * Set the leap bit on the last minute of the leap day.
2260
   */
2261
0
  isleap = up->decvec[YR].digit & 0x3;
2262
0
  if (up->misc & SECWAR && up->status & INSYNC) {
2263
0
    if ((day == (isleap ? 182 : 183) || day == (isleap ?
2264
0
        365 : 366)) && minute == 1439)
2265
0
      up->status |= LEPSEC;
2266
0
  }
2267
2268
  /*
2269
   * Roll the day if this the first minute and propagate carries
2270
   * through the year.
2271
   */
2272
0
  if (minute != 1440)
2273
0
    return;
2274
2275
  // minute = 0;
2276
0
  while (carry(&up->decvec[HR]) != 0); /* advance to minute 0 */
2277
0
  while (carry(&up->decvec[HR + 1]) != 0);
2278
0
  day++;
2279
0
  temp = carry(&up->decvec[DA]); /* carry days */
2280
0
  if (temp == 0)
2281
0
    temp = carry(&up->decvec[DA + 1]);
2282
0
  if (temp == 0)
2283
0
    temp = carry(&up->decvec[DA + 2]);
2284
  // XXX: Is there an expected value of temp here?
2285
2286
  /*
2287
   * Roll the year if this the first day and propagate carries
2288
   * through the century.
2289
   */
2290
0
  if (day != (isleap ? 365 : 366))
2291
0
    return;
2292
2293
  // day = 1;
2294
0
  while (carry(&up->decvec[DA]) != 1); /* advance to day 1 */
2295
0
  while (carry(&up->decvec[DA + 1]) != 0);
2296
0
  while (carry(&up->decvec[DA + 2]) != 0);
2297
0
  temp = carry(&up->decvec[YR]); /* carry years */
2298
0
  if (temp == 0)
2299
0
    carry(&up->decvec[YR + 1]);
2300
0
}
2301
2302
2303
/*
2304
 * carry - process digit
2305
 *
2306
 * This routine rotates a likelihood vector one position and increments
2307
 * the clock digit modulo the radix. It returns the new clock digit or
2308
 * zero if a carry occurred. Once synchronized, the clock digit will
2309
 * match the maximum-likelihood digit corresponding to that position.
2310
 */
2311
static int
2312
carry(
2313
  struct decvec *dp /* decoding table pointer */
2314
  )
2315
0
{
2316
0
  int temp;
2317
0
  int j;
2318
2319
0
  dp->digit++;
2320
0
  if (dp->digit == dp->radix)
2321
0
    dp->digit = 0;
2322
0
  temp = dp->like[dp->radix - 1];
2323
0
  for (j = dp->radix - 1; j > 0; j--)
2324
0
    dp->like[j] = dp->like[j - 1];
2325
0
  dp->like[0] = temp;
2326
0
  return (dp->digit);
2327
0
}
2328
2329
2330
/*
2331
 * wwv_snr - compute SNR or likelihood function
2332
 */
2333
static double
2334
wwv_snr(
2335
  double signal,    /* signal */
2336
  double noise    /* noise */
2337
  )
2338
0
{
2339
0
  double rval;
2340
2341
  /*
2342
   * This is a little tricky. Due to the way things are measured,
2343
   * either or both the signal or noise amplitude can be negative
2344
   * or zero. The intent is that, if the signal is negative or
2345
   * zero, the SNR must always be zero. This can happen with the
2346
   * subcarrier SNR before the phase has been aligned. On the
2347
   * other hand, in the likelihood function the "noise" is the
2348
   * next maximum down from the peak and this could be negative.
2349
   * However, in this case the SNR is truly stupendous, so we
2350
   * simply cap at MAXSNR dB (40).
2351
   */
2352
0
  if (signal <= 0) {
2353
0
    rval = 0;
2354
0
  } else if (noise <= 0) {
2355
0
    rval = MAXSNR;
2356
0
  } else {
2357
0
    rval = 20. * log10(signal / noise);
2358
0
    if (rval > MAXSNR)
2359
0
      rval = MAXSNR;
2360
0
  }
2361
0
  return (rval);
2362
0
}
2363
2364
2365
/*
2366
 * wwv_newchan - change to new data channel
2367
 *
2368
 * The radio actually appears to have ten channels, one channel for each
2369
 * of five frequencies and each of two stations (WWV and WWVH), although
2370
 * if not tunable only the DCHAN channel appears live. While the radio
2371
 * is tuned to the working data channel frequency and station for most
2372
 * of the minute, during seconds 59, 0 and 1 the radio is tuned to a
2373
 * probe frequency in order to search for minute sync pulse and data
2374
 * subcarrier from other transmitters.
2375
 *
2376
 * The search for WWV and WWVH operates simultaneously, with WWV minute
2377
 * sync pulse at 1000 Hz and WWVH at 1200 Hz. The probe frequency
2378
 * rotates each minute over 2.5, 5, 10, 15 and 20 MHz in order and yes,
2379
 * we all know WWVH is dark on 20 MHz, but few remember when WWV was lit
2380
 * on 25 MHz.
2381
 *
2382
 * This routine selects the best channel using a metric computed from
2383
 * the reachability register and minute pulse amplitude. Normally, the
2384
 * award goes to the the channel with the highest metric; but, in case
2385
 * of ties, the award goes to the channel with the highest minute sync
2386
 * pulse amplitude and then to the highest frequency.
2387
 *
2388
 * The routine performs an important squelch function to keep dirty data
2389
 * from polluting the integrators. In order to consider a station valid,
2390
 * the metric must be at least MTHR (13); otherwise, the station select
2391
 * bits are cleared so the second sync is disabled and the data bit
2392
 * integrators averaged to a miss. 
2393
 */
2394
static int
2395
wwv_newchan(
2396
  struct peer *peer /* peer structure pointer */
2397
  )
2398
0
{
2399
0
  struct refclockproc *pp;
2400
0
  struct wwvunit *up;
2401
0
  struct sync *sp, *rp;
2402
0
  double rank, dtemp;
2403
0
  int i, j, rval;
2404
2405
0
  pp = peer->procptr;
2406
0
  up = pp->unitptr;
2407
2408
  /*
2409
   * Search all five station pairs looking for the channel with
2410
   * maximum metric.
2411
   */
2412
0
  sp = NULL;
2413
0
  j = 0;
2414
0
  rank = 0;
2415
0
  for (i = 0; i < NCHAN; i++) {
2416
0
    rp = &up->mitig[i].wwvh;
2417
0
    dtemp = rp->metric;
2418
0
    if (dtemp >= rank) {
2419
0
      rank = dtemp;
2420
0
      sp = rp;
2421
0
      j = i;
2422
0
    }
2423
0
    rp = &up->mitig[i].wwv;
2424
0
    dtemp = rp->metric;
2425
0
    if (dtemp >= rank) {
2426
0
      rank = dtemp;
2427
0
      sp = rp;
2428
0
      j = i;
2429
0
    }
2430
0
  }
2431
2432
  /*
2433
   * If the strongest signal is less than the MTHR threshold (13),
2434
   * we are beneath the waves, so squelch the second sync and
2435
   * advance to the next station. This makes sure all stations are
2436
   * scanned when the ions grow dim. If the strongest signal is
2437
   * greater than the threshold, tune to that frequency and
2438
   * transmitter QTH.
2439
   */
2440
0
  up->status &= ~(SELV | SELH);
2441
0
  if (rank < MTHR) {
2442
0
    up->dchan = (up->dchan + 1) % NCHAN;
2443
0
    if (up->status & METRIC) {
2444
0
      up->status &= ~METRIC;
2445
0
      refclock_report(peer, CEVNT_PROP);
2446
0
    }
2447
0
    rval = FALSE;
2448
0
  } else {
2449
0
    up->dchan = j;
2450
0
    up->sptr = sp;
2451
0
    memcpy(&pp->refid, sp->refid, 4);
2452
0
    peer->refid = pp->refid;
2453
0
    up->status |= METRIC;
2454
0
    if (sp->select & SELV) {
2455
0
      up->status |= SELV;
2456
0
      up->pdelay = pp->fudgetime1;
2457
0
    } else if (sp->select & SELH) {
2458
0
      up->status |= SELH;
2459
0
      up->pdelay = pp->fudgetime2;
2460
0
    } else {
2461
0
      up->pdelay = 0;
2462
0
    }
2463
0
    rval = TRUE;
2464
0
  }
2465
0
#ifdef ICOM
2466
0
  if (up->fd_icom > 0)
2467
0
    wwv_qsy(peer, up->dchan);
2468
0
#endif /* ICOM */
2469
0
  return (rval);
2470
0
}
2471
2472
2473
/*
2474
 * wwv_newgame - reset and start over
2475
 *
2476
 * There are three conditions resulting in a new game:
2477
 *
2478
 * 1  After finding the minute pulse (MSYNC lit), going 15 minutes
2479
 *  (DATA) without finding the unit seconds digit.
2480
 *
2481
 * 2  After finding good data (DSYNC lit), going more than 40 minutes
2482
 *  (SYNCH) without finding station sync (INSYNC lit).
2483
 *
2484
 * 3  After finding station sync (INSYNC lit), going more than 2 days
2485
 *  (PANIC) without finding any station. 
2486
 */
2487
static void
2488
wwv_newgame(
2489
  struct peer *peer /* peer structure pointer */
2490
  )
2491
0
{
2492
0
  struct refclockproc *pp;
2493
0
  struct wwvunit *up;
2494
0
  struct chan *cp;
2495
0
  int i;
2496
2497
0
  pp = peer->procptr;
2498
0
  up = pp->unitptr;
2499
2500
  /*
2501
   * Initialize strategic values. Note we set the leap bits
2502
   * NOTINSYNC and the refid "NONE".
2503
   */
2504
0
  if (up->status)
2505
0
    up->errflg = CEVNT_TIMEOUT;
2506
0
  peer->leap = LEAP_NOTINSYNC;
2507
0
  up->watch = up->status = up->alarm = 0;
2508
0
  up->avgint = MINAVG;
2509
0
  up->freq = 0;
2510
0
  up->gain = MAXGAIN / 2;
2511
2512
  /*
2513
   * Initialize the station processes for audio gain, select bit,
2514
   * station/frequency identifier and reference identifier. Start
2515
   * probing at the strongest channel or the default channel if
2516
   * nothing heard.
2517
   */
2518
0
  memset(up->mitig, 0, sizeof(up->mitig));
2519
0
  for (i = 0; i < NCHAN; i++) {
2520
0
    cp = &up->mitig[i];
2521
0
    cp->gain = up->gain;
2522
0
    cp->wwv.select = SELV;
2523
0
    snprintf(cp->wwv.refid, sizeof(cp->wwv.refid), "WV%.0f",
2524
0
        floor(qsy[i])); 
2525
0
    cp->wwvh.select = SELH;
2526
0
    snprintf(cp->wwvh.refid, sizeof(cp->wwvh.refid), "WH%.0f",
2527
0
        floor(qsy[i])); 
2528
0
  }
2529
0
  up->dchan = (DCHAN + NCHAN - 1) % NCHAN;
2530
0
  wwv_newchan(peer);
2531
0
  up->schan = up->dchan;
2532
0
}
2533
2534
/*
2535
 * wwv_metric - compute station metric
2536
 *
2537
 * The most significant bits represent the number of ones in the
2538
 * station reachability register. The least significant bits represent
2539
 * the minute sync pulse amplitude. The combined value is scaled 0-100.
2540
 */
2541
double
2542
wwv_metric(
2543
  struct sync *sp   /* station pointer */
2544
  )
2545
0
{
2546
0
  double  dtemp;
2547
2548
0
  dtemp = sp->count * MAXAMP;
2549
0
  if (sp->synmax < MAXAMP)
2550
0
    dtemp += sp->synmax;
2551
0
  else
2552
0
    dtemp += MAXAMP - 1;
2553
0
  dtemp /= (AMAX + 1) * MAXAMP;
2554
0
  return (dtemp * 100.);
2555
0
}
2556
2557
2558
#ifdef ICOM
2559
/*
2560
 * wwv_qsy - Tune ICOM receiver
2561
 *
2562
 * This routine saves the AGC for the current channel, switches to a new
2563
 * channel and restores the AGC for that channel. If a tunable receiver
2564
 * is not available, just fake it.
2565
 */
2566
static int
2567
wwv_qsy(
2568
  struct peer *peer,  /* peer structure pointer */
2569
  int chan    /* channel */
2570
  )
2571
0
{
2572
0
  int rval = 0;
2573
0
  struct refclockproc *pp;
2574
0
  struct wwvunit *up;
2575
2576
0
  pp = peer->procptr;
2577
0
  up = pp->unitptr;
2578
0
  if (up->fd_icom > 0) {
2579
0
    up->mitig[up->achan].gain = up->gain;
2580
0
    rval = icom_freq(up->fd_icom, peer->ttl & 0x7f,
2581
0
        qsy[chan]);
2582
0
    up->achan = chan;
2583
0
    up->gain = up->mitig[up->achan].gain;
2584
0
  }
2585
0
  return (rval);
2586
0
}
2587
#endif /* ICOM */
2588
2589
2590
/*
2591
 * timecode - assemble timecode string and length
2592
 *
2593
 * Prettytime format - similar to Spectracom
2594
 *
2595
 * sq yy ddd hh:mm:ss ld dut lset agc iden sig errs freq avgt
2596
 *
2597
 * s  sync indicator ('?' or ' ')
2598
 * q  error bits (hex 0-F)
2599
 * yyyy year of century
2600
 * ddd  day of year
2601
 * hh hour of day
2602
 * mm minute of hour
2603
 * ss second of minute)
2604
 * l  leap second warning (' ' or 'L')
2605
 * d  DST state ('S', 'D', 'I', or 'O')
2606
 * dut  DUT sign and magnitude (0.1 s)
2607
 * lset minutes since last clock update
2608
 * agc  audio gain (0-255)
2609
 * iden reference identifier (station and frequency)
2610
 * sig  signal quality (0-100)
2611
 * errs bit errors in last minute
2612
 * freq frequency offset (PPM)
2613
 * avgt averaging time (s)
2614
 */
2615
static int
2616
timecode(
2617
  struct wwvunit *up, /* driver structure pointer */
2618
  char *    tc, /* target string */
2619
  size_t    tcsiz /* target max chars */
2620
  )
2621
0
{
2622
0
  struct sync *sp;
2623
0
  int year, day, hour, minute, second, dut;
2624
0
  char synchar, leapchar, dst;
2625
0
  char cptr[50];
2626
  
2627
2628
  /*
2629
   * Common fixed-format fields
2630
   */
2631
0
  synchar = (up->status & INSYNC) ? ' ' : '?';
2632
0
  year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 +
2633
0
      2000;
2634
0
  day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 +
2635
0
      up->decvec[DA + 2].digit * 100;
2636
0
  hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10;
2637
0
  minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10;
2638
0
  second = 0;
2639
0
  leapchar = (up->misc & SECWAR) ? 'L' : ' ';
2640
0
  dst = dstcod[(up->misc >> 4) & 0x3];
2641
0
  dut = up->misc & 0x7;
2642
0
  if (!(up->misc & DUTS))
2643
0
    dut = -dut;
2644
0
  snprintf(tc, tcsiz, "%c%1X", synchar, up->alarm);
2645
0
  snprintf(cptr, sizeof(cptr),
2646
0
     " %4d %03d %02d:%02d:%02d %c%c %+d",
2647
0
     year, day, hour, minute, second, leapchar, dst, dut);
2648
0
  strlcat(tc, cptr, tcsiz);
2649
2650
  /*
2651
   * Specific variable-format fields
2652
   */
2653
0
  sp = up->sptr;
2654
0
  snprintf(cptr, sizeof(cptr), " %d %d %s %.0f %d %.1f %d",
2655
0
     up->watch, up->mitig[up->dchan].gain, sp->refid,
2656
0
     sp->metric, up->errcnt, up->freq / WWV_SEC * 1e6,
2657
0
     up->avgint);
2658
0
  strlcat(tc, cptr, tcsiz);
2659
2660
0
  return strlen(tc);
2661
0
}
2662
2663
2664
/*
2665
 * wwv_gain - adjust codec gain
2666
 *
2667
 * This routine is called at the end of each second. During the second
2668
 * the number of signal clips above the MAXAMP threshold (6000). If
2669
 * there are no clips, the gain is bumped up; if there are more than
2670
 * MAXCLP clips (100), it is bumped down. The decoder is relatively
2671
 * insensitive to amplitude, so this crudity works just peachy. The
2672
 * routine also jiggles the input port and selectively mutes the
2673
 * monitor.
2674
 */
2675
static void
2676
wwv_gain(
2677
  struct peer *peer /* peer structure pointer */
2678
  )
2679
0
{
2680
0
  struct refclockproc *pp;
2681
0
  struct wwvunit *up;
2682
2683
0
  pp = peer->procptr;
2684
0
  up = pp->unitptr;
2685
2686
  /*
2687
   * Apparently, the codec uses only the high order bits of the
2688
   * gain control field. Thus, it may take awhile for changes to
2689
   * wiggle the hardware bits.
2690
   */
2691
0
  if (up->clipcnt == 0) {
2692
0
    up->gain += 4;
2693
0
    if (up->gain > MAXGAIN)
2694
0
      up->gain = MAXGAIN;
2695
0
  } else if (up->clipcnt > MAXCLP) {
2696
0
    up->gain -= 4;
2697
0
    if (up->gain < 0)
2698
0
      up->gain = 0;
2699
0
  }
2700
0
  audio_gain(up->gain, up->mongain, up->port);
2701
0
  up->clipcnt = 0;
2702
0
#if DEBUG
2703
0
  if (debug > 1)
2704
0
    audio_show();
2705
0
#endif
2706
0
}
2707
2708
2709
#else
2710
int refclock_wwv_bs;
2711
#endif /* REFCLOCK */