Annotation of embedaddon/ntp/ntpd/refclock_wwv.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>