1 1.8 christos /* $NetBSD: refclock_wwv.c,v 1.9 2024/08/18 20:47:19 christos 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.2 joerg * 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.2 joerg #define WWV_SEC 8000 /* second epoch (sample rate) (Hz) */ 87 1.2 joerg #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.2 joerg #define MS (WWV_SEC / 1000) /* samples per millisecond */ 207 1.2 joerg #define IN100 ((100 * 80) / WWV_SEC) /* 100 Hz increment */ 208 1.2 joerg #define IN1000 ((1000 * 80) / WWV_SEC) /* 1000 Hz increment */ 209 1.2 joerg #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.2 joerg 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.2 joerg up = emalloc_zero(sizeof(*up)); 665 1.1 kardel pp = peer->procptr; 666 1.1 kardel pp->io.clock_recv = wwv_receive; 667 1.2 joerg 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.2 joerg 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.2 joerg if (i % 16 == 0) 695 1.2 joerg step *= 2.; 696 1.1 kardel } 697 1.2 joerg 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.2 joerg 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.2 joerg peer = rbufp->recv_peer; 805 1.1 kardel pp = peer->procptr; 806 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg up->mphase = (up->mphase + 1) % WWV_MIN; 1097 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg up->mphase -= WWV_SEC; 1182 1.1 kardel if (up->mphase < 0) 1183 1.2 joerg 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.2 joerg if (sp->metric >= TTHR && epoch == sp->mepoch % WWV_SEC) 1208 1.1 kardel { 1209 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg sp->synmax) / WWV_MIN); 1336 1.1 kardel if (sp->count == 0) 1337 1.1 kardel sp->lastpos = sp->pos; 1338 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg up = pp->unitptr; 1411 1.1 kardel if (!iniflg) { 1412 1.1 kardel iniflg = 1; 1413 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg dtemp = (mepoch - zepoch) % WWV_SEC; 1544 1.1 kardel if (up->status & FGATE) { 1545 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg up = pp->unitptr; 1765 1.1 kardel if (!iniflg) { 1766 1.1 kardel iniflg = 1; 1767 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg pp->lencode = timecode(up, pp->a_lastcode, 2097 1.2 joerg 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.2 joerg 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.2 joerg 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.2 joerg 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.6 christos // XXX: Does temp have an expected value here? 2247 1.1 kardel 2248 1.1 kardel /* 2249 1.1 kardel * Decode the current minute and day. Set leap day if the 2250 1.1 kardel * timecode leap bit is set on 30 June or 31 December. Set leap 2251 1.1 kardel * minute if the last minute on leap day, but only if the clock 2252 1.1 kardel * is syncrhronized. This code fails in 2400 AD. 2253 1.1 kardel */ 2254 1.1 kardel minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 2255 1.1 kardel 10 + up->decvec[HR].digit * 60 + up->decvec[HR + 2256 1.1 kardel 1].digit * 600; 2257 1.1 kardel day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 + 2258 1.1 kardel up->decvec[DA + 2].digit * 100; 2259 1.1 kardel 2260 1.1 kardel /* 2261 1.1 kardel * Set the leap bit on the last minute of the leap day. 2262 1.1 kardel */ 2263 1.1 kardel isleap = up->decvec[YR].digit & 0x3; 2264 1.1 kardel if (up->misc & SECWAR && up->status & INSYNC) { 2265 1.1 kardel if ((day == (isleap ? 182 : 183) || day == (isleap ? 2266 1.1 kardel 365 : 366)) && minute == 1439) 2267 1.1 kardel up->status |= LEPSEC; 2268 1.1 kardel } 2269 1.1 kardel 2270 1.1 kardel /* 2271 1.1 kardel * Roll the day if this the first minute and propagate carries 2272 1.1 kardel * through the year. 2273 1.1 kardel */ 2274 1.1 kardel if (minute != 1440) 2275 1.1 kardel return; 2276 1.1 kardel 2277 1.6 christos // minute = 0; 2278 1.1 kardel while (carry(&up->decvec[HR]) != 0); /* advance to minute 0 */ 2279 1.1 kardel while (carry(&up->decvec[HR + 1]) != 0); 2280 1.1 kardel day++; 2281 1.1 kardel temp = carry(&up->decvec[DA]); /* carry days */ 2282 1.1 kardel if (temp == 0) 2283 1.1 kardel temp = carry(&up->decvec[DA + 1]); 2284 1.1 kardel if (temp == 0) 2285 1.1 kardel temp = carry(&up->decvec[DA + 2]); 2286 1.6 christos // XXX: Is there an expected value of temp here? 2287 1.1 kardel 2288 1.1 kardel /* 2289 1.1 kardel * Roll the year if this the first day and propagate carries 2290 1.1 kardel * through the century. 2291 1.1 kardel */ 2292 1.1 kardel if (day != (isleap ? 365 : 366)) 2293 1.1 kardel return; 2294 1.1 kardel 2295 1.6 christos // day = 1; 2296 1.1 kardel while (carry(&up->decvec[DA]) != 1); /* advance to day 1 */ 2297 1.1 kardel while (carry(&up->decvec[DA + 1]) != 0); 2298 1.1 kardel while (carry(&up->decvec[DA + 2]) != 0); 2299 1.1 kardel temp = carry(&up->decvec[YR]); /* carry years */ 2300 1.1 kardel if (temp == 0) 2301 1.1 kardel carry(&up->decvec[YR + 1]); 2302 1.1 kardel } 2303 1.1 kardel 2304 1.1 kardel 2305 1.1 kardel /* 2306 1.1 kardel * carry - process digit 2307 1.1 kardel * 2308 1.1 kardel * This routine rotates a likelihood vector one position and increments 2309 1.1 kardel * the clock digit modulo the radix. It returns the new clock digit or 2310 1.1 kardel * zero if a carry occurred. Once synchronized, the clock digit will 2311 1.1 kardel * match the maximum-likelihood digit corresponding to that position. 2312 1.1 kardel */ 2313 1.1 kardel static int 2314 1.1 kardel carry( 2315 1.1 kardel struct decvec *dp /* decoding table pointer */ 2316 1.1 kardel ) 2317 1.1 kardel { 2318 1.1 kardel int temp; 2319 1.1 kardel int j; 2320 1.1 kardel 2321 1.1 kardel dp->digit++; 2322 1.1 kardel if (dp->digit == dp->radix) 2323 1.1 kardel dp->digit = 0; 2324 1.1 kardel temp = dp->like[dp->radix - 1]; 2325 1.1 kardel for (j = dp->radix - 1; j > 0; j--) 2326 1.1 kardel dp->like[j] = dp->like[j - 1]; 2327 1.1 kardel dp->like[0] = temp; 2328 1.1 kardel return (dp->digit); 2329 1.1 kardel } 2330 1.1 kardel 2331 1.1 kardel 2332 1.1 kardel /* 2333 1.1 kardel * wwv_snr - compute SNR or likelihood function 2334 1.1 kardel */ 2335 1.1 kardel static double 2336 1.1 kardel wwv_snr( 2337 1.1 kardel double signal, /* signal */ 2338 1.1 kardel double noise /* noise */ 2339 1.1 kardel ) 2340 1.1 kardel { 2341 1.1 kardel double rval; 2342 1.1 kardel 2343 1.1 kardel /* 2344 1.1 kardel * This is a little tricky. Due to the way things are measured, 2345 1.1 kardel * either or both the signal or noise amplitude can be negative 2346 1.1 kardel * or zero. The intent is that, if the signal is negative or 2347 1.1 kardel * zero, the SNR must always be zero. This can happen with the 2348 1.1 kardel * subcarrier SNR before the phase has been aligned. On the 2349 1.1 kardel * other hand, in the likelihood function the "noise" is the 2350 1.1 kardel * next maximum down from the peak and this could be negative. 2351 1.1 kardel * However, in this case the SNR is truly stupendous, so we 2352 1.1 kardel * simply cap at MAXSNR dB (40). 2353 1.1 kardel */ 2354 1.1 kardel if (signal <= 0) { 2355 1.1 kardel rval = 0; 2356 1.1 kardel } else if (noise <= 0) { 2357 1.1 kardel rval = MAXSNR; 2358 1.1 kardel } else { 2359 1.1 kardel rval = 20. * log10(signal / noise); 2360 1.1 kardel if (rval > MAXSNR) 2361 1.1 kardel rval = MAXSNR; 2362 1.1 kardel } 2363 1.1 kardel return (rval); 2364 1.1 kardel } 2365 1.1 kardel 2366 1.1 kardel 2367 1.1 kardel /* 2368 1.1 kardel * wwv_newchan - change to new data channel 2369 1.1 kardel * 2370 1.1 kardel * The radio actually appears to have ten channels, one channel for each 2371 1.1 kardel * of five frequencies and each of two stations (WWV and WWVH), although 2372 1.1 kardel * if not tunable only the DCHAN channel appears live. While the radio 2373 1.1 kardel * is tuned to the working data channel frequency and station for most 2374 1.1 kardel * of the minute, during seconds 59, 0 and 1 the radio is tuned to a 2375 1.1 kardel * probe frequency in order to search for minute sync pulse and data 2376 1.1 kardel * subcarrier from other transmitters. 2377 1.1 kardel * 2378 1.1 kardel * The search for WWV and WWVH operates simultaneously, with WWV minute 2379 1.1 kardel * sync pulse at 1000 Hz and WWVH at 1200 Hz. The probe frequency 2380 1.1 kardel * rotates each minute over 2.5, 5, 10, 15 and 20 MHz in order and yes, 2381 1.1 kardel * we all know WWVH is dark on 20 MHz, but few remember when WWV was lit 2382 1.1 kardel * on 25 MHz. 2383 1.1 kardel * 2384 1.1 kardel * This routine selects the best channel using a metric computed from 2385 1.1 kardel * the reachability register and minute pulse amplitude. Normally, the 2386 1.1 kardel * award goes to the the channel with the highest metric; but, in case 2387 1.1 kardel * of ties, the award goes to the channel with the highest minute sync 2388 1.1 kardel * pulse amplitude and then to the highest frequency. 2389 1.1 kardel * 2390 1.1 kardel * The routine performs an important squelch function to keep dirty data 2391 1.1 kardel * from polluting the integrators. In order to consider a station valid, 2392 1.1 kardel * the metric must be at least MTHR (13); otherwise, the station select 2393 1.1 kardel * bits are cleared so the second sync is disabled and the data bit 2394 1.1 kardel * integrators averaged to a miss. 2395 1.1 kardel */ 2396 1.1 kardel static int 2397 1.1 kardel wwv_newchan( 2398 1.1 kardel struct peer *peer /* peer structure pointer */ 2399 1.1 kardel ) 2400 1.1 kardel { 2401 1.1 kardel struct refclockproc *pp; 2402 1.1 kardel struct wwvunit *up; 2403 1.1 kardel struct sync *sp, *rp; 2404 1.1 kardel double rank, dtemp; 2405 1.1 kardel int i, j, rval; 2406 1.1 kardel 2407 1.1 kardel pp = peer->procptr; 2408 1.2 joerg up = pp->unitptr; 2409 1.1 kardel 2410 1.1 kardel /* 2411 1.1 kardel * Search all five station pairs looking for the channel with 2412 1.1 kardel * maximum metric. 2413 1.1 kardel */ 2414 1.1 kardel sp = NULL; 2415 1.1 kardel j = 0; 2416 1.1 kardel rank = 0; 2417 1.1 kardel for (i = 0; i < NCHAN; i++) { 2418 1.1 kardel rp = &up->mitig[i].wwvh; 2419 1.1 kardel dtemp = rp->metric; 2420 1.1 kardel if (dtemp >= rank) { 2421 1.1 kardel rank = dtemp; 2422 1.1 kardel sp = rp; 2423 1.1 kardel j = i; 2424 1.1 kardel } 2425 1.1 kardel rp = &up->mitig[i].wwv; 2426 1.1 kardel dtemp = rp->metric; 2427 1.1 kardel if (dtemp >= rank) { 2428 1.1 kardel rank = dtemp; 2429 1.1 kardel sp = rp; 2430 1.1 kardel j = i; 2431 1.1 kardel } 2432 1.1 kardel } 2433 1.1 kardel 2434 1.1 kardel /* 2435 1.1 kardel * If the strongest signal is less than the MTHR threshold (13), 2436 1.1 kardel * we are beneath the waves, so squelch the second sync and 2437 1.1 kardel * advance to the next station. This makes sure all stations are 2438 1.1 kardel * scanned when the ions grow dim. If the strongest signal is 2439 1.1 kardel * greater than the threshold, tune to that frequency and 2440 1.1 kardel * transmitter QTH. 2441 1.1 kardel */ 2442 1.1 kardel up->status &= ~(SELV | SELH); 2443 1.1 kardel if (rank < MTHR) { 2444 1.1 kardel up->dchan = (up->dchan + 1) % NCHAN; 2445 1.1 kardel if (up->status & METRIC) { 2446 1.1 kardel up->status &= ~METRIC; 2447 1.1 kardel refclock_report(peer, CEVNT_PROP); 2448 1.1 kardel } 2449 1.1 kardel rval = FALSE; 2450 1.1 kardel } else { 2451 1.1 kardel up->dchan = j; 2452 1.1 kardel up->sptr = sp; 2453 1.1 kardel memcpy(&pp->refid, sp->refid, 4); 2454 1.1 kardel peer->refid = pp->refid; 2455 1.1 kardel up->status |= METRIC; 2456 1.1 kardel if (sp->select & SELV) { 2457 1.1 kardel up->status |= SELV; 2458 1.1 kardel up->pdelay = pp->fudgetime1; 2459 1.1 kardel } else if (sp->select & SELH) { 2460 1.1 kardel up->status |= SELH; 2461 1.1 kardel up->pdelay = pp->fudgetime2; 2462 1.1 kardel } else { 2463 1.1 kardel up->pdelay = 0; 2464 1.1 kardel } 2465 1.1 kardel rval = TRUE; 2466 1.1 kardel } 2467 1.1 kardel #ifdef ICOM 2468 1.1 kardel if (up->fd_icom > 0) 2469 1.1 kardel wwv_qsy(peer, up->dchan); 2470 1.1 kardel #endif /* ICOM */ 2471 1.1 kardel return (rval); 2472 1.1 kardel } 2473 1.1 kardel 2474 1.1 kardel 2475 1.1 kardel /* 2476 1.1 kardel * wwv_newgame - reset and start over 2477 1.1 kardel * 2478 1.1 kardel * There are three conditions resulting in a new game: 2479 1.1 kardel * 2480 1.1 kardel * 1 After finding the minute pulse (MSYNC lit), going 15 minutes 2481 1.1 kardel * (DATA) without finding the unit seconds digit. 2482 1.1 kardel * 2483 1.1 kardel * 2 After finding good data (DSYNC lit), going more than 40 minutes 2484 1.1 kardel * (SYNCH) without finding station sync (INSYNC lit). 2485 1.1 kardel * 2486 1.1 kardel * 3 After finding station sync (INSYNC lit), going more than 2 days 2487 1.1 kardel * (PANIC) without finding any station. 2488 1.1 kardel */ 2489 1.1 kardel static void 2490 1.1 kardel wwv_newgame( 2491 1.1 kardel struct peer *peer /* peer structure pointer */ 2492 1.1 kardel ) 2493 1.1 kardel { 2494 1.1 kardel struct refclockproc *pp; 2495 1.1 kardel struct wwvunit *up; 2496 1.1 kardel struct chan *cp; 2497 1.1 kardel int i; 2498 1.1 kardel 2499 1.1 kardel pp = peer->procptr; 2500 1.2 joerg up = pp->unitptr; 2501 1.1 kardel 2502 1.1 kardel /* 2503 1.1 kardel * Initialize strategic values. Note we set the leap bits 2504 1.1 kardel * NOTINSYNC and the refid "NONE". 2505 1.1 kardel */ 2506 1.1 kardel if (up->status) 2507 1.1 kardel up->errflg = CEVNT_TIMEOUT; 2508 1.1 kardel peer->leap = LEAP_NOTINSYNC; 2509 1.1 kardel up->watch = up->status = up->alarm = 0; 2510 1.1 kardel up->avgint = MINAVG; 2511 1.1 kardel up->freq = 0; 2512 1.1 kardel up->gain = MAXGAIN / 2; 2513 1.1 kardel 2514 1.1 kardel /* 2515 1.1 kardel * Initialize the station processes for audio gain, select bit, 2516 1.1 kardel * station/frequency identifier and reference identifier. Start 2517 1.1 kardel * probing at the strongest channel or the default channel if 2518 1.1 kardel * nothing heard. 2519 1.1 kardel */ 2520 1.1 kardel memset(up->mitig, 0, sizeof(up->mitig)); 2521 1.1 kardel for (i = 0; i < NCHAN; i++) { 2522 1.1 kardel cp = &up->mitig[i]; 2523 1.1 kardel cp->gain = up->gain; 2524 1.1 kardel cp->wwv.select = SELV; 2525 1.2 joerg snprintf(cp->wwv.refid, sizeof(cp->wwv.refid), "WV%.0f", 2526 1.2 joerg floor(qsy[i])); 2527 1.1 kardel cp->wwvh.select = SELH; 2528 1.2 joerg snprintf(cp->wwvh.refid, sizeof(cp->wwvh.refid), "WH%.0f", 2529 1.2 joerg floor(qsy[i])); 2530 1.1 kardel } 2531 1.1 kardel up->dchan = (DCHAN + NCHAN - 1) % NCHAN; 2532 1.1 kardel wwv_newchan(peer); 2533 1.1 kardel up->schan = up->dchan; 2534 1.1 kardel } 2535 1.1 kardel 2536 1.1 kardel /* 2537 1.1 kardel * wwv_metric - compute station metric 2538 1.1 kardel * 2539 1.1 kardel * The most significant bits represent the number of ones in the 2540 1.1 kardel * station reachability register. The least significant bits represent 2541 1.1 kardel * the minute sync pulse amplitude. The combined value is scaled 0-100. 2542 1.1 kardel */ 2543 1.1 kardel double 2544 1.1 kardel wwv_metric( 2545 1.1 kardel struct sync *sp /* station pointer */ 2546 1.1 kardel ) 2547 1.1 kardel { 2548 1.1 kardel double dtemp; 2549 1.1 kardel 2550 1.1 kardel dtemp = sp->count * MAXAMP; 2551 1.1 kardel if (sp->synmax < MAXAMP) 2552 1.1 kardel dtemp += sp->synmax; 2553 1.1 kardel else 2554 1.1 kardel dtemp += MAXAMP - 1; 2555 1.1 kardel dtemp /= (AMAX + 1) * MAXAMP; 2556 1.1 kardel return (dtemp * 100.); 2557 1.1 kardel } 2558 1.1 kardel 2559 1.1 kardel 2560 1.1 kardel #ifdef ICOM 2561 1.1 kardel /* 2562 1.1 kardel * wwv_qsy - Tune ICOM receiver 2563 1.1 kardel * 2564 1.1 kardel * This routine saves the AGC for the current channel, switches to a new 2565 1.1 kardel * channel and restores the AGC for that channel. If a tunable receiver 2566 1.1 kardel * is not available, just fake it. 2567 1.1 kardel */ 2568 1.1 kardel static int 2569 1.1 kardel wwv_qsy( 2570 1.1 kardel struct peer *peer, /* peer structure pointer */ 2571 1.1 kardel int chan /* channel */ 2572 1.1 kardel ) 2573 1.1 kardel { 2574 1.1 kardel int rval = 0; 2575 1.1 kardel struct refclockproc *pp; 2576 1.1 kardel struct wwvunit *up; 2577 1.1 kardel 2578 1.1 kardel pp = peer->procptr; 2579 1.2 joerg up = pp->unitptr; 2580 1.1 kardel if (up->fd_icom > 0) { 2581 1.1 kardel up->mitig[up->achan].gain = up->gain; 2582 1.1 kardel rval = icom_freq(up->fd_icom, peer->ttl & 0x7f, 2583 1.1 kardel qsy[chan]); 2584 1.1 kardel up->achan = chan; 2585 1.1 kardel up->gain = up->mitig[up->achan].gain; 2586 1.1 kardel } 2587 1.1 kardel return (rval); 2588 1.1 kardel } 2589 1.1 kardel #endif /* ICOM */ 2590 1.1 kardel 2591 1.1 kardel 2592 1.1 kardel /* 2593 1.1 kardel * timecode - assemble timecode string and length 2594 1.1 kardel * 2595 1.1 kardel * Prettytime format - similar to Spectracom 2596 1.1 kardel * 2597 1.1 kardel * sq yy ddd hh:mm:ss ld dut lset agc iden sig errs freq avgt 2598 1.1 kardel * 2599 1.1 kardel * s sync indicator ('?' or ' ') 2600 1.1 kardel * q error bits (hex 0-F) 2601 1.1 kardel * yyyy year of century 2602 1.1 kardel * ddd day of year 2603 1.1 kardel * hh hour of day 2604 1.1 kardel * mm minute of hour 2605 1.1 kardel * ss second of minute) 2606 1.1 kardel * l leap second warning (' ' or 'L') 2607 1.1 kardel * d DST state ('S', 'D', 'I', or 'O') 2608 1.1 kardel * dut DUT sign and magnitude (0.1 s) 2609 1.1 kardel * lset minutes since last clock update 2610 1.1 kardel * agc audio gain (0-255) 2611 1.1 kardel * iden reference identifier (station and frequency) 2612 1.1 kardel * sig signal quality (0-100) 2613 1.1 kardel * errs bit errors in last minute 2614 1.1 kardel * freq frequency offset (PPM) 2615 1.1 kardel * avgt averaging time (s) 2616 1.1 kardel */ 2617 1.1 kardel static int 2618 1.1 kardel timecode( 2619 1.1 kardel struct wwvunit *up, /* driver structure pointer */ 2620 1.2 joerg char * tc, /* target string */ 2621 1.2 joerg size_t tcsiz /* target max chars */ 2622 1.1 kardel ) 2623 1.1 kardel { 2624 1.1 kardel struct sync *sp; 2625 1.1 kardel int year, day, hour, minute, second, dut; 2626 1.1 kardel char synchar, leapchar, dst; 2627 1.1 kardel char cptr[50]; 2628 1.1 kardel 2629 1.1 kardel 2630 1.1 kardel /* 2631 1.1 kardel * Common fixed-format fields 2632 1.1 kardel */ 2633 1.1 kardel synchar = (up->status & INSYNC) ? ' ' : '?'; 2634 1.1 kardel year = up->decvec[YR].digit + up->decvec[YR + 1].digit * 10 + 2635 1.1 kardel 2000; 2636 1.1 kardel day = up->decvec[DA].digit + up->decvec[DA + 1].digit * 10 + 2637 1.1 kardel up->decvec[DA + 2].digit * 100; 2638 1.1 kardel hour = up->decvec[HR].digit + up->decvec[HR + 1].digit * 10; 2639 1.1 kardel minute = up->decvec[MN].digit + up->decvec[MN + 1].digit * 10; 2640 1.1 kardel second = 0; 2641 1.1 kardel leapchar = (up->misc & SECWAR) ? 'L' : ' '; 2642 1.1 kardel dst = dstcod[(up->misc >> 4) & 0x3]; 2643 1.1 kardel dut = up->misc & 0x7; 2644 1.1 kardel if (!(up->misc & DUTS)) 2645 1.1 kardel dut = -dut; 2646 1.2 joerg snprintf(tc, tcsiz, "%c%1X", synchar, up->alarm); 2647 1.2 joerg snprintf(cptr, sizeof(cptr), 2648 1.2 joerg " %4d %03d %02d:%02d:%02d %c%c %+d", 2649 1.2 joerg year, day, hour, minute, second, leapchar, dst, dut); 2650 1.2 joerg strlcat(tc, cptr, tcsiz); 2651 1.1 kardel 2652 1.1 kardel /* 2653 1.1 kardel * Specific variable-format fields 2654 1.1 kardel */ 2655 1.1 kardel sp = up->sptr; 2656 1.2 joerg snprintf(cptr, sizeof(cptr), " %d %d %s %.0f %d %.1f %d", 2657 1.2 joerg up->watch, up->mitig[up->dchan].gain, sp->refid, 2658 1.2 joerg sp->metric, up->errcnt, up->freq / WWV_SEC * 1e6, 2659 1.2 joerg up->avgint); 2660 1.2 joerg strlcat(tc, cptr, tcsiz); 2661 1.2 joerg 2662 1.2 joerg return strlen(tc); 2663 1.1 kardel } 2664 1.1 kardel 2665 1.1 kardel 2666 1.1 kardel /* 2667 1.1 kardel * wwv_gain - adjust codec gain 2668 1.1 kardel * 2669 1.1 kardel * This routine is called at the end of each second. During the second 2670 1.1 kardel * the number of signal clips above the MAXAMP threshold (6000). If 2671 1.1 kardel * there are no clips, the gain is bumped up; if there are more than 2672 1.1 kardel * MAXCLP clips (100), it is bumped down. The decoder is relatively 2673 1.1 kardel * insensitive to amplitude, so this crudity works just peachy. The 2674 1.1 kardel * routine also jiggles the input port and selectively mutes the 2675 1.1 kardel * monitor. 2676 1.1 kardel */ 2677 1.1 kardel static void 2678 1.1 kardel wwv_gain( 2679 1.1 kardel struct peer *peer /* peer structure pointer */ 2680 1.1 kardel ) 2681 1.1 kardel { 2682 1.1 kardel struct refclockproc *pp; 2683 1.1 kardel struct wwvunit *up; 2684 1.1 kardel 2685 1.1 kardel pp = peer->procptr; 2686 1.2 joerg up = pp->unitptr; 2687 1.1 kardel 2688 1.1 kardel /* 2689 1.1 kardel * Apparently, the codec uses only the high order bits of the 2690 1.1 kardel * gain control field. Thus, it may take awhile for changes to 2691 1.1 kardel * wiggle the hardware bits. 2692 1.1 kardel */ 2693 1.1 kardel if (up->clipcnt == 0) { 2694 1.1 kardel up->gain += 4; 2695 1.1 kardel if (up->gain > MAXGAIN) 2696 1.1 kardel up->gain = MAXGAIN; 2697 1.1 kardel } else if (up->clipcnt > MAXCLP) { 2698 1.1 kardel up->gain -= 4; 2699 1.1 kardel if (up->gain < 0) 2700 1.1 kardel up->gain = 0; 2701 1.1 kardel } 2702 1.1 kardel audio_gain(up->gain, up->mongain, up->port); 2703 1.1 kardel up->clipcnt = 0; 2704 1.1 kardel #if DEBUG 2705 1.1 kardel if (debug > 1) 2706 1.1 kardel audio_show(); 2707 1.1 kardel #endif 2708 1.1 kardel } 2709 1.1 kardel 2710 1.1 kardel 2711 1.1 kardel #else 2712 1.9 christos NONEMPTY_TRANSLATION_UNIT 2713 1.1 kardel #endif /* REFCLOCK */ 2714