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